diff -u --recursive --new-file v2.4.4/linux/CREDITS linux/CREDITS --- v2.4.4/linux/CREDITS Fri Apr 20 16:23:12 2001 +++ linux/CREDITS Tue May 22 19:54:04 2001 @@ -221,6 +221,14 @@ S: 62-300 Wrzesnia S: Poland +N: Fred Barnes +E: frmb2@ukc.ac.uk +D: Various parport/ppdev hacks and fixes +S: Computing Lab, The University +S: Canterbury, KENT +S: CT2 7NF +S: England + N: Paul Barton-Davis E: pbd@op.net D: Driver for WaveFront soundcards (Turtle Beach Maui, Tropez, Tropez+) @@ -1111,8 +1119,10 @@ S: Germany N: Christoph Hellwig -E: chhellwig@gmx.net -D: Sound/OSS hacking +E: hch@caldera.de +E: hch@infradead.org +D: misc driver & makefile hacking +D: freevxfs driver S: Triftstraße 26 S: 38644 Goslar S: Germany @@ -1663,6 +1673,7 @@ N: Jamie Lokier E: jamie@imbolc.ucc.ie D: Reboot-through-BIOS for broken 486 motherboards +D: Some parport fixes S: 11 Goodson Walk S: Marston S: Oxford @@ -1869,10 +1880,13 @@ N: Arnaldo Carvalho de Melo E: acme@conectiva.com.br -W: http://www.conectiva.com.br/~acme +E: acme@gnu.org +W: http://bazar.conectiva.com.br/~acme +W: http://advogato.org/person/acme +P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01 D: wanrouter hacking -D: USB hacking -D: miscellaneous Makefile & Config.in fixes +D: misc Makefile, Config.in, drivers and network stacks fixes +D: IPX Maintainer D: Cyclom 2X synchronous card driver D: i18n for minicom, net-tools, util-linux, fetchmail, etc S: Conectiva S.A. @@ -2880,7 +2894,7 @@ S: USA N: Tim Waugh -E: tim@cyberelk.demon.co.uk +E: tim@cyberelk.net D: Co-architect of the parallel-port sharing system S: 17 Curling Vale S: GUILDFORD @@ -3011,8 +3025,8 @@ E: jwoithe@physics.adelaide.edu.au W: http://www.physics.adelaide.edu.au/~jwoithe D: ALS-007 sound card extensions to Sound Blaster driver -S: 4/36 Trevelyan St -S: Wayville SA 5034 +S: 20 Jordan St +S: Valley View, SA 5093 S: Australia N: Clifford Wolf diff -u --recursive --new-file v2.4.4/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.4/linux/Documentation/Changes Wed Apr 11 19:02:27 2001 +++ linux/Documentation/Changes Sat May 19 17:43:05 2001 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: April 6, 2001 +Last updated: May 9, 2001 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -71,7 +71,7 @@ information about their gcc version requirements from another source. The recommended compiler for the kernel is egcs 1.1.2 (gcc 2.91.66), and it -should be used when you need absolute stability. You may use gcc 2.95.2 +should be used when you need absolute stability. You may use gcc 2.95.x instead if you wish, although it may cause problems. Later versions of gcc have not received much testing for Linux kernel compilation, and there are almost certainly bugs (mainly, but not exclusively, in the kernel) that @@ -83,9 +83,9 @@ be compiled with it. In addition, please pay attention to compiler optimization. Anything -greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95 +greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95.x or derivatives, be sure not to use -fstrict-aliasing (which, depending on -your version of gcc 2.95, may necessitate using -fno-strict-aliasing). +your version of gcc 2.95.x, may necessitate using -fno-strict-aliasing). Make ---- @@ -268,15 +268,15 @@ ------------------------ o -gcc 2.95.2 +gcc 2.95.3 ---------- -o +o Gnu Make ******** Make 3.77 --------- +--------- o Binutils diff -u --recursive --new-file v2.4.4/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.4/linux/Documentation/Configure.help Fri Apr 20 16:23:12 2001 +++ linux/Documentation/Configure.help Thu May 24 15:03:06 2001 @@ -4170,22 +4170,6 @@ It is safe to say N here for now. -IPv6: enable EUI-64 token format -CONFIG_IPV6_EUI64 - 6bone, the network of computers using the IPv6 protocol, is moving - to a new aggregatable address format and a new link local address - assignment (EUI-64). Say Y if your site has upgraded already, or - has started to upgrade. - -IPv6: disable provider based addresses -CONFIG_IPV6_NO_PB - Linux tries to operate correctly when your site has moved to EUI-64 - only partially. Unfortunately, the two address formats (old: - "provider based" and new: "aggregatable") are incompatible. Say Y if - your site finished the upgrade to EUI-64, and/or you encountered - some problems caused by the presence of two link-local addresses on - an interface. - IPv6: routing messages via old netlink CONFIG_IPV6_NETLINK You can say Y here to receive routing messages from the IPv6 code @@ -5635,7 +5619,7 @@ Default: 253 Initial Bus Reset Settle Delay -CONFIG_AIC7XXX_RESET_DELAY +CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. @@ -7188,7 +7172,7 @@ This driver requires a specially patched pppd daemon. The patch to pppd, along with binaries of a patched pppd package can be found at: - http://www.math.uwaterloo.ca/~mostrows + http://www.shoshin.uwaterloo.ca/~mostrows Wireless LAN (non-hamradio) CONFIG_NET_RADIO @@ -10933,6 +10917,35 @@ The module will be called ov511.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Philips webcam support +CONFIG_USB_PWC + Say Y or M here if you want to use one of these Philips USB webcams: + PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or + the Askey VC010. The PCA635, PCVC665 and PCVC720 are not + supported by this driver and never will be. + + This driver has an optional plugin, which is distributed as a + binary module only. It contains code that allow you to use + higher resolutions and framerates but may not be distributed + as source. But even without this plugin you can these cams + for most applications. + + See Documentation/usb/philips.txt for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + 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 pwc.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + USB ADMtek Pegasus-based ethernet device support CONFIG_USB_PEGASUS Say Y if you want to use your USB ethernet device. Supported @@ -11489,6 +11502,16 @@ (the one containing the directory /) cannot be a module, so saying M could be dangerous. If unsure, say N. +PReP residual data support +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is not + present or incorrect. + + Unless you expect to boot on a PReP system, there is not need to select + yes. + /proc file system support CONFIG_PROC_FS This is a virtual file system providing information about the status @@ -11657,6 +11680,23 @@ The module is called hpfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. +FreeVxFS file system support (VERITAS VxFS(TM) compatible) +CONFIG_VXFS_FS + FreeVxFS is a filesystem driver that support the VERITAS VxFS(TM) + filesystem format. VERITAS VxFS(TM) is the standard filesystem + of SCO UnixWare (and possibly others) and optionally available + for Sunsoft Solaris, HP-UX and many other operating systems. + Currently only readonly access is supported. + + NOTE: the filesystem type as used by mount(1), mount(2) and fstab(5) + is 'vxfs' as it describes the filesystem format, not the + actual driver. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called freevxfs.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. If unsure, say N. + NTFS support (read only) CONFIG_NTFS_FS NTFS is the file system of Microsoft Windows NT. Say Y if you want @@ -12081,10 +12121,7 @@ The nls settings can be changed at mount time, if your smbmount supports that, using the codepage and iocharset parameters. - Currently no smbmount distributed with samba supports this, it is - assumed future versions will. In the meantime you can get an - unofficial patch for samba 2.0.7 from: - http://www.hojdpunkten.ac.se/054/samba/index.html + smbmount from samba 2.2.0 or later supports this. nls support setting CONFIG_SMB_NLS_REMOTE @@ -12096,10 +12133,7 @@ The nls settings can be changed at mount time, if your smbmount supports that, using the codepage and iocharset parameters. - Currently no smbmount distributed with samba supports this, it is - assumed future versions will. In the meantime you can get an - unofficial patch for samba 2.0.7 from: - http://www.hojdpunkten.ac.se/054/samba/index.html + smbmount from samba 2.2.0 or later supports this. Coda file system support (advanced network fs) CONFIG_CODA_FS @@ -13204,6 +13238,14 @@ say M here and read Documentation/modules.txt. The module will be called msbusmouse.o. +Apple Desktop Bus support +CONFIG_ADB + Apple Desktop Bus (ADB) support is for support of devices which + are connected to the to an ADB port. ADB devices tend to have + 4 pins. If you have an Apple Macintosh prior to the iMac, or a + "Blue and White G3", you probably want to say Y here. Otherwise + say N. + Apple Desktop Bus mouse support CONFIG_ADBMOUSE Say Y here if you have this type of bus mouse (4 pin connector) as @@ -16249,22 +16291,45 @@ Processor Type CONFIG_6xx There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750), the Motorola embedded versions - (821, 823, 850, 855, 860), the IBM embedded versions (403 and + types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions + (821, 823, 850, 855, 860, 8260), the IBM embedded versions (403 and 405) and the high end 64 bit Power processors (Power 3, Power 4). - Unless you are building a kernel for one of the embedded - processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that - the kernel runs in 32-bit mode even on 64-bit chips. + Unless you are building a kernel for one of the embedded processor + systems, or a 64 bit IBM RS/6000, choose 6xx. Note that the kernel + runs in 32-bit mode even on 64-bit chips. Also note that because + the 82xx family has a 603e core, specific support for that chipset + is asked later on. + +Motorola MPC8260 CPM support +CONFIG_8260 + The MPC8260 CPM (Communications Processor Module) is a typically + embedded CPU made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with specifically an 8260 + for a CPU. + + If in doubt, say N. + +Workarounds for PPC601 bugs +CONFIG_PPC601_SYNC_FIX + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near certain + instructions, typically those that make major changes to the CPU state. + These extra instructions reduce performance slightly. If you say N + here, these extra instructions will not be included, resulting in a + kernel which will run faster but may not run at all on some systems + with the PPC601 chip. + + If in doubt, say Y here. Machine Type -CONFIG_PMAC +CONFIG_ALL_PPC Linux currently supports several different kinds of PowerPC-based machines: Apple Power Macintoshes and clones (such as the Motorola Starmax series), PReP (PowerPC Reference Platform) machines such as - the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the - embedded MBX boards from Motorola. Currently, a single kernel binary - only supports one type or the other. However, there is very early - work on support for CHRP, PReP and PowerMac's from a single binary. + the Motorola PowerStack, CHRP (Common Hardware Reference Platform), + the embedded MBX boards from Motorola and many others. Currently, + the default option is to build a kernel which works on the first + three. Support for other machines is currently incomplete. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -16324,6 +16389,37 @@ an image of the device tree that the kernel copies from Open Firmware. If unsure, say Y here. +RTAS proc interface +CONFIG_PPC_RTAS + When you use this option, you will be able to use RTAS from + userspace. + + RTAS stands for RunTime Abstraction Services and should + provide a portable way to access and set system information. This is + commonly used on RS/6000 (pSeries) computers. + + You can access RTAS via the special proc filesystem entry rtas. + Don't confuse this rtas entry with the one in /proc/device-tree/rtas + which is readonly. + + If you don't know if you can use RTAS look into + /proc/device-tree/rtas. If there are some entries, it is very likely + that you will be able to use RTAS. + + You can do cool things with rtas. To print out information about + various sensors in the system, just do a + + $ cat /proc/rtas/sensors + + or if you power off your machine at night but want it running when + you enter your office at 7:45 am, do a + + # date -d 'tomorrow 7:30' +%s > /proc/rtas/poweron + + and shutdown. + + If unsure, say Y + MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced @@ -16367,6 +16463,16 @@ which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + +Use AAUI port instead of TP by default +CONFIG_MACE_AAUI_PORT + Some Apple machines (notably the Apple Network Server) which use the + MACE ethernet chip have an Apple AUI port (small 15-pin connector), + instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say + Y here if you have such a machine. If unsure, say N. + The driver will default to AAUI on ANS anyway, and if you use it as + a module, you can provide the port_aaui=0|1 to force the driver + setting. BMAC (G3 ethernet) support CONFIG_BMAC diff -u --recursive --new-file v2.4.4/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- v2.4.4/linux/Documentation/DMA-mapping.txt Thu Apr 19 08:38:48 2001 +++ linux/Documentation/DMA-mapping.txt Sat May 19 17:43:05 2001 @@ -240,6 +240,7 @@ where dev, size are the same as in the above call and cpu_addr and dma_handle are the values pci_alloc_consistent returned to you. +This function may not be called in interrupt context. If your driver needs lots of smaller memory regions, you can write custom code to subdivide pages returned by pci_alloc_consistent, @@ -262,7 +263,8 @@ sleeping context (f.e. in_interrupt is true or while holding SMP locks), pass SLAB_ATOMIC. If your device has no boundary crossing restrictions, pass 0 for alloc; passing 4096 says memory allocated -from this pool must not cross 4KByte boundaries. +from this pool must not cross 4KByte boundaries (but at that time it +may be better to go for pci_alloc_consistent directly instead). Allocate memory from a pci pool like this: @@ -270,21 +272,23 @@ flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor holding SMP locks), SLAB_ATOMIC otherwise. Like pci_alloc_consistent, -this returns two values, cpu_addr and dma_handle, +this returns two values, cpu_addr and dma_handle. Free memory that was allocated from a pci_pool like this: pci_pool_free(pool, cpu_addr, dma_handle); where pool is what you passed to pci_pool_alloc, and cpu_addr and -dma_handle are the values pci_pool_alloc returned. +dma_handle are the values pci_pool_alloc returned. This function +may be called in interrupt context. Destroy a pci_pool by calling: pci_pool_destroy(pool); Make sure you've called pci_pool_free for all memory allocated -from a pool before you destroy the pool. +from a pool before you destroy the pool. This function may not +be called in interrupt context. DMA Direction diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.4/linux/Documentation/DocBook/Makefile Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/Makefile Mon May 7 12:14:56 2001 @@ -95,6 +95,7 @@ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ $(TOPDIR)/kernel/kmod.c \ + $(TOPDIR)/kernel/module.c \ $(TOPDIR)/kernel/printk.c \ $(TOPDIR)/kernel/sched.c \ $(TOPDIR)/kernel/sysctl.c \ diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl linux/Documentation/DocBook/deviceiobook.tmpl --- v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/deviceiobook.tmpl Tue May 1 14:20:25 2001 @@ -171,7 +171,7 @@ with 'isa_' and are isa_readb, isa_writeb, isa_readw, isa_writew, isa_readl, - isa_writelisa_memcpy_fromio + isa_writel, isa_memcpy_fromio and isa_memcpy_toio diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.4/linux/Documentation/DocBook/kernel-api.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/kernel-api.tmpl Thu May 24 15:14:08 2001 @@ -41,8 +41,9 @@ !Iinclude/linux/init.h - Atomics + Atomic and pointer manipulation !Iinclude/asm-i386/atomic.h +!Iinclude/asm-i386/unaligned.h Delaying, scheduling, and timer routines @@ -140,8 +141,13 @@ - Module Loading + Module Support + Module Loading !Ekernel/kmod.c + + Inter Module support +!Ekernel/module.c + diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl --- v2.4.4/linux/Documentation/DocBook/kernel-hacking.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/kernel-hacking.tmpl Sat May 19 17:43:05 2001 @@ -713,7 +713,8 @@ Static data structures marked as __initdata must be initialised - (as opposed to ordinary static data which is zeroed BSS). + (as opposed to ordinary static data which is zeroed BSS) and cannot be + const. diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl --- v2.4.4/linux/Documentation/DocBook/kernel-locking.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/kernel-locking.tmpl Sat May 19 17:43:05 2001 @@ -760,8 +760,11 @@ - Any atomic operation is defined to act as a memory barrier - (ie. as per the mb() macro). Also, + Some atomic operations are defined to act as a memory barrier + (ie. as per the mb() macro, but if in + doubt, be explicit. + + Also, spinlock operations act as partial barriers: operations after gaining a spinlock will never be moved to precede the spin_lock() call, and operations before diff -u --recursive --new-file v2.4.4/linux/Documentation/cris/README linux/Documentation/cris/README --- v2.4.4/linux/Documentation/cris/README Fri Apr 6 10:42:55 2001 +++ linux/Documentation/cris/README Tue May 1 16:04:56 2001 @@ -1,13 +1,19 @@ Linux 2.4 on the CRIS architecture ================================== -$Id: README,v 1.6 2001/02/21 15:27:25 bjornw Exp $ +$Id: README,v 1.7 2001/04/19 12:38:32 bjornw Exp $ This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For more information about CRIS and ETRAX please see further below. - +In order to compile this you need a version of gcc with support for the +ETRAX chip family. Please see this link for more information on how to +download the compiler and other tools useful when building and booting +software for the ETRAX platform: +http://developer.axis.com/doc/software/devboard_lx/install-howto.html + + What is CRIS ? -------------- @@ -97,7 +103,7 @@ ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB eth0 initialized eth0: changed MAC to 00:40:8C:CD:00:00 -ETRAX 100LX serial-driver $Revision: 1.6 $, (c) 2000 Axis Communications AB +ETRAX 100LX serial-driver $Revision: 1.7 $, (c) 2000 Axis Communications AB ttyS0 at 0xb0000060 is a builtin UART with DMA ttyS1 at 0xb0000068 is a builtin UART with DMA ttyS2 at 0xb0000070 is a builtin UART with DMA @@ -127,7 +133,7 @@ Hostname is bbox1 Telnetd starting, using port 23. using /bin/sash as shell. -sftpd[15]: sftpd $Revision: 1.6 $ starting up +sftpd[15]: sftpd $Revision: 1.7 $ starting up diff -u --recursive --new-file v2.4.4/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.4.4/linux/Documentation/devices.txt Sat Dec 30 11:26:10 2000 +++ linux/Documentation/devices.txt Sat May 19 17:43:05 2001 @@ -660,6 +660,12 @@ 29 char Universal frame buffer 0 = /dev/fb0 First frame buffer + 1 = /dev/fb1 Second frame buffer + ... + 31 = /dev/fb31 32nd frame buffer + + Backward compatibility aliases {2.6} + 32 = /dev/fb1 Second frame buffer ... 224 = /dev/fb7 Eighth frame buffer @@ -765,7 +771,7 @@ 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user 1 = /dev/skip enSKIP security cache control - 3 = /dec/fwmonitor Firewall packet copies + 3 = /dev/fwmonitor Firewall packet copies 16 = /dev/tap0 First Ethertap device ... 31 = /dev/tap15 16th Ethertap device @@ -2436,7 +2442,7 @@ 224 char A2232 serial card 0 = /dev/ttyY0 First A2232 port - 1 = /dev/cuy0 Second A2232 port + 1 = /dev/ttyY1 Second A2232 port ... 225 char A2232 serial card (alternate devices) diff -u --recursive --new-file v2.4.4/linux/Documentation/fb/framebuffer.txt linux/Documentation/fb/framebuffer.txt --- v2.4.4/linux/Documentation/fb/framebuffer.txt Sat Jul 8 19:44:07 2000 +++ linux/Documentation/fb/framebuffer.txt Thu May 24 15:14:08 2001 @@ -2,7 +2,7 @@ ----------------------- Maintained by Geert Uytterhoeven -Last revised: January 2, 2000 +Last revised: May 10, 2001 0. Introduction @@ -296,7 +296,7 @@ For more specific information about the frame buffer device and its applications, please refer to the Linux-fbdev website: - http://www.linux-fbdev.org/ + http://linux-fbdev.sourceforge.net/ and to the following documentation: @@ -312,13 +312,13 @@ 8. Mailing list --------------- -There's a _development_ mailing list at linux-fbdev@vuser.vu.union.edu, -controlled by majordomo. Send an email with `help' in the message body to -majordomo@vuser.vu.union.edu for subscription information. +There are several frame buffer device related mailing lists at SourceForge: + - linux-fbdev-announce@lists.sourceforge.net, for announcements, + - linux-fbdev-user@lists.sourceforge.net, for generic user support, + - linux-fbdev-devel@lists.sourceforge.net, for project developers. -The mailing list is archived at - - http://www.mail-archive.com/linux-fbdev@vuser.vu.union.edu/ +Point your web browser to http://sourceforge.net/projects/linux-fbdev/ for +subscription information and archive browsing. 9. Downloading diff -u --recursive --new-file v2.4.4/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.4.4/linux/Documentation/ioctl-number.txt Fri Mar 2 17:50:22 2001 +++ linux/Documentation/ioctl-number.txt Sat May 19 17:54:14 2001 @@ -139,7 +139,7 @@ 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h 'p' 80-9F user-space parport - + 'q' 00-1F linux/videotext.h conflict! 'q' 80-FF Internet PhoneJACK, Internet LineJACK diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.4/linux/Documentation/networking/8139too.txt Thu Apr 19 09:32:48 2001 +++ linux/Documentation/networking/8139too.txt Mon May 7 14:13:19 2001 @@ -185,6 +185,13 @@ Change History -------------- +Version 0.9.17 - May 7, 2001 + +* Fix chipset wakeup bug which prevent media connection for 8139B +* Print out "media is unconnected..." instead of + "partner ability 0000" + + Version 0.9.16 - April 14, 2001 * Complete MMIO audit, disable read-after-every-write diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/cops.txt linux/Documentation/networking/cops.txt --- v2.4.4/linux/Documentation/networking/cops.txt Thu Jan 6 14:46:18 2000 +++ linux/Documentation/networking/cops.txt Wed May 16 10:31:27 2001 @@ -1,5 +1,5 @@ Text File for the COPS LocalTalk Linux driver (cops.c). - By Jay Schulist + By Jay Schulist This driver has two modes and they are: Dayna mode and Tangent mode. Each mode corresponds with the type of card. It has been found diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/ethertap.txt linux/Documentation/networking/ethertap.txt --- v2.4.4/linux/Documentation/networking/ethertap.txt Wed Aug 23 09:30:13 2000 +++ linux/Documentation/networking/ethertap.txt Wed May 16 10:31:27 2001 @@ -7,7 +7,7 @@ Ethertap programming mini-HOWTO ------------------------------- -The ethertap driver was written by Jay Schulist , +The ethertap driver was written by Jay Schulist , you should contact him for further information. This document was written by bert hubert . Updates are welcome. diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/filter.txt linux/Documentation/networking/filter.txt --- v2.4.4/linux/Documentation/networking/filter.txt Thu Jan 6 14:46:18 2000 +++ linux/Documentation/networking/filter.txt Wed May 16 10:31:27 2001 @@ -1,5 +1,5 @@ filter.txt: Linux Socket Filtering -Written by: Jay Schulist +Written by: Jay Schulist Introduction ============ diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.4.4/linux/Documentation/networking/ip-sysctl.txt Sun Mar 25 18:14:21 2001 +++ linux/Documentation/networking/ip-sysctl.txt Wed May 16 10:21:45 2001 @@ -398,4 +398,117 @@ Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.18 2001/03/16 06:49:20 davem Exp $ + + + + + + +/proc/sys/net/ipv6/* Variables: + +IPv6 has no global variables such as tcp_*. tcp_* settings under ipv4/ also +apply to IPv6 [XXX?]. + +conf/default/*: + Change the interface-specific default settings. + + +conf/all/*: + Change all the interface-specific settings. + + [XXX: Other special features than forwarding?] + +conf/all/forwarding - BOOLEAN + Enable global IPv6 forwarding between all interfaces. + + IPv4 and IPv6 work differently here; e.g. netfilter must be used + to control which interfaces may forward packets and which not. + + This also sets all interfaces' Host/Router setting + 'forwarding' to the specified value. See below for details. + + This referred to as global forwarding. + +conf/interface/*: + Change special settings per interface. + + The functional behaviour for certain settings is different + depending on whether local forwarding is enabled or not. + +accept_ra - BOOLEAN + Accept Router Advertisements; autoconfigure using them. + + Functional default: enabled if local forwarding is disabled. + disabled if local forwarding is enabled. + +accept_redirects - BOOLEAN + Accept Redirects. + + Functional default: enabled if local forwarding is disabled. + disabled if local forwarding is enabled. + +autoconf - BOOLEAN + Configure link-local addresses using L2 hardware addresses. + + Default: TRUE + +dad_transmits - INTEGER + The amount of Duplicate Address Detection probes to send. + Default: 1 + +forwarding - BOOLEAN + Configure interface-specific Host/Router behaviour. + + Note: It is recommended to have the same setting on all + interfaces; mixed router/host scenarios are rather uncommon. + + FALSE: + + By default, Host behaviour is assumed. This means: + + 1. IsRouter flag is not set in Neighbour Advertisements. + 2. Router Solicitations are being sent when necessary. + 3. If accept_ra is TRUE (default), accept Router + Advertisements (and do autoconfiguration). + 4. If accept_redirects is TRUE (default), accept Redirects. + + TRUE: + + If local forwarding is enabled, Router behaviour is assumed. + This means exactly the reverse from the above: + + 1. IsRouter flag is set in Neighbour Advertisements. + 2. Router Solicitations are not sent. + 3. Router Advertisements are ignored. + 4. Redirects are ignored. + + Default: FALSE if global forwarding is disabled (default), + otherwise TRUE. + +hop_limit - INTEGER + Default Hop Limit to set. + Default: 64 + +mtu - INTEGER + Default Maximum Transfer Unit + Default: 1280 (IPv6 required minimum) + +router_solicitation_delay - INTEGER + Number of seconds to wait after interface is brought up + before sending Router Solicitations. + Default: 1 + +router_solicitation_interval - INTEGER + Number of seconds to wait between Router Solicitations. + Default: 4 + +router_solicitations - INTEGER + Number of Router Solicitations to send until assuming no + routers are present. + Default: 3 + +IPv6 Update by: +Pekka Savola +pekkas@netcore.fi + +$Id: ip-sysctl.txt,v 1.19 2001/05/16 17:11:04 davem Exp $ diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/ipddp.txt linux/Documentation/networking/ipddp.txt --- v2.4.4/linux/Documentation/networking/ipddp.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/networking/ipddp.txt Wed May 16 10:31:27 2001 @@ -1,7 +1,7 @@ Text file for ipddp.c: AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation -This text file is written by Jay Schulist +This text file is written by Jay Schulist Introduction ------------ @@ -72,7 +72,7 @@ Further Assistance ------------------- -You can contact me (Jay Schulist ) with any +You can contact me (Jay Schulist ) with any questions regarding decapsulation or encapsulation. Bradford W. Johnson originally wrote the ipddp.c driver for IP encapsulation in AppleTalk. diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/smctr.txt linux/Documentation/networking/smctr.txt --- v2.4.4/linux/Documentation/networking/smctr.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/smctr.txt Wed May 16 10:31:27 2001 @@ -1,5 +1,5 @@ Text File for the SMC TokenCard TokenRing Linux driver (smctr.c). - By Jay Schulist + By Jay Schulist The Linux SMC Token Ring driver works with the SMC TokenCard Elite (8115T) ISA and SMC TokenCard Elite/A (8115T/A) MCA adapters. @@ -22,7 +22,7 @@ following command will suffice for most: # modprobe smctr -smctr.c: v1.00 12/6/99 by jschlst@turbolinux.com +smctr.c: v1.00 12/6/99 by jschlst@samba.org tr0: SMC TokenCard 8115T at Io 0x300, Irq 10, Rom 0xd8000, Ram 0xcc000. Now just setup the device via ifconfig and set and routes you may have. After diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/tms380tr.txt linux/Documentation/networking/tms380tr.txt --- v2.4.4/linux/Documentation/networking/tms380tr.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/tms380tr.txt Wed May 16 10:31:27 2001 @@ -1,5 +1,5 @@ Text file for the Linux SysKonnect Token Ring ISA/PCI Adapter Driver. - Text file by: Jay Schulist + Text file by: Jay Schulist The Linux SysKonnect Token Ring driver works with the SysKonnect TR4/16(+) ISA, SysKonnect TR4/16(+) PCI, SysKonnect TR4/16 PCI, and older revisions of the diff -u --recursive --new-file v2.4.4/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.4.4/linux/Documentation/parport.txt Fri Apr 6 10:42:51 2001 +++ linux/Documentation/parport.txt Sat May 19 17:54:14 2001 @@ -261,4 +261,4 @@ io=0x378 irq=7 dma=3 (for DMA) -- Philip.Blundell@pobox.com -tim@cyberelk.demon.co.uk +tim@cyberelk.net diff -u --recursive --new-file v2.4.4/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.4.4/linux/Documentation/pci.txt Sun Sep 17 09:45:06 2000 +++ linux/Documentation/pci.txt Sat May 19 17:43:05 2001 @@ -60,8 +60,8 @@ remove Pointer to a function which gets called whenever a device being handled by this driver is removed (either during deregistration of the driver or when it's manually pulled - out of a hot-pluggable slot). This function can be called - from interrupt context. + out of a hot-pluggable slot). This function always gets + called from process context, so it can sleep. suspend, Power management hooks -- called when the device goes to resume sleep or is resumed. diff -u --recursive --new-file v2.4.4/linux/Documentation/rtc.txt linux/Documentation/rtc.txt --- v2.4.4/linux/Documentation/rtc.txt Thu Jan 4 12:50:17 2001 +++ linux/Documentation/rtc.txt Sat May 19 17:43:05 2001 @@ -89,7 +89,7 @@ #include #include -void main(void) { +int main(void) { int i, fd, retval, irqcount = 0; unsigned long tmp, data; @@ -277,5 +277,6 @@ irqcount); close(fd); +return 0; } /* end main */ diff -u --recursive --new-file v2.4.4/linux/Documentation/s390/3270.txt linux/Documentation/s390/3270.txt --- v2.4.4/linux/Documentation/s390/3270.txt Thu Apr 12 12:03:50 2001 +++ linux/Documentation/s390/3270.txt Thu May 24 15:14:08 2001 @@ -100,9 +100,9 @@ you will see login prompts appear on your 3270s as soon as boot is complete (or with emulated 3270s, as soon as you dial into your vm guest using the command "DIAL "). - Since the line-mode major number is 212, the line to add to + Since the line-mode major number is 227, the line to add to /etc/modules.conf should be: - alias char-major-212 tub3270 + alias char-major-227 tub3270 3. Define graphic devices to your vm guest machine, if you haven't already. Define them before you reboot (reipl): @@ -175,7 +175,7 @@ C. Are the device special files created, as in installation step 2 above? Use the ls -l command to find out; for instance, issue "ls -l /dev/3270/tty620". The output should start with the - letter "c" meaning character device and should contain "212, 1" + letter "c" meaning character device and should contain "227, 1" just to the left of the device name. No such file? no "c"? Wrong major number? Wrong minor number? There's your problem! diff -u --recursive --new-file v2.4.4/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt --- v2.4.4/linux/Documentation/scsi-generic.txt Thu Apr 12 12:03:50 2001 +++ linux/Documentation/scsi-generic.txt Tue May 1 16:04:56 2001 @@ -238,8 +238,8 @@ open(const char * filename, int flags) -------------------------------------- The filename should be an 'sg' device such as -/dev/sg[a-z] /dev/sg[0,1,2,...] +/dev/sg[a-z] <<< now deprecated >>> or a symbolic link to one of these. [Devfs has its own sub-directory for sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .] It seems as though SCSI devices are allocated to sg minor numbers in the diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16 --- v2.4.4/linux/Documentation/sound/MAD16 Mon Aug 23 10:23:23 1999 +++ linux/Documentation/sound/MAD16 Tue May 1 16:05:00 2001 @@ -1,3 +1,5 @@ +(This recipe has been edited to update the configuration symbols.) + From: Shaw Carruthers I have been using mad16 sound for some time now with no problems, current @@ -14,9 +16,9 @@ .config has: CONFIG_SOUND=m -CONFIG_ADLIB=m -CONFIG_MAD16=m -CONFIG_YM3812=m +CONFIG_SOUND_ADLIB=m +CONFIG_SOUND_MAD16=m +CONFIG_SOUND_YM3812=m modules.conf has: diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/Opti linux/Documentation/sound/Opti --- v2.4.4/linux/Documentation/sound/Opti Wed Mar 8 11:37:03 2000 +++ linux/Documentation/sound/Opti Tue May 1 16:05:00 2001 @@ -29,21 +29,21 @@ Sound card support should be enabled as a module (chose m). Answer 'm' for these items: - Generic OPL2/OPL3 FM synthesizer support (CONFIG_ADLIB) - Microsoft Sound System support (CONFIG_MSS) - Support for OPTi MAD16 and/or Mozart based cards (CONFIG_MAD16) - FM synthesizer (YM3812/OPL-3) support (CONFIG_YM3812) + Generic OPL2/OPL3 FM synthesizer support (CONFIG_SOUND_ADLIB) + Microsoft Sound System support (CONFIG_SOUND_MSS) + Support for OPTi MAD16 and/or Mozart based cards (CONFIG_SOUND_MAD16) + FM synthesizer (YM3812/OPL-3) support (CONFIG_SOUND_YM3812) The configuration menu may ask for addresses, IRQ lines or DMA channels. If the card is used as a module the module loading options will override these values. For the OPTi 931 you can answer 'n' to: - Support MIDI in older MAD16 based cards (requires SB) (CONFIG_MAD16_OLDCARD) + Support MIDI in older MAD16 based cards (requires SB) (CONFIG_SOUND_MAD16_OLDCARD) If you do need MIDI support in a Mozart or C928 based card you need to answer 'm' to the above question. In that case you will also need to answer 'm' to: - '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB) + '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB) Go on and compile your kernel and modules. Install the modules. Run depmod -a. diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/cs46xx linux/Documentation/sound/cs46xx --- v2.4.4/linux/Documentation/sound/cs46xx Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/cs46xx Sat May 19 17:43:05 2001 @@ -0,0 +1,138 @@ + +Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio +controller chips (2001/05/11) + +The cs46xx audio driver supports the DSP line of Cirrus controllers. +Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280 +products. This driver uses the generic ac97_codec driver for AC97 codec +support. + + +Features: + +Full Duplex Playback/Capture supported from 8k-48k. +16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported. + +APM/PM - 2.2.x PM is enabled and functional. APM can also +be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro +definition. + +DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg +(defaultorder=11). DMA capture buffer size is fixed at a single 4k page as +two 2k fragments. + +MMAP seems to work well with QuakeIII, and test XMMS plugin. + +Myth2 works, but the polling logic is not fully correct, but is functional. + +The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested +with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o). This +audio driver must be loaded prior to the joystick driver to enable the +DSP task image supporting the joystick device. + + +Limitations: + +SPDIF is currently not supported. + +Primary codec support only. No secondary codec support is implemented. + + + +NOTES: + +Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp, +and has been tested. +Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR +to disable the external amplifier. + +VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control +the external amplifier for the "back" speakers, since we do not +support the secondary codec then this external amp is not +turned on. The primary codec external amplifier is supported but +note that the AC97 EAPD bit is inverted logic (amp_voyetra()). + +DMA buffer size - there are issues with many of the Linux applications +concerning the optimal buffer size. Several applications request a +certain fragment size and number and then do not verify that the driver +has the ability to support the requested configuration. +SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and +number of fragments. Some applications exit if an error is returned +on this particular ioctl. Therefore, in alignment with the other OSS audio +drivers, no error is returned when a SETFRAGs IOCTL is received, but the +values passed from the app are not used in any buffer calculation +(ossfragshift/ossmaxfrags are not used). +Use the "defaultorder=N" module parameter to change the buffer size if +you have an application that requires a specific number of fragments +or a specific buffer size (see below). + +Debug Interface +--------------- +There is an ioctl debug interface to allow runtime modification of the +debug print levels. This debug interface code can be disabled from the +compilation process with commenting the following define: +#define CSDEBUG_INTERFACE 1 +There is also a debug print methodolgy to select printf statements from +different areas of the driver. A debug print level is also used to allow +additional printfs to be active. Comment out the following line in the +driver to disable compilation of the CS_DBGOUT print statements: +#define CSDEBUG 1 + +Please see the defintions for cs_debuglevel and cs_debugmask for additional +information on the debug levels and sections. + +There is also a csdbg executable to allow runtime manipulation of these +parameters. for a copy email: twoller@crystal.cirrus.com + + + +MODULE_PARMS definitions +------------------------ +MODULE_PARM(defaultorder, "i"); +defaultorder=N +where N is a value from 1 to 12 +The buffer order determines the size of the dma buffer for the driver. +under Linux, a smaller buffer allows more responsiveness from many of the +applications (e.g. games). A larger buffer allows some of the apps (esound) +to not underrun the dma buffer as easily. As default, use 32k (order=3) +rather than 64k as some of the games work more responsively. +(2^N) * PAGE_SIZE = allocated buffer size + +MODULE_PARM(cs_debuglevel, "i"); +MODULE_PARM(cs_debugmask, "i"); +cs_debuglevel=N +cs_debugmask=0xMMMMMMMM +where N is a value from 0 (no debug printfs), to 9 (maximum) +0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source). + +MODULE_PARM(hercules_egpio_disable, "i"); +hercules_egpio_disable=N +where N is a 0 (enable egpio), or a 1 (disable egpio support) + +MODULE_PARM(initdelay, "i"); +initdelay=N +This value is used to determine the millescond delay during the initialization +code prior to powering up the PLL. On laptops this value can be used to +assist with errors on resume, mostly with IBM laptops. Basically, if the +system is booted under battery power then the mdelay()/udelay() functions fail to +properly delay the required time. Also, if the system is booted under AC power +and then the power removed, the mdelay()/udelay() functions will not delay properly. + +MODULE_PARM(powerdown, "i"); +powerdown=N +where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown) + + +MODULE_PARM(external_amp, "i"); +external_amp=1 +if N is set to 1, then force enabling the EAPD support in the primary AC97 codec. +override the detection logic and force the external amp bit in the AC97 0x26 register +to be reset (0). EAPD should be 0 for powerup, and 1 for powerdown. The VTB Santa Cruz +card has inverted logic, so there is a special function for these cards. + +MODULE_PARM(thinkpad, "i"); +thinkpad=1 +if N is set to 1, then force enabling the clkrun functionality. +Currently, when the part is being used, then clkrun is disabled for the entire system, +but re-enabled when the driver is released or there is no outstanding open count. + diff -u --recursive --new-file v2.4.4/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt --- v2.4.4/linux/Documentation/sysrq.txt Thu Mar 22 09:20:45 2001 +++ linux/Documentation/sysrq.txt Thu May 24 15:03:06 2001 @@ -29,7 +29,8 @@ You send a BREAK, then within 5 seconds a command key. Sending BREAK twice is interpreted as a normal BREAK. -On Mac - Press 'Keypad+-F13-' +On PowerPC - Press 'ALT - Print Screen (or F13) - , + Print Screen (or F13) - may suffice. On other - If you know of the key combos for other architectures, please let me know so I can add them to this section. diff -u --recursive --new-file v2.4.4/linux/Documentation/usb/hotplug.txt linux/Documentation/usb/hotplug.txt --- v2.4.4/linux/Documentation/usb/hotplug.txt Tue Jan 16 12:02:51 2001 +++ linux/Documentation/usb/hotplug.txt Sat May 19 17:49:14 2001 @@ -69,7 +69,10 @@ If "usbdevfs" is configured, DEVICE and DEVFS are also passed. DEVICE is the pathname of the device, and is useful for devices with multiple and/or -alternate interfaces that complicate driver selection. +alternate interfaces that complicate driver selection. By design, USB +hotplugging is independent of "usbdevfs": you can do most essential parts +of USB device setup without using that filesystem, and without running a +user mode daemon to detect changes in system configuration. Currently available policy agent implementations can load drivers for modules, and can invoke driver-specific setup scripts. The newest ones @@ -85,14 +88,26 @@ See for full information about such table entries; or look at existing drivers. Each table entry describes one or more criteria to -be used when matching a driver to a device or class of devices. +be used when matching a driver to a device or class of devices. The +specific criteria are identified by bits set in "match_flags", paired +with field values. You can construct the criteria directly, or with +macros such as these, and use driver_info to store more information. + + USB_DEVICE (vendorId, productId) + ... matching devices with specified vendor and product ids + USB_DEVICE_VER (vendorId, productId, lo, hi) + ... like USB_DEVICE with lo <= productversion <= hi + USB_INTERFACE_INFO (class, subclass, protocol) + ... matching specified interface class info + USB_DEVICE_INFO (class, subclass, protocol) + ... matching specified device class info A short example, for a driver that supports several specific USB devices and their quirks, might have a MODULE_DEVICE_TABLE like this: static const struct usb_device_id mydriver_id_table = { - { idVendor: 0x9999, idProduct 0xaaaa, driver_info: QUIRK_X }, - { idVendor: 0xbbbb, idProduct 0x8888, driver_info: QUIRK_Y|QUIRK_Z }, + { USB_DEVICE (0x9999, 0xaaaa), driver_info: QUIRK_X }, + { USB_DEVICE (0xbbbb, 0x8888), driver_info: QUIRK_Y|QUIRK_Z }, ... { } /* end with an all-zeroes entry */ } diff -u --recursive --new-file v2.4.4/linux/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt --- v2.4.4/linux/Documentation/usb/philips.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/usb/philips.txt Tue May 22 10:25:36 2001 @@ -0,0 +1,141 @@ +This file contains some additional information for the Philips webcams. +E-mail: webcam@smcc.demon.nl Last updated: 2001-04-25 + +The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/. +It contains a lot of extra information, a FAQ, and the binary plugin +'PWCX'. This plugin contains decompression routines that allow you to +use higher image sizes and framerates; in addition the webcam uses less +bandwidth on the USB bus (handy if you want to run more than 1 camera +simultaneously). These routines fall under an NDA, and may therefor not be +distributed as source; however, its use is completely optional. + +You can build this code either into your kernel, or as a module. I recommend +the latter, since it makes troubleshooting a lot easier. The built-in +microphone is supported through the USB Audio class. + +(Taken from install.html) + +When you load the module you can set some default settings for the +camera; some programs depend on a particular image-size or -format. The +options are: + +size + Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or + 'vga', for an image size of resp. 128x96, 160x120, 176x144, + 320x240, 352x288 and 640x480 (of course, only for those cameras that support these resolutions). + +fps + Specifies the desired framerate. Is an integer in the range of 4-30. + +palette + Specifies the desired colour order that should be delivered by read() and + mmap(). The string can be one of bgr24, rgb24, rgb32, bgr32, yuyv, + yuv420, yuv420p. If the tool you use produces odd colours (more + specificly, red and blue are swapped), try palette=bgr24 or + palette=rgb24. + +fbufs + This paramter specifies the number of internal buffers to use for storing + frames from the cam. This will help if the process that reads images from + the cam is a bit slow or momentarely busy. However, on slow machines it + only introduces lag, so choose carefully. The default is 3, which is + reasonable. You can set it between 2 and 5. + +mbufs + This is an integer between 1 and 4. It will tell the module the number of + buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. + The default is 2, which is adequate for most applications (double + buffering). + + Should you experience a lot of 'Dumping frame...' messages during + grabbing with a tool that uses mmap(), you might want to increase if. + However, it doesn't really buffer images, it just gives you a bit more + slack when your program is behind. But you need a multi-threaded or + forked program to really take advantage of these buffers. + + The absolute maximum is 4, but don't set it too high! Every buffer takes + up 1.22 MB of RAM, so unless you have a lot of memory setting this to + something more than 2 is an absolute waste. This memory is only + allocated during open(), so nothing is wasted when the camera is not in + use. + +power_save + When power_save is enabled (set to 1), the module will try to shut down + the cam on close() and re-activate on open(). This will save power and + turn off the LED. Not all cameras support this though (the 645 and 646 + don't have power saving at all), and some models don't work either (they + will shut down, but never wake up). Consider this experimental. By + default this option is disabled. + +compression (only useful with the plugin) + With this option you can control the compression factor that the camera + use to squeeze the image through the USB bus. You can set the + parameter between 0 and 3: + 0 = prefer uncompressed images; if the requested mode is not available + in an uncompressed format, the driver will silently switch to low + compression. + 1 = low compression. + 2 = medium compression. + 3 = high compression. + + High compression takes less bandwidth of course, but it could also + introduce some unwanted artefacts. The default is 2, medium compression. + See the FAQ on the website for an overview of which modes require + compression. + + The compression parameter only applies to the Vesta & ToUCam cameras. + The 645 and 646 have fixed compression parameters. + +trace + + In order to better detect problems, it is now possible to turn on a + 'trace' of some of the calls the module makes; it logs all items in your + kernel log at debug level. + + The trace variable is a bitmask; each bit represents a certain feature. + If you want to trace something, look up the bit value(s) in the table + below, add the values together and supply that to the trace variable. + + Value Value Description Default + (dec) (hex) + 1 0x1 Module initialization; this will log messages On + while loading and unloading the module + + 2 0x2 probe() and disconnect() traces On + + 4 0x4 Trace open() and close() calls Off + + 8 0x8 read(), mmap() and associated ioctl() calls Off + + 16 0x10 Memory allocation of buffers, etc. Off + + 32 0x20 Showing underflow, overflow and Dumping frame On + messages + + 64 0x40 Show viewport and image sizes Off + + + For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, + so you would supply trace=12 during insmod or modprobe. If + you want to turn the initialization and probing tracing off, set trace=0. + The default value for trace is 35 (0x23). + + Example: + + # modprobe pwc size=cif fps=15 power_save=1 + +The fbufs, mbufs and trace parameters are global and apply to all connected +cameras. Each camera has its own set of buffers. + +size, fps, palette only specify defaults when you open() the device; this is +to accommodate some tools that don't set the size or colour palette. You can +change these settings after open() with the Video4Linux ioctl() calls. The +default of defaults is QCIF size at 10 fps, BGR order. + +The compression parameter is semiglobal; it sets the initial compression +preference for all camera's, but this parameter can be set per camera with +the VIDIOCPWCSCQUAL ioctl() call. + +All parameters are optional. + + diff -u --recursive --new-file v2.4.4/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.4/linux/MAINTAINERS Wed Apr 25 14:35:25 2001 +++ linux/MAINTAINERS Sun May 20 12:11:38 2001 @@ -160,8 +160,8 @@ APPLETALK NETWORK LAYER P: Jay Schulist -M: jschlst@turbolinux.com -L: linux-atalk@netspace.org +M: jschlst@samba.org +L: linux-atalk@lists.netspace.org S: Maintained ARM MFM AND FLOPPY DRIVERS @@ -280,13 +280,17 @@ CONFIGURE, MENUCONFIG, XCONFIG P: Michael Elizabeth Chastain M: mec@shout.net -L: linux-kbuild@torque.net -W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +L: kbuild-devel@lists.sourceforge.net +W: http://kbuild.sourceforge.net S: Maintained CONFIGURE.HELP -P: Axel Boldt -M: axel@uni-paderborn.de +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 @@ -393,7 +397,7 @@ DISK GEOMETRY AND PARTITION HANDLING P: Andries Brouwer -M: aeb@veritas.com +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 @@ -405,6 +409,12 @@ L: linux-kernel@vger.kernel.org S: Maintained +DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER +P: Tobias Ringstrom +M: tori@unhappy.mine.nu +L: linux-kernel@vger.kernel.org +S: Maintained + DOUBLETALK DRIVER P: James R. Van Zandt M: jrv@vanzandt.mv.com @@ -495,6 +505,12 @@ L: linux-net@vger.kernel.org S: Maintained +FREEVXFS FILESYSTEM +P: Christoph Hellwig +M: hch@caldera.de +W: ftp://ftp.openlinux.org/pub/people/hch/vxfs +S: Maintained + FTAPE/QIC-117 P: Claus-Justus Heine M: claus@momo.math.rwth-aachen.de @@ -548,22 +564,6 @@ W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/ S: Maintained -KERNEL BUILD (Makefile, Rules.make, scripts/*) -P: Keith Owens -M: kaos@ocs.com.au -P: Michael Elizabeth Chastain -M: mec@shout.net -L: linux-kbuild@torque.net -W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ -S: Maintained - -LOGICAL VOLUME MANAGER -P: Heinz Mauelshagen -M: linux-LVM@EZ-Darmstadt.Telekom.de -L: linux-LVM@msede.com -W: http://linux.msede.com/lvm -S: Maintained - HIPPI P: Jes Sorensen M: jes@linuxcare.com @@ -694,9 +694,9 @@ M: jjciarla@raiz.uncu.edu.ar S: Maintained -IPX/SPX NETWORK LAYER -P: Jay Schulist -M: jschlst@turbolinux.com +IPX NETWORK LAYER +P: Arnaldo Carvalho de Melo +M: acme@conectiva.com.br L: linux-net@vger.kernel.org S: Maintained @@ -759,6 +759,15 @@ L: autofs@linux.kernel.org S: Maintained +KERNEL BUILD (Makefile, Rules.make, scripts/*) +P: Keith Owens +M: kaos@ocs.com.au +P: Michael Elizabeth Chastain +M: mec@shout.net +L: linux-kbuild@torque.net +W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +S: Maintained + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au @@ -793,6 +802,13 @@ L: linuxppc-dev@lists.linuxppc.org S: Maintained +LOGICAL VOLUME MANAGER +P: Heinz Mauelshagen +M: linux-LVM@EZ-Darmstadt.Telekom.de +L: linux-LVM@msede.com +W: http://linux.msede.com/lvm +S: Maintained + M68K P: Jes Sorensen M: jes@linuxcare.com @@ -927,6 +943,8 @@ M: ak@muc.de P: Alexey Kuznetsov M: kuznet@ms2.inr.ac.ru +P: Pekka Savola (ipv6) +M: pekkas@netcore.fi L: netdev@oss.sgi.com S: Maintained @@ -989,7 +1007,7 @@ P: Phil Blundell M: Philip.Blundell@pobox.com P: Tim Waugh -M: tim@cyberelk.demon.co.uk +M: tim@cyberelk.net P: David Campbell M: campbell@torque.net P: Andrea Arcangeli @@ -1000,7 +1018,7 @@ PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES P: Tim Waugh -M: tim@cyberelk.demon.co.uk +M: tim@cyberelk.net L: linux-parport@torque.net W: http://www.torque.net/linux-pp.html S: Maintained @@ -1171,7 +1189,7 @@ SMB FILESYSTEM P: Urban Widmark -M: urban@svenskatest.se +M: urban@teststation.com W: http://samba.org/ L: samba@samba.org S: Maintained @@ -1222,13 +1240,13 @@ SPX NETWORK LAYER P: Jay Schulist -M: jschlst@turbolinux.com +M: jschlst@samba.org L: linux-net@vger.kernel.org S: Supported SNA NETWORK LAYER P: Jay Schulist -M: jschlst@turbolinux.com +M: jschlst@samba.org L: linux-sna@turbolinux.com W: http://www.linux-sna.org S: Supported diff -u --recursive --new-file v2.4.4/linux/Makefile linux/Makefile --- v2.4.4/linux/Makefile Fri Apr 27 18:17:19 2001 +++ linux/Makefile Fri May 25 09:51:33 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 4 +SUBLEVEL = 5 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -118,11 +118,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o NETWORKS =net/network.o -DRIVERS =drivers/block/block.o \ - drivers/char/char.o \ - drivers/misc/misc.o \ - drivers/net/net.o \ - drivers/media/media.o + LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib @@ -132,6 +128,11 @@ DRIVERS- := DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o +DRIVERS-y += drivers/char/char.o \ + drivers/block/block.o \ + drivers/misc/misc.o \ + drivers/net/net.o \ + drivers/media/media.o DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a @@ -144,7 +145,6 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o -DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -178,7 +178,7 @@ DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o -DRIVERS += $(DRIVERS-y) +DRIVERS := $(DRIVERS-y) # files removed with 'make clean' @@ -416,7 +416,7 @@ distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS tags + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz diff -u --recursive --new-file v2.4.4/linux/arch/alpha/boot/tools/objstrip.c linux/arch/alpha/boot/tools/objstrip.c --- v2.4.4/linux/arch/alpha/boot/tools/objstrip.c Tue Jul 11 19:02:37 2000 +++ linux/arch/alpha/boot/tools/objstrip.c Mon May 21 13:41:40 2001 @@ -14,6 +14,8 @@ * Richard L. Sites and Richard T. Witek. */ #include +#include +#include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.4/linux/arch/alpha/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/alpha/config.in Fri May 25 09:55:36 2001 @@ -59,7 +59,7 @@ Wildfire CONFIG_ALPHA_WILDFIRE" Generic # clear all implied options (don't want default values for those): -unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 CONFIG_ALPHA_EV67 +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 unset CONFIG_ALPHA_EISA unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS @@ -141,12 +141,10 @@ then define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y - bool 'EV67 (or later) CPU (speed > 600MHz)?' CONFIG_ALPHA_EV67 fi if [ "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "y" ] then define_bool CONFIG_ALPHA_EV6 y - define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then @@ -166,7 +164,6 @@ then define_bool CONFIG_ALPHA_IRONGATE y define_bool CONFIG_ALPHA_EV6 y - define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ @@ -209,15 +206,15 @@ bool 'Symmetric multi-processing support' CONFIG_SMP fi -# The machine must be able to support more than 8GB physical memory -# before large vmalloc might even pretend to be an issue. -if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_DP264" = "y" \ - -o "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "y" ] -then - bool 'Large VMALLOC support' CONFIG_ALPHA_LARGE_VMALLOC -else - define_bool CONFIG_ALPHA_LARGE_VMALLOC n +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Discontiguous Memory Support' CONFIG_DISCONTIGMEM + if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then + bool ' NUMA Support' CONFIG_NUMA + fi fi + +# LARGE_VMALLOC is racy, if you *really* need it then fix it first +define_bool CONFIG_ALPHA_LARGE_VMALLOC n source drivers/pci/Config.in diff -u --recursive --new-file v2.4.4/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.4.4/linux/arch/alpha/defconfig Sun Mar 4 14:30:18 2001 +++ linux/arch/alpha/defconfig Fri May 4 15:16:28 2001 @@ -286,7 +286,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.4.4/linux/arch/alpha/kernel/alpha_ksyms.c Fri Apr 20 18:26:15 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Fri May 25 09:54:50 2001 @@ -188,6 +188,7 @@ EXPORT_SYMBOL(flush_tlb_all); EXPORT_SYMBOL(flush_tlb_mm); EXPORT_SYMBOL(flush_tlb_range); +EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(__cpu_number_map); @@ -206,6 +207,7 @@ EXPORT_SYMBOL(write_lock); EXPORT_SYMBOL(read_lock); #endif +EXPORT_SYMBOL(cpu_present_mask); #endif /* CONFIG_SMP */ EXPORT_SYMBOL(rtc_lock); @@ -229,6 +231,6 @@ EXPORT_SYMBOL_NOVERS(__remqu); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memchr); EXPORT_SYMBOL(get_wchan); -EXPORT_SYMBOL(flush_tlb_page); diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.4.4/linux/arch/alpha/kernel/core_cia.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/core_cia.c Tue May 22 16:29:57 2001 @@ -308,66 +308,29 @@ } /* - * Fixup attempt number 1. - * - * Write zeros directly into the tag registers. + * On PYXIS, even if the tbia works, we cannot use it. It effectively locks + * the chip (as well as direct write to the tag registers) if there is a + * SG DMA operation in progress. This is true at least for PYXIS rev. 1, + * so always use the method below. */ - -static void -cia_pci_tbi_try1(struct pci_controller *hose, - dma_addr_t start, dma_addr_t end) -{ - wmb(); - *(vip)CIA_IOC_TB_TAGn(0) = 0; - *(vip)CIA_IOC_TB_TAGn(1) = 0; - *(vip)CIA_IOC_TB_TAGn(2) = 0; - *(vip)CIA_IOC_TB_TAGn(3) = 0; - *(vip)CIA_IOC_TB_TAGn(4) = 0; - *(vip)CIA_IOC_TB_TAGn(5) = 0; - *(vip)CIA_IOC_TB_TAGn(6) = 0; - *(vip)CIA_IOC_TB_TAGn(7) = 0; - mb(); - *(vip)CIA_IOC_TB_TAGn(0); -} - -#if 0 /* - * Fixup attempt number 2. This is the method NT and NetBSD use. + * This is the method NT and NetBSD use. * * Allocate mappings, and put the chip into DMA loopback mode to read a * garbage page. This works by causing TLB misses, causing old entries to * be purged to make room for the new entries coming in for the garbage page. */ -#define CIA_BROKEN_TBI_TRY2_BASE 0xE0000000 - -static void __init -cia_enable_broken_tbi_try2(void) -{ - unsigned long *ppte, pte; - long i; - - ppte = __alloc_bootmem(PAGE_SIZE, 32768, 0); - pte = (virt_to_phys(ppte) >> (PAGE_SHIFT - 1)) | 1; - - for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); ++i) - ppte[i] = pte; - - *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBI_TRY2_BASE | 3; - *(vip)CIA_IOC_PCI_W3_MASK = (PAGE_SIZE - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2; -} +#define CIA_BROKEN_TBIA_BASE 0xE0000000 +#define CIA_BROKEN_TBIA_SIZE 1024 -static void +/* Always called with interrupts disabled */ +void cia_pci_tbi_try2(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { - unsigned long flags; unsigned long bus_addr; int ctrl; - long i; - - __save_and_cli(flags); /* Put the chip into PCI loopback mode. */ mb(); @@ -382,10 +345,19 @@ TLB entries are not quite LRU, meaning that we need to read more times than there are actual tags. The 2117x docs claim strict round-robin. Oh well, we've come this far... */ - - bus_addr = cia_ioremap(CIA_BROKEN_TBI_TRY2_BASE); - for (i = 0; i < 12; ++i, bus_addr += 32768) - cia_readl(bus_addr); + /* Even better - as seen on the PYXIS rev 1 the TLB tags 0-3 can + be filled by the TLB misses *only once* after being invalidated + (by tbia or direct write). Next misses won't update them even + though the lock bits are cleared. Tags 4-7 are "quite LRU" though, + so use them and read at window 3 base exactly 4 times. Reading + more sometimes makes the chip crazy. -ink */ + + bus_addr = cia_ioremap(CIA_BROKEN_TBIA_BASE); + + cia_readl(bus_addr + 0x00000); + cia_readl(bus_addr + 0x08000); + cia_readl(bus_addr + 0x10000); + cia_readl(bus_addr + 0x18000); /* Restore normal PCI operation. */ mb(); @@ -393,10 +365,26 @@ mb(); *(vip)CIA_IOC_CIA_CTRL; mb(); +} + +static inline void +cia_prepare_tbia_workaround(void) +{ + unsigned long *ppte, pte; + long i; + + /* Use minimal 1K map. */ + ppte = __alloc_bootmem(CIA_BROKEN_TBIA_SIZE, 32768, 0); + pte = (virt_to_phys(ppte) >> (PAGE_SHIFT - 1)) | 1; - __restore_flags(flags); + for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i) + ppte[i] = pte; + + *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBIA_BASE | 3; + *(vip)CIA_IOC_PCI_W3_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1) + & 0xfff00000; + *(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2; } -#endif static void __init verify_tb_operation(void) @@ -407,7 +395,11 @@ struct pci_iommu_arena *arena = pci_isa_hose->sg_isa; int ctrl, addr0, tag0, pte0, data0; - int temp; + int temp, use_tbia_try2 = 0; + + /* pyxis -- tbia is broken */ + if (pci_isa_hose->dense_io_base) + use_tbia_try2 = 1; /* Put the chip into PCI loopback mode. */ mb(); @@ -489,22 +481,15 @@ /* Third, try to invalidate the TLB. */ - cia_pci_tbi(arena->hose, 0, -1); - temp = *(vip)CIA_IOC_TB_TAGn(0); - if (temp & 1) { - cia_pci_tbi_try1(arena->hose, 0, -1); - + if (! use_tbia_try2) { + cia_pci_tbi(arena->hose, 0, -1); temp = *(vip)CIA_IOC_TB_TAGn(0); if (temp & 1) { - printk("pci: failed tbia test; " - "no usable workaround\n"); - goto failed; + use_tbia_try2 = 1; + printk("pci: failed tbia test; workaround available\n"); + } else { + printk("pci: passed tbia test\n"); } - - alpha_mv.mv_pci_tbi = cia_pci_tbi_try1; - printk("pci: failed tbia test; workaround 1 succeeded\n"); - } else { - printk("pci: passed tbia test\n"); } /* Fourth, verify the TLB snoops the EV5's caches when @@ -574,6 +559,19 @@ /* Clean up after the tests. */ arena->ptes[4] = 0; arena->ptes[5] = 0; + + if (use_tbia_try2) { + alpha_mv.mv_pci_tbi = cia_pci_tbi_try2; + + /* Tags 0-3 must be disabled if we use this workaraund. */ + wmb(); + *(vip)CIA_IOC_TB_TAGn(0) = 2; + *(vip)CIA_IOC_TB_TAGn(1) = 2; + *(vip)CIA_IOC_TB_TAGn(2) = 2; + *(vip)CIA_IOC_TB_TAGn(3) = 2; + + printk("pci: tbia workaround enabled\n"); + } alpha_mv.mv_pci_tbi(arena->hose, 0, -1); exit: @@ -706,7 +704,8 @@ *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000; *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2; - *(vip)CIA_IOC_PCI_W3_BASE = 0; + /* Prepare workaround for apparently broken tbia. */ + cia_prepare_tbia_workaround(); } void __init diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.4.4/linux/arch/alpha/kernel/core_tsunami.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/core_tsunami.c Thu May 24 15:24:37 2001 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -222,7 +223,6 @@ it's the shifted tag bits. */ value = (start & 0xffff0000) >> 12; - wmb(); *csr = value; mb(); *csr; @@ -278,6 +278,16 @@ #define FN __FUNCTION__ static void __init +tsunami_monster_window_enable(tsunami_pchip * pchip) +{ + volatile unsigned long * csr = &pchip->pctl.csr; + + *csr |= pctl_m_mwin; + mb(); + *csr; +} + +static void __init tsunami_init_one_pchip(tsunami_pchip *pchip, int index) { struct pci_controller *hose; @@ -358,7 +368,13 @@ * address range. */ hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); - hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + { + unsigned long size = 0x08000000; + if (max_low_pfn > (0x80000000 >> PAGE_SHIFT)) + size = 0x40000000; + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, size, 0); + } + __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; @@ -379,6 +395,9 @@ pchip->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); tsunami_pci_tbi(hose, 0, -1); + + /* Enable the Monster Window to make DAC pci64 possible. */ + tsunami_monster_window_enable(pchip); } void __init diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.4/linux/arch/alpha/kernel/entry.S Sun Sep 3 11:36:45 2000 +++ linux/arch/alpha/kernel/entry.S Thu May 24 15:20:18 2001 @@ -10,7 +10,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 377 +#define NR_SYSCALLS 378 /* * These offsets must match with alpha_mv in . @@ -709,16 +709,14 @@ br restore_all .end entSys -#ifdef CONFIG_SMP - .globl ret_from_smp_fork + .globl ret_from_fork .align 3 -.ent ret_from_smp_fork -ret_from_smp_fork: +.ent ret_from_fork +ret_from_fork: lda $26,ret_from_sys_call mov $17,$16 jsr $31,schedule_tail -.end ret_from_smp_fork -#endif /* CONFIG_SMP */ +.end ret_from_fork .align 3 .ent reschedule diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.4.4/linux/arch/alpha/kernel/pci.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/pci.c Mon May 21 13:38:41 2001 @@ -156,7 +156,7 @@ else if (res->flags & IORESOURCE_MEM) { /* Make sure we start at our min on all hoses */ if (start - hose->mem_space->start < PCIBIOS_MIN_MEM) - start = PCIBIOS_MIN_MEM + hose->io_space->start; + start = PCIBIOS_MIN_MEM + hose->mem_space->start; /* * The following holds at least for the Low Cost @@ -441,15 +441,15 @@ if (hose->index == bus) break; if (!hose) return -ENODEV; } else { - /* Special hook for ISA access. */ - if (bus == 0 && dfn == 0) { - hose = pci_isa_hose; - } else { - dev = pci_find_slot(bus, dfn); - if (!dev) - return -ENODEV; - hose = dev->sysdata; - } + /* Special hook for ISA access. */ + if (bus == 0 && dfn == 0) { + hose = pci_isa_hose; + } else { + dev = pci_find_slot(bus, dfn); + if (!dev) + return -ENODEV; + hose = dev->sysdata; + } } switch (which & ~IOBASE_FROM_HOSE) { @@ -468,4 +468,12 @@ } return -EOPNOTSUPP; +} + +/* Return the index of the PCI controller for device PDEV. */ +int +pci_controller_num(struct pci_dev *pdev) +{ + struct pci_controller *hose = pdev->sysdata; + return (hose ? hose->index : -ENXIO); } diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- v2.4.4/linux/arch/alpha/kernel/pci_impl.h Sun Mar 25 18:24:31 2001 +++ linux/arch/alpha/kernel/pci_impl.h Fri May 25 09:54:50 2001 @@ -135,6 +135,7 @@ { spinlock_t lock; struct pci_controller *hose; +#define IOMMU_INVALID_PTE 0x2 /* 32:63 bits MBZ */ unsigned long *ptes; dma_addr_t dma_base; unsigned int size; diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.4.4/linux/arch/alpha/kernel/pci_iommu.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/pci_iommu.c Fri May 25 09:54:50 2001 @@ -42,6 +42,25 @@ return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; } +static void __init +iommu_arena_fixup(struct pci_iommu_arena * arena) +{ + unsigned long base, size; + + /* + * The Cypress chip has a quirk, it get confused by addresses + * above -1M so reserve the pagetables that maps pci addresses + * above -1M. + */ + base = arena->dma_base; + size = arena->size; + if (base + size > 0xfff00000) { + int i = (0xfff00000 - base) >> PAGE_SHIFT; + for (; i < (0x100000 >> PAGE_SHIFT); i++) + arena->ptes[i] = IOMMU_INVALID_PTE; + } +} + struct pci_iommu_arena * iommu_arena_new(struct pci_controller *hose, dma_addr_t base, unsigned long window_size, unsigned long align) @@ -71,6 +90,8 @@ unless there are chip bugs. */ arena->align_entry = 1; + iommu_arena_fixup(arena); + return arena; } @@ -115,12 +136,12 @@ } } - /* Success. Mark them all in use, ie not zero. Typically - bit zero is the valid bit, so write ~1 into everything. + /* Success. Mark them all in use, ie not zero and invalid + for the iommu tlb that could load them from under us. The chip specific bits will fill this in with something kosher when we return. */ for (i = 0; i < n; ++i) - ptes[p+i] = ~1UL; + ptes[p+i] = IOMMU_INVALID_PTE; arena->next_entry = p + n; spin_unlock_irqrestore(&arena->lock, flags); @@ -175,7 +196,7 @@ /* If the machine doesn't define a pci_tbi routine, we have to assume it doesn't support sg mapping. */ if (! alpha_mv.mv_pci_tbi) { - printk(KERN_INFO "pci_map_single failed: no hw sg\n"); + printk(KERN_WARNING "pci_map_single failed: no hw sg\n"); return 0; } @@ -186,7 +207,7 @@ npages = calc_npages((paddr & ~PAGE_MASK) + size); dma_ofs = iommu_arena_alloc(arena, npages); if (dma_ofs < 0) { - printk(KERN_INFO "pci_map_single failed: " + printk(KERN_WARNING "pci_map_single failed: " "could not allocate dma page tables\n"); return 0; } @@ -215,6 +236,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction) { + unsigned long flags; struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; struct pci_iommu_arena *arena; long dma_ofs, npages; @@ -248,6 +270,9 @@ } npages = calc_npages((dma_addr & ~PAGE_MASK) + size); + + spin_lock_irqsave(&arena->lock, flags); + iommu_arena_free(arena, dma_ofs, npages); @@ -259,6 +284,8 @@ if (dma_ofs >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); + spin_unlock_irqrestore(&arena->lock, flags); + DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", dma_addr, size, npages, __builtin_return_address(0)); } @@ -402,8 +429,20 @@ paddr &= ~PAGE_MASK; npages = calc_npages(paddr + size); dma_ofs = iommu_arena_alloc(arena, npages); - if (dma_ofs < 0) - return -1; + if (dma_ofs < 0) { + /* If we attempted a direct map above but failed, die. */ + if (leader->dma_address == 0) + return -1; + + /* Otherwise, break up the remaining virtually contiguous + hunks into individual direct maps. */ + for (sg = leader; sg < end; ++sg) + if (sg->dma_address == 1 || sg->dma_address == -2) + sg->dma_address = 0; + + /* Retry. */ + return sg_fill(leader, end, out, arena, max_dma); + } out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr; out->dma_length = size; @@ -503,13 +542,13 @@ out->dma_length = 0; if (out - start == 0) - printk(KERN_INFO "pci_map_sg failed: no entries?\n"); + printk(KERN_WARNING "pci_map_sg failed: no entries?\n"); DBGA("pci_map_sg: %ld entries\n", out - start); return out - start; error: - printk(KERN_INFO "pci_map_sg failed: " + printk(KERN_WARNING "pci_map_sg failed: " "could not allocate dma page tables\n"); /* Some allocation failed while mapping the scatterlist @@ -528,6 +567,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { + unsigned long flags; struct pci_controller *hose; struct pci_iommu_arena *arena; struct scatterlist *end; @@ -547,6 +587,9 @@ arena = hose->sg_isa; fbeg = -1, fend = 0; + + spin_lock_irqsave(&arena->lock, flags); + for (end = sg + nents; sg < end; ++sg) { unsigned long addr, size; long npages, ofs; @@ -586,6 +629,8 @@ */ if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, fbeg, fend); + + spin_unlock_irqrestore(&arena->lock, flags); DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); } diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.4.4/linux/arch/alpha/kernel/process.c Fri Feb 9 11:29:44 2001 +++ linux/arch/alpha/kernel/process.c Thu May 24 15:20:18 2001 @@ -83,10 +83,11 @@ /* Although we are an idle CPU, we do not want to get into the scheduler unnecessarily. */ - if (current->need_resched) { - schedule(); - check_pgt_cache(); - } + long oldval = xchg(¤t->need_resched, -1UL); + if (!oldval) + while (current->need_resched < 0); + schedule(); + check_pgt_cache(); } } @@ -303,7 +304,7 @@ struct task_struct * p, struct pt_regs * regs) { extern void ret_from_sys_call(void); - extern void ret_from_smp_fork(void); + extern void ret_from_fork(void); struct pt_regs * childregs; struct switch_stack * childstack, *stack; @@ -322,11 +323,7 @@ stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; -#ifdef CONFIG_SMP - childstack->r26 = (unsigned long) ret_from_smp_fork; -#else - childstack->r26 = (unsigned long) ret_from_sys_call; -#endif + childstack->r26 = (unsigned long) ret_from_fork; p->thread.usp = usp; p->thread.ksp = (unsigned long) childstack; p->thread.pal_flags = 1; /* set FEN, clear everything else */ diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.4.4/linux/arch/alpha/kernel/setup.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/setup.c Thu May 24 15:20:18 2001 @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include @@ -87,18 +87,6 @@ static struct alpha_machine_vector *get_sysvec_byname(const char *); static void get_sysnames(long, long, char **, char **); -/* - * This is setup by the secondary bootstrap loader. Because - * the zero page is zeroed out as soon as the vm system is - * initialized, we need to copy things out into a more permanent - * place. - */ -#define PARAM ZERO_PGE -#define COMMAND_LINE ((char*)(PARAM + 0x0000)) -#define COMMAND_LINE_SIZE 256 -#define INITRD_START (*(unsigned long *) (PARAM+0x100)) -#define INITRD_SIZE (*(unsigned long *) (PARAM+0x108)) - static char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; @@ -245,6 +233,7 @@ return end >> PAGE_SHIFT; /* Return the PFN of the limit. */ } +#ifndef CONFIG_DISCONTIGMEM static void __init setup_memory(void *kernel_end) { @@ -362,6 +351,7 @@ /* Reserve the bootmap memory. */ reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size); + printk("reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size)); #ifdef CONFIG_BLK_DEV_INITRD initrd_start = INITRD_START; @@ -383,6 +373,9 @@ } #endif /* CONFIG_BLK_DEV_INITRD */ } +#else +extern void setup_memory(void *); +#endif /* !CONFIG_DISCONTIGMEM */ int __init page_is_ram(unsigned long pfn) diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.4/linux/arch/alpha/kernel/smp.c Tue Feb 13 14:13:43 2001 +++ linux/arch/alpha/kernel/smp.c Thu May 24 15:24:37 2001 @@ -123,6 +123,22 @@ cpu_data[cpuid].prof_multiplier = 1; } +static void __init +wait_boot_cpu_to_stop(int cpuid) +{ + long stop = jiffies + 10*HZ; + + while (time_before(jiffies, stop)) { + if (!smp_secondary_alive) + return; + barrier(); + } + + printk("wait_boot_cpu_to_stop: FAILED on CPU %d, hanging now\n", cpuid); + for (;;) + barrier(); +} + /* * Where secondaries begin a life of C. */ @@ -131,6 +147,11 @@ { int cpuid = hard_smp_processor_id(); + if (current != init_tasks[cpu_number_map(cpuid)]) { + printk("BUG: smp_calling: cpu %d current %p init_tasks[cpu_number_map(cpuid)] %p\n", + cpuid, current, init_tasks[cpu_number_map(cpuid)]); + } + DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); /* Turn on machine checks. */ @@ -154,12 +175,22 @@ /* Must have completely accurate bogos. */ __sti(); + + /* + * Wait boot CPU to stop with irq enabled before + * running calibrate_delay(). + */ + wait_boot_cpu_to_stop(cpuid); + mb(); calibrate_delay(); - smp_store_cpu_info(cpuid); - /* Allow master to continue. */ + smp_store_cpu_info(cpuid); + /* + * Allow master to continue only after we written + * the loops_per_jiffy. + */ wmb(); - smp_secondary_alive = cpuid; + smp_secondary_alive = 1; /* Wait for the go code. */ while (!smp_threads_ready) @@ -203,6 +234,7 @@ break; case EV6_CPU: + case EV67_CPU: on_chip_cache = 64 + 64; break; @@ -246,7 +278,7 @@ + hwrpb->processor_offset + cpuid * hwrpb->processor_size); - cpumask = (1L << cpuid); + cpumask = (1UL << cpuid); if (hwrpb->txrdy & cpumask) goto delay1; ready1: @@ -267,8 +299,8 @@ return; delay1: - /* Wait one second. Note that jiffies aren't ticking yet. */ - for (timeout = 100000; timeout > 0; --timeout) { + /* Wait 10 seconds. Note that jiffies aren't ticking yet. */ + for (timeout = 1000000; timeout > 0; --timeout) { if (!(hwrpb->txrdy & cpumask)) goto ready1; udelay(10); @@ -277,8 +309,8 @@ goto timeout; delay2: - /* Wait one second. */ - for (timeout = 100000; timeout > 0; --timeout) { + /* Wait 10 seconds. */ + for (timeout = 1000000; timeout > 0; --timeout) { if (!(hwrpb->txrdy & cpumask)) goto ready2; udelay(10); @@ -307,7 +339,7 @@ mycpu = hard_smp_processor_id(); for (i = 0; i < NR_CPUS; i++) { - if (!(txrdy & (1L << i))) + if (!(txrdy & (1UL << i))) continue; DBGS(("recv_secondary_console_msg: " @@ -375,7 +407,7 @@ #if 0 DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", - hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); + hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwpcb->unique)); #endif DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->thread.pal_flags)); @@ -398,9 +430,9 @@ send_secondary_console_msg("START\r\n", cpuid); - /* Wait 1 second for an ACK from the console. Note that jiffies + /* Wait 10 seconds for an ACK from the console. Note that jiffies aren't ticking yet. */ - for (timeout = 100000; timeout > 0; timeout--) { + for (timeout = 1000000; timeout > 0; timeout--) { if (cpu->flags & 1) goto started; udelay(10); @@ -447,6 +479,8 @@ idle = init_task.prev_task; if (!idle) panic("No idle process for CPU %d", cpuid); + if (idle == &init_task) + panic("idle process is init_task for CPU %d", cpuid); idle->processor = cpuid; __cpu_logical_map[cpunum] = cpuid; @@ -468,10 +502,14 @@ if (secondary_cpu_start(cpuid, idle)) return -1; + mb(); + /* Notify the secondary CPU it can run calibrate_delay() */ + smp_secondary_alive = 0; + /* We've been acked by the console; wait one second for the task to start up for real. Note that jiffies aren't ticking yet. */ - for (timeout = 0; timeout < 100000; timeout++) { - if (smp_secondary_alive != -1) + for (timeout = 0; timeout < 1000000; timeout++) { + if (smp_secondary_alive == 1) goto alive; udelay(10); barrier(); @@ -523,7 +561,7 @@ if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; /* Assume here that "whami" == index */ - hwrpb_cpu_present_mask |= (1L << i); + hwrpb_cpu_present_mask |= (1UL << i); cpu->pal_revision = boot_cpu_palrev; } @@ -534,9 +572,9 @@ } } else { smp_num_probed = 1; - hwrpb_cpu_present_mask = (1L << boot_cpuid); + hwrpb_cpu_present_mask = (1UL << boot_cpuid); } - cpu_present_mask = 1L << boot_cpuid; + cpu_present_mask = 1UL << boot_cpuid; printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", smp_num_probed, hwrpb_cpu_present_mask); @@ -589,7 +627,7 @@ if (smp_boot_one_cpu(i, cpu_count)) continue; - cpu_present_mask |= 1L << i; + cpu_present_mask |= 1UL << i; cpu_count++; } @@ -600,7 +638,7 @@ bogosum = 0; for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_mask & (1L << i)) + if (cpu_present_mask & (1UL << i)) bogosum += cpu_data[i].loops_per_jiffy; } printk(KERN_INFO "SMP: Total of %d processors activated " @@ -798,13 +836,13 @@ printk(KERN_WARNING "smp_send_reschedule: Sending IPI to self.\n"); #endif - send_ipi_message(1L << cpu, IPI_RESCHEDULE); + send_ipi_message(1UL << cpu, IPI_RESCHEDULE); } void smp_send_stop(void) { - unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + unsigned long to_whom = cpu_present_mask ^ (1UL << smp_processor_id()); #if DEBUG_IPI_MSG if (hard_smp_processor_id() != boot_cpu_id) printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n"); @@ -827,7 +865,7 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { - unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + unsigned long to_whom = cpu_present_mask ^ (1UL << smp_processor_id()); struct smp_call_struct data; long timeout; @@ -1060,7 +1098,7 @@ int printed = 0; int cpu = smp_processor_id(); - stuck = 1L << 28; + stuck = 1L << 30; try_again: /* Use sub-sections to put the actual loop at the end @@ -1137,8 +1175,8 @@ try_again: - stuck_lock = 1<<26; - stuck_reader = 1<<26; + stuck_lock = 1<<30; + stuck_reader = 1<<30; __asm__ __volatile__( "1: ldl_l %1,%0\n" @@ -1182,7 +1220,7 @@ try_again: - stuck_lock = 1<<26; + stuck_lock = 1<<30; __asm__ __volatile__( "1: ldl_l %1,%0;" diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.4.4/linux/arch/alpha/kernel/sys_dp264.c Fri Mar 2 11:12:07 2001 +++ linux/arch/alpha/kernel/sys_dp264.c Fri May 25 09:54:50 2001 @@ -16,15 +16,18 @@ #include #include +#define __EXTERN_INLINE inline +#include +#include +#undef __EXTERN_INLINE + #include #include #include #include #include #include -#include #include -#include #include #include "proto.h" diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- v2.4.4/linux/arch/alpha/kernel/sys_miata.c Fri Oct 27 10:55:01 2000 +++ linux/arch/alpha/kernel/sys_miata.c Sat May 19 17:43:05 2001 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -223,11 +224,21 @@ static void miata_kill_arch(int mode) { - /* Who said DEC engineers have no sense of humor? ;-) */ - if (alpha_using_srm) { - *(vuip) PYXIS_RESET = 0x0000dead; - mb(); + switch(mode) { + case LINUX_REBOOT_CMD_RESTART: + /* Who said DEC engineers have no sense of humor? ;-) */ + if (alpha_using_srm) { + *(vuip) PYXIS_RESET = 0x0000dead; + mb(); + } + break; + case LINUX_REBOOT_CMD_HALT: + break; + case LINUX_REBOOT_CMD_POWER_OFF: + break; } + + halt(); } diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/sys_nautilus.c linux/arch/alpha/kernel/sys_nautilus.c --- v2.4.4/linux/arch/alpha/kernel/sys_nautilus.c Sun Mar 25 18:24:31 2001 +++ linux/arch/alpha/kernel/sys_nautilus.c Mon May 21 13:40:39 2001 @@ -55,7 +55,6 @@ { if (alpha_using_srm) { alpha_mv.device_interrupt = srm_device_interrupt; - alpha_mv.kill_arch = NULL; } init_i8259a_irqs(); @@ -77,7 +76,7 @@ { switch (mode) { case LINUX_REBOOT_CMD_RESTART: - { + if (! alpha_using_srm) { u8 t8; pcibios_read_config_byte(0, 0x38, 0x43, &t8); pcibios_write_config_byte(0, 0x38, 0x43, t8 | 0x80); diff -u --recursive --new-file v2.4.4/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.4.4/linux/arch/alpha/kernel/traps.c Thu Feb 8 12:56:29 2001 +++ linux/arch/alpha/kernel/traps.c Thu May 24 15:24:37 2001 @@ -291,12 +291,40 @@ * is interesting. */ printk("%6x%c", (int)tmp & 0xffffff, (++i % 11) ? ' ' : '\n'); +#if 0 if (i > 40) { printk(" ..."); break; } +#endif } printk("\n"); +} + +int kstack_depth_to_print = 24; + +void show_stack(unsigned long *sp) +{ + unsigned long *stack; + int i; + + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ + if(sp==NULL) + sp=(unsigned long*)&sp; + + stack = sp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 4) == 0)) + printk("\n "); + printk("%016lx ", *stack++); + } + printk("\n"); + dik_show_trace(sp); } void diff -u --recursive --new-file v2.4.4/linux/arch/alpha/mm/Makefile linux/arch/alpha/mm/Makefile --- v2.4.4/linux/arch/alpha/mm/Makefile Wed Oct 30 08:41:44 1996 +++ linux/arch/alpha/mm/Makefile Thu May 24 15:20:18 2001 @@ -7,9 +7,10 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -OBJS = init.o fault.o extable.o +O_TARGET := mm.o -mm.o: $(OBJS) - $(LD) -r -o mm.o $(OBJS) +obj-y := init.o fault.o extable.o + +obj-$(CONFIG_DISCONTIGMEM) += numa.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/alpha/mm/extable.c linux/arch/alpha/mm/extable.c --- v2.4.4/linux/arch/alpha/mm/extable.c Fri Sep 22 14:07:43 2000 +++ linux/arch/alpha/mm/extable.c Thu May 24 15:20:18 2001 @@ -45,20 +45,26 @@ /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); - if (ret) return ret; #else + extern spinlock_t modlist_lock; + unsigned long flags; /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; + + ret = 0; + spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp ; mp = mp->next) { - if (!mp->ex_table_start) + if (!mp->ex_table_start || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); - if (ret) return ret; + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); #endif - return 0; + return ret; } unsigned @@ -71,15 +77,23 @@ addr - exc_gp); if (ret) return ret; #else + extern spinlock_t modlist_lock; + unsigned long flags; /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; + + ret = 0; + spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp ; mp = mp->next) { - if (!mp->ex_table_start) + if (!mp->ex_table_start || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - exc_gp); - if (ret) return ret; + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); + if (ret) return ret; #endif /* diff -u --recursive --new-file v2.4.4/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.4.4/linux/arch/alpha/mm/init.c Fri Apr 13 20:26:06 2001 +++ linux/arch/alpha/mm/init.c Thu May 24 15:20:18 2001 @@ -33,7 +33,7 @@ #include #include -static unsigned long totalram_pages; +unsigned long totalram_pages; extern void die_if_kernel(char *,struct pt_regs *,long); @@ -115,6 +115,7 @@ return pte_mkdirty(mk_pte(virt_to_page(EMPTY_PGE), PAGE_SHARED)); } +#ifndef CONFIG_DISCONTIGMEM void show_mem(void) { @@ -144,6 +145,7 @@ printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); } +#endif static inline unsigned long load_PCB(struct thread_struct * pcb) @@ -275,6 +277,7 @@ } +#ifndef CONFIG_DISCONTIGMEM /* * paging_init() sets up the memory map. */ @@ -287,16 +290,7 @@ dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; high_pfn = max_low_pfn; -#define ORDER_MASK (~((1L << (MAX_ORDER-1))-1)) -#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) - - dma_pfn = ORDER_ALIGN(dma_pfn); - high_pfn = ORDER_ALIGN(high_pfn); - -#undef ORDER_MASK -#undef ORDER_ALIGN - - if (dma_pfn > high_pfn) + if (dma_pfn >= high_pfn) zones_size[ZONE_DMA] = high_pfn; else { zones_size[ZONE_DMA] = dma_pfn; @@ -309,6 +303,7 @@ /* Initialize the kernel's ZERO_PGE. */ memset((void *)ZERO_PGE, 0, PAGE_SIZE); } +#endif /* CONFIG_DISCONTIGMEM */ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) void @@ -327,6 +322,7 @@ } #endif +#ifndef CONFIG_DISCONTIGMEM static void __init printk_memory_info(void) { @@ -366,6 +362,7 @@ printk_memory_info(); } +#endif /* CONFIG_DISCONTIGMEM */ void free_initmem (void) @@ -388,13 +385,14 @@ void free_initrd_mem(unsigned long start, unsigned long end) { + unsigned long __start = start; for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk ("Freeing initrd memory: %ldk freed\n", (end - __start) >> 10); } #endif diff -u --recursive --new-file v2.4.4/linux/arch/alpha/mm/numa.c linux/arch/alpha/mm/numa.c --- v2.4.4/linux/arch/alpha/mm/numa.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/mm/numa.c Thu May 24 15:20:18 2001 @@ -0,0 +1,430 @@ +/* + * linux/arch/alpha/mm/numa.c + * + * DISCONTIGMEM NUMA alpha support. + * + * Copyright (C) 2001 Andrea Arcangeli SuSE + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#include +#include + +plat_pg_data_t *plat_node_data[MAX_NUMNODES]; +bootmem_data_t plat_node_bdata[MAX_NUMNODES]; + +#undef DEBUG_DISCONTIG +#ifdef DEBUG_DISCONTIG +#define DBGDCONT(args...) printk(args) +#else +#define DBGDCONT(args...) +#endif + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) +#define for_each_mem_cluster(memdesc, cluster, i) \ + for ((cluster) = (memdesc)->cluster, (i) = 0; \ + (i) < (memdesc)->numclusters; (i)++, (cluster)++) + +static void __init show_mem_layout(void) +{ + struct memclust_struct * cluster; + struct memdesc_struct * memdesc; + int i; + + /* Find free clusters, and init and free the bootmem accordingly. */ + memdesc = (struct memdesc_struct *) + (hwrpb->mddt_offset + (unsigned long) hwrpb); + + printk("Raw memory layout:\n"); + for_each_mem_cluster(memdesc, cluster, i) { + printk(" memcluster %2d, usage %1lx, start %8lu, end %8lu\n", + i, cluster->usage, cluster->start_pfn, + cluster->start_pfn + cluster->numpages); + } +} + +static void __init +setup_memory_node(int nid, void *kernel_end) +{ + extern unsigned long mem_size_limit; + struct memclust_struct * cluster; + struct memdesc_struct * memdesc; + unsigned long start_kernel_pfn, end_kernel_pfn; + unsigned long bootmap_size, bootmap_pages, bootmap_start; + unsigned long start, end; + unsigned long node_pfn_start, node_pfn_end; + int i; + unsigned long node_datasz = PFN_UP(sizeof(plat_pg_data_t)); + int show_init = 0; + + /* Find the bounds of current node */ + node_pfn_start = (nid * NODE_MAX_MEM_SIZE) >> PAGE_SHIFT; + node_pfn_end = node_pfn_start + (NODE_MAX_MEM_SIZE >> PAGE_SHIFT); + + /* Find free clusters, and init and free the bootmem accordingly. */ + memdesc = (struct memdesc_struct *) + (hwrpb->mddt_offset + (unsigned long) hwrpb); + + /* find the bounds of this node (min_low_pfn/max_low_pfn) */ + min_low_pfn = ~0UL; + for_each_mem_cluster(memdesc, cluster, i) { + /* Bit 0 is console/PALcode reserved. Bit 1 is + non-volatile memory -- we might want to mark + this for later. */ + if (cluster->usage & 3) + continue; + + start = cluster->start_pfn; + end = start + cluster->numpages; + + if (start >= node_pfn_end || end <= node_pfn_start) + continue; + + if (!show_init) { + show_init = 1; + printk("Initialing bootmem allocator on Node ID %d\n", nid); + } + printk(" memcluster %2d, usage %1lx, start %8lu, end %8lu\n", + i, cluster->usage, cluster->start_pfn, + cluster->start_pfn + cluster->numpages); + + if (start < node_pfn_start) + start = node_pfn_start; + if (end > node_pfn_end) + end = node_pfn_end; + + if (start < min_low_pfn) + min_low_pfn = start; + if (end > max_low_pfn) + max_low_pfn = end; + } + + if (mem_size_limit && max_low_pfn >= mem_size_limit) { + printk("setup: forcing memory size to %ldK (from %ldK).\n", + mem_size_limit << (PAGE_SHIFT - 10), + max_low_pfn << (PAGE_SHIFT - 10)); + max_low_pfn = mem_size_limit; + } + + if (min_low_pfn >= max_low_pfn) + return; + + num_physpages += max_low_pfn - min_low_pfn; + + /* Cute trick to make sure our local node data is on local memory */ + PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT)); + /* Quasi-mark the plat_pg_data_t as in-use */ + min_low_pfn += node_datasz; + if (min_low_pfn >= max_low_pfn) { + printk(" not enough mem to reserve PLAT_NODE_DATA"); + return; + } + NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; + + printk(" Detected node memory: start %8lu, end %8lu\n", + min_low_pfn, max_low_pfn); + + DBGDCONT(" DISCONTIG: plat_node_data[%d] is at 0x%p\n", nid, PLAT_NODE_DATA(nid)); + DBGDCONT(" DISCONTIG: NODE_DATA(%d)->bdata is at 0x%p\n", nid, NODE_DATA(nid)->bdata); + + /* Find the bounds of kernel memory. */ + start_kernel_pfn = PFN_DOWN(KERNEL_START_PHYS); + end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end)); + bootmap_start = -1; + + if (!nid && (max_low_pfn < end_kernel_pfn || min_low_pfn > start_kernel_pfn)) + panic("kernel loaded out of ram"); + + /* Zone start phys-addr must be 2^(MAX_ORDER-1) aligned */ + min_low_pfn = (min_low_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1); + + /* We need to know how many physically contiguous pages + we'll need for the bootmap. */ + bootmap_pages = bootmem_bootmap_pages(max_low_pfn-min_low_pfn); + + /* Now find a good region where to allocate the bootmap. */ + for_each_mem_cluster(memdesc, cluster, i) { + if (cluster->usage & 3) + continue; + + start = cluster->start_pfn; + end = start + cluster->numpages; + + if (start >= max_low_pfn || end <= min_low_pfn) + continue; + + if (end > max_low_pfn) + end = max_low_pfn; + if (start < min_low_pfn) + start = min_low_pfn; + + if (start < start_kernel_pfn) { + if (end > end_kernel_pfn + && end - end_kernel_pfn >= bootmap_pages) { + bootmap_start = end_kernel_pfn; + break; + } else if (end > start_kernel_pfn) + end = start_kernel_pfn; + } else if (start < end_kernel_pfn) + start = end_kernel_pfn; + if (end - start >= bootmap_pages) { + bootmap_start = start; + break; + } + } + + if (bootmap_start == -1) + panic("couldn't find a contigous place for the bootmap"); + + /* Allocate the bootmap and mark the whole MM as reserved. */ + bootmap_size = init_bootmem_node(NODE_DATA(nid), bootmap_start, + min_low_pfn, max_low_pfn); + DBGDCONT(" bootmap_start %lu, bootmap_size %lu, bootmap_pages %lu\n", + bootmap_start, bootmap_size, bootmap_pages); + + /* Mark the free regions. */ + for_each_mem_cluster(memdesc, cluster, i) { + if (cluster->usage & 3) + continue; + + start = cluster->start_pfn; + end = cluster->start_pfn + cluster->numpages; + + if (start >= max_low_pfn || end <= min_low_pfn) + continue; + + if (end > max_low_pfn) + end = max_low_pfn; + if (start < min_low_pfn) + start = min_low_pfn; + + if (start < start_kernel_pfn) { + if (end > end_kernel_pfn) { + free_bootmem_node(NODE_DATA(nid), PFN_PHYS(start), + (PFN_PHYS(start_kernel_pfn) + - PFN_PHYS(start))); + printk(" freeing pages %ld:%ld\n", + start, start_kernel_pfn); + start = end_kernel_pfn; + } else if (end > start_kernel_pfn) + end = start_kernel_pfn; + } else if (start < end_kernel_pfn) + start = end_kernel_pfn; + if (start >= end) + continue; + + free_bootmem_node(NODE_DATA(nid), PFN_PHYS(start), PFN_PHYS(end) - PFN_PHYS(start)); + printk(" freeing pages %ld:%ld\n", start, end); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(bootmap_start), bootmap_size); + printk(" reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size)); + + numnodes++; +} + +void __init +setup_memory(void *kernel_end) +{ + int nid; + + show_mem_layout(); + + numnodes = 0; + for (nid = 0; nid < MAX_NUMNODES; nid++) + setup_memory_node(nid, kernel_end); + +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = INITRD_START; + if (initrd_start) { + initrd_end = initrd_start+INITRD_SIZE; + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *) initrd_start, INITRD_SIZE); + + if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%p)\ndisabling initrd\n", + initrd_end, + phys_to_virt(PFN_PHYS(max_low_pfn))); + initrd_start = initrd_end = 0; + } else { + /* Assume the initrd to be in the first node */ + reserve_bootmem_node(NODE_DATA(nid), virt_to_phys((void *)initrd_start), + INITRD_SIZE); + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +void __init paging_init(void) +{ + unsigned int nid; + unsigned long zones_size[MAX_NR_ZONES] = {0, }; + unsigned long dma_local_pfn; + + /* + * The old global MAX_DMA_ADDRESS per-arch API doesn't fit + * in the NUMA model, for now we convert it to a pfn and + * we interpret this pfn as a local per-node information. + * This issue isn't very important since none of these machines + * have legacy ISA slots anyways. + */ + dma_local_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + + for (nid = 0; nid < numnodes; nid++) { + unsigned long start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT; + unsigned long end_pfn = plat_node_bdata[nid].node_low_pfn; + unsigned long lmax_mapnr; + + if (dma_local_pfn >= end_pfn - start_pfn) + zones_size[ZONE_DMA] = end_pfn - start_pfn; + else { + zones_size[ZONE_DMA] = dma_local_pfn; + zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn; + } + free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size, start_pfn< max_mapnr) { + max_mapnr = lmax_mapnr; + DBGDCONT("Grow max_mapnr to %ld\n", max_mapnr); + } + } + + /* Initialize the kernel's ZERO_PGE. */ + memset((void *)ZERO_PGE, 0, PAGE_SIZE); +} + +#define printkdot() \ +do { \ + if (!(i++ % ((100UL*1024*1024)>>PAGE_SHIFT))) \ + printk("."); \ +} while(0) + +#define clobber(p, size) memset((p)->virtual, 0xaa, (size)) + +void __init mem_stress(void) +{ + LIST_HEAD(x); + LIST_HEAD(xx); + struct page * p; + unsigned long i = 0; + + printk("starting memstress"); + while ((p = alloc_pages(GFP_ATOMIC, 1))) { + clobber(p, PAGE_SIZE*2); + list_add(&p->list, &x); + printkdot(); + } + while ((p = alloc_page(GFP_ATOMIC))) { + clobber(p, PAGE_SIZE); + list_add(&p->list, &xx); + printkdot(); + } + while (!list_empty(&x)) { + p = list_entry(x.next, struct page, list); + clobber(p, PAGE_SIZE*2); + list_del(x.next); + __free_pages(p, 1); + printkdot(); + } + while (!list_empty(&xx)) { + p = list_entry(xx.next, struct page, list); + clobber(p, PAGE_SIZE); + list_del(xx.next); + __free_pages(p, 0); + printkdot(); + } + printk("I'm still alive duh!\n"); +} + +#undef printkdot +#undef clobber + +void __init mem_init(void) +{ + unsigned long codesize, reservedpages, datasize, initsize, pfn; + extern int page_is_ram(unsigned long) __init; + extern char _text, _etext, _data, _edata; + extern char __init_begin, __init_end; + extern unsigned long totalram_pages; + unsigned long nid, i; + mem_map_t * lmem_map; + + high_memory = (void *) __va(max_mapnr <node_start_paddr >> PAGE_SHIFT; + for (i = 0; i < PLAT_NODE_DATA_SIZE(nid); i++, pfn++) + if (page_is_ram(pfn) && PageReserved(lmem_map+i)) + reservedpages++; + } + + codesize = (unsigned long) &_etext - (unsigned long) &_text; + datasize = (unsigned long) &_edata - (unsigned long) &_data; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, " + "%luk data, %luk init)\n", + nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +#if 0 + mem_stress(); +#endif +} + +void +show_mem(void) +{ + long i,free = 0,total = 0,reserved = 0; + long shared = 0, cached = 0; + int nid; + + printk("\nMem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + for (nid = 0; nid < numnodes; nid++) { + mem_map_t * lmem_map = NODE_MEM_MAP(nid); + i = PLAT_NODE_DATA_SIZE(nid); + while (i-- > 0) { + total++; + if (PageReserved(lmem_map+i)) + reserved++; + else if (PageSwapCache(lmem_map+i)) + cached++; + else if (!page_count(lmem_map+i)) + free++; + else + shared += atomic_read(&lmem_map[i].count) - 1; + } + } + printk("%ld pages of RAM\n",total); + printk("%ld free pages\n",free); + printk("%ld reserved pages\n",reserved); + printk("%ld pages shared\n",shared); + printk("%ld pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); +} diff -u --recursive --new-file v2.4.4/linux/arch/arm/def-configs/clps7500 linux/arch/arm/def-configs/clps7500 --- v2.4.4/linux/arch/arm/def-configs/clps7500 Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/def-configs/clps7500 Sat May 19 17:43:05 2001 @@ -2,7 +2,9 @@ # 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 # @@ -23,6 +25,7 @@ CONFIG_ARCH_CLPS7500=y # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_FTVPCI is not set # CONFIG_ARCH_TBOX is not set # CONFIG_ARCH_SHARK is not set @@ -30,22 +33,51 @@ # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # 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=y -CONFIG_CPU_ARM7=y +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +CONFIG_CPU_ARM710=y +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set # CONFIG_DISCONTIGMEM is not set -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set # # General setup # +CONFIG_ANGELBOOT=y +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set CONFIG_NET=y @@ -60,7 +92,7 @@ # CONFIG_BINFMT_MISC is not set # CONFIG_PM is not set # CONFIG_ARTHUR is not set -CONFIG_CMDLINE="root=/dev/nfs rw" +CONFIG_CMDLINE="mem=16M root=nfs" # CONFIG_ALIGNMENT_TRAP is not set # @@ -81,34 +113,35 @@ # Memory Technology Devices (MTD) # CONFIG_MTD=y +# CONFIG_MTD_DEBUG 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 + +# +# RAM/ROM Device Drivers +# # CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set # CONFIG_MTD_MTDRAM is not set # -# MTD drivers for mapped chips +# Linearly Mapped Flash Device Drivers # # CONFIG_MTD_CFI is not set -# CONFIG_MTD_CFI_INTELEXT is not set -# CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set -# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_JEDEC is not set # # Drivers for chip mappings # -# CONFIG_MTD_MIXMEM is not set -# CONFIG_MTD_NORA is not set -# CONFIG_MTD_OCTAGON is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_VMAX is not set # # User modules and translation layers for MTD devices @@ -122,7 +155,6 @@ # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # Block devices @@ -130,20 +162,12 @@ # 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_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM 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_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_BLK_DEV_FLD7500=y +# CONFIG_BLK_DEV_FLD7500 is not set # # Networking options @@ -159,10 +183,8 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -179,6 +201,7 @@ # 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 @@ -201,6 +224,7 @@ CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -213,16 +237,19 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set +CONFIG_NET_PCI=y +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=y +# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set -# CONFIG_SK98LIN is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PLIP is not set @@ -283,10 +310,6 @@ # 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 @@ -294,6 +317,11 @@ # CONFIG_ISDN is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # CONFIG_VT=y @@ -305,7 +333,7 @@ CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=y -CONFIG_LP_CONSOLE=y +# CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set # @@ -322,16 +350,38 @@ # # Mice # -# CONFIG_BUSMOUSE is not set +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set CONFIG_MOUSE=y -CONFIG_PSMOUSE=y +# CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set # # Joysticks # -# CONFIG_JOYSTICK is not set + +# +# Game port support +# + +# +# Gameport joysticks +# + +# +# Serial port support +# + +# +# Serial port joysticks +# + +# +# Parallel port joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -341,11 +391,6 @@ CONFIG_CLPS7500_FLASH=y # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -353,45 +398,38 @@ # 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_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_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 is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # 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 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_SYSV_FS_WRITE 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 @@ -401,21 +439,10 @@ # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS 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_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -430,11 +457,14 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Console drivers # +CONFIG_PC_KEYB=y +CONFIG_PC_KEYMAP=y # CONFIG_VGA_CONSOLE is not set CONFIG_FB=y @@ -445,15 +475,14 @@ CONFIG_DUMMY_CONSOLE=y CONFIG_FB_ACORN=y # CONFIG_CHRONTEL_7003 is not set -# 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_MFB=y +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y CONFIG_FBCON_CFB8=y -# CONFIG_FBCON_CFB16 is not set -# CONFIG_FBCON_CFB24 is not set +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y # CONFIG_FBCON_CFB32 is not set # CONFIG_FBCON_AFB is not set # CONFIG_FBCON_ILBM is not set @@ -487,4 +516,4 @@ # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -u --recursive --new-file v2.4.4/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110 --- v2.4.4/linux/arch/arm/def-configs/ebsa110 Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/def-configs/ebsa110 Wed May 16 10:31:27 2001 @@ -192,8 +192,6 @@ CONFIG_IP_NF_NAT_NEEDED=y # CONFIG_IP_NF_COMPAT_IPFWADM is not set CONFIG_IPV6=m -CONFIG_IPV6_EUI64=y -# CONFIG_IPV6_NO_PB is not set # # IPv6: Netfilter Configuration diff -u --recursive --new-file v2.4.4/linux/arch/arm/def-configs/integrator linux/arch/arm/def-configs/integrator --- v2.4.4/linux/arch/arm/def-configs/integrator Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/def-configs/integrator Sat May 19 17:43:05 2001 @@ -25,6 +25,7 @@ # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_FOOTBRIDGE is not set CONFIG_ARCH_INTEGRATOR=y # CONFIG_ARCH_RPC is not set @@ -56,18 +57,28 @@ # # Processor Type # +# CONFIG_CPU_32v3 is not set CONFIG_CPU_32v4=y -CONFIG_CPU_ARM720=y -CONFIG_CPU_ARM920=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +CONFIG_CPU_ARM720T=y +CONFIG_CPU_ARM920T=y CONFIG_CPU_ARM920_CPU_IDLE=y CONFIG_CPU_ARM920_I_CACHE_ON=y CONFIG_CPU_ARM920_D_CACHE_ON=y # CONFIG_CPU_ARM920_WRITETHROUGH is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set # CONFIG_DISCONTIGMEM is not set # # General setup # + +# +# Please ensure that you have read the help on the next option +# # CONFIG_ANGELBOOT is not set CONFIG_PCI_INTEGRATOR=y CONFIG_PCI=y @@ -103,23 +114,32 @@ # Memory Technology Devices (MTD) # CONFIG_MTD=y +# CONFIG_MTD_DEBUG 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 + +# +# RAM/ROM Device Drivers +# # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_MTDRAM is not set # -# MTD drivers for mapped chips +# Linearly Mapped Flash Device Drivers # CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set +# CONFIG_MTD_JEDEC is not set # CONFIG_MTD_PHYSMAP is not set # @@ -347,6 +367,8 @@ CONFIG_SERIAL_AMBA=y CONFIG_SERIAL_INTEGRATOR=y CONFIG_SERIAL_AMBA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 @@ -403,6 +425,8 @@ # 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_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -457,8 +481,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -475,6 +497,7 @@ # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # @@ -503,7 +526,7 @@ # # Kernel hacking # -CONFIG_FRAME_POINTER=y +# CONFIG_NO_FRAME_POINTER is not set CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -u --recursive --new-file v2.4.4/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.4.4/linux/arch/arm/defconfig Mon Jun 19 17:59:33 2000 +++ linux/arch/arm/defconfig Sat May 19 17:43:05 2001 @@ -2,50 +2,80 @@ # 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 # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and processor type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -CONFIG_FOOTBRIDGE=y -CONFIG_HOST_FOOTBRIDGE=y -# CONFIG_ADDIN_FOOTBRIDGE is not set -CONFIG_ARCH_EBSA285=y -# CONFIG_ARCH_CATS is not set -CONFIG_ARCH_NETWINDER=y -# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_INTEGRATOR=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # 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_32v4=y -CONFIG_CPU_SA110=y -CONFIG_PCI=y -CONFIG_PCI_NAMES=y -CONFIG_ISA=y -CONFIG_ISA_DMA=y -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -# CONFIG_ALIGNMENT_TRAP is not set # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ARM720=y +CONFIG_CPU_ARM920=y +CONFIG_CPU_ARM920_CPU_IDLE=y +CONFIG_CPU_ARM920_I_CACHE_ON=y +CONFIG_CPU_ARM920_D_CACHE_ON=y +# CONFIG_CPU_ARM920_WRITETHROUGH is not set +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_ANGELBOOT is not set +CONFIG_PCI_INTEGRATOR=y +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -56,296 +86,86 @@ 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_CMDLINE="root=1f04 mem=32M" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support # -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=y -CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_ARC is not set -# CONFIG_PARPORT_AMIGA is not set -# CONFIG_PARPORT_MFC3 is not set -# CONFIG_PARPORT_ATARI is not set -# CONFIG_PARPORT_SUNBPP is not set -# CONFIG_PARPORT_OTHER is not set -CONFIG_PARPORT_1284=y -CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" -CONFIG_LEDS=y -CONFIG_LEDS_TIMER=y -# CONFIG_LEDS_CPU is not set +# CONFIG_PARPORT is not set # -# IEEE 1394 (FireWire) support +# Memory Technology Devices (MTD) # -# CONFIG_IEEE1394 is not set +CONFIG_MTD=y +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set # -# I2O device support +# MTD drivers for mapped chips # -# CONFIG_I2O is not set -# CONFIG_I2O_PCI 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 +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_PHYSMAP is not set + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +CONFIG_MTD_ARM=y # # Plug and Play configuration # -CONFIG_PNP=y -CONFIG_ISAPNP=y +# 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=m -CONFIG_PARIDE_PARPORT=y - -# -# Parallel IDE high-level drivers -# -CONFIG_PARIDE_PD=m -CONFIG_PARIDE_PCD=m -CONFIG_PARIDE_PF=m -CONFIG_PARIDE_PT=m -CONFIG_PARIDE_PG=m - -# -# Parallel IDE protocol modules -# -CONFIG_PARIDE_ATEN=m -CONFIG_PARIDE_BPCK=m -CONFIG_PARIDE_COMM=m -CONFIG_PARIDE_DSTR=m -CONFIG_PARIDE_FIT2=m -CONFIG_PARIDE_FIT3=m -CONFIG_PARIDE_EPAT=m -CONFIG_PARIDE_EPIA=m -CONFIG_PARIDE_FRIQ=m -CONFIG_PARIDE_FRPW=m -CONFIG_PARIDE_KBIC=m -CONFIG_PARIDE_KTTI=m -CONFIG_PARIDE_ON20=m -CONFIG_PARIDE_ON26=m +# 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=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m +# 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 is not set # -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_PRINTER=m -# 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 - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_WDT is not set -CONFIG_SOFT_WATCHDOG=y -# CONFIG_PCWATCHDOG is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_MIXCOMWD is not set -# CONFIG_21285_WATCHDOG is not set -CONFIG_977_WATCHDOG=m -CONFIG_DS1620=y -CONFIG_NWBUTTON=y -CONFIG_NWBUTTON_REBOOT=y -CONFIG_NWFLASH=m -# CONFIG_NVRAM is not set -CONFIG_RTC=y - -# -# Video For Linux -# -CONFIG_VIDEO_DEV=y -# CONFIG_I2C_PARPORT is not set - -# -# Radio Adapters -# -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_MIROPCM20 is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set - -# -# Video Adapters -# -# CONFIG_VIDEO_PMS is not set -# CONFIG_VIDEO_BWQCAM is not set -# CONFIG_VIDEO_CQCAM is not set -# CONFIG_VIDEO_SAA5249 is not set -# CONFIG_TUNER_3036 is not set -# CONFIG_VIDEO_STRADIS is not set -# CONFIG_VIDEO_ZORAN is not set -# CONFIG_VIDEO_BUZ is not set -# CONFIG_VIDEO_ZR36120 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_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set - -# -# USB support -# -CONFIG_USB=m - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -CONFIG_USB_OHCI=m - -# -# Miscellaneous USB options -# -CONFIG_USB_DEVICEFS=y - -# -# USB Devices -# -CONFIG_USB_PRINTER=m -# CONFIG_USB_SCANNER is not set -CONFIG_USB_AUDIO=m -CONFIG_USB_ACM=m -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_CPIA is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_USS720 is not set -# CONFIG_USB_DABUSB is not set -# CONFIG_USB_PLUSB is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_DSBR is not set - -# -# USB HID -# -# CONFIG_USB_HID is not set -CONFIG_USB_KBD=m -CONFIG_USB_MOUSE=m -# CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=m -CONFIG_INPUT_MOUSEDEV=m -CONFIG_INPUT_MOUSEDEV_MIX=y -# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_RIVA is not set -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set -CONFIG_FB_CYBER2000=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX 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=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -# 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=y -# CONFIG_FBCON_HGA is not set -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y - -# # Networking options # -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set +# CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -356,16 +176,10 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -376,10 +190,11 @@ # 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_BRIDGE 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 @@ -391,16 +206,6 @@ # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -412,68 +217,59 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -# CONFIG_ARM_AM79C961A is not set -CONFIG_NET_VENDOR_3COM=y -# CONFIG_EL1 is not set -# CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set -# CONFIG_EL3 is not set -# CONFIG_3C515 is not set -CONFIG_VORTEX=y +# CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set +CONFIG_TULIP=y # CONFIG_DE4X5 is not set -CONFIG_TULIP=m # CONFIG_DGRS is not set # CONFIG_DM9102 is not set -# CONFIG_EEPRO100 is not set +CONFIG_EEPRO100=y +CONFIG_EEPRO100_PM=y # CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set -CONFIG_NE2K_PCI=y -# CONFIG_RTL8129 is not set +# CONFIG_ES3210 is not set # CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC 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_ASYNC=m -# CONFIG_PPP_SYNC_TTY is not set -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_SLIP_MODE_SLIP6=y +# CONFIG_PPP is not set +# CONFIG_SLIP is not set # # Wireless LAN (non-hamradio) @@ -494,71 +290,21 @@ # CONFIG_WAN is not set # -# ATA/IDE/MFM/RLL support +# Amateur Radio support # -CONFIG_IDE=y +# CONFIG_HAMRADIO is not set # -# IDE, ATA and ATAPI Block devices +# IrDA (infrared) support # -CONFIG_BLK_DEV_IDE=y +# CONFIG_IRDA is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# ATA/IDE/MFM/RLL support # -# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_IDEDISK_MULTI_MODE=y -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# 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_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_OFFBOARD=y -CONFIG_IDEDMA_PCI_AUTO=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y -# CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD7409 is not set -# CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set -CONFIG_BLK_DEV_CY82C693=y -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_HPT34X_AUTODMA is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -CONFIG_BLK_DEV_PDC202XX=y -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set -# CONFIG_BLK_DEV_SIS5513 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -CONFIG_BLK_DEV_SL82C105=y -# CONFIG_IDE_CHIPSETS is not set -CONFIG_IDEDMA_AUTO=y -CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support @@ -566,72 +312,115 @@ # CONFIG_SCSI is not set # -# Sound +# IEEE 1394 (FireWire) support # -CONFIG_SOUND=m -# CONFIG_SOUND_CMPCI 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_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_OSS=m -# CONFIG_SOUND_TRACEINIT is not set -# 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_ACI_MIXER is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set -CONFIG_SOUND_SB=m -# CONFIG_SOUND_AWE32_SYNTH is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_UART6850 is not set -# CONFIG_SOUND_AEDSP16 is not set -# CONFIG_SOUND_VIDC is not set -CONFIG_SOUND_WAVEARTIST=m +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_AMBA=y +CONFIG_SERIAL_INTEGRATOR=y +CONFIG_SERIAL_AMBA_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# 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 + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# 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_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=y +# CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set -CONFIG_ADFS_FS=y +# 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_FAT_FS=m -CONFIG_MSDOS_FS=m +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=m +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set # CONFIG_MINIX_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 @@ -639,77 +428,77 @@ # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE 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_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y -CONFIG_NFSD=m +# CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS 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_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # CONFIG_PARTITION_ADVANCED=y -CONFIG_ACORN_PARTITION=y -# CONFIG_ACORN_PARTITION_ICS is not set -CONFIG_ACORN_PARTITION_ADFS=y -# CONFIG_ACORN_PARTITION_POWERTEC is not set -# CONFIG_ACORN_PARTITION_RISCIX is not set +# CONFIG_ACORN_PARTITION is not set # CONFIG_OSF_PARTITION is not set # CONFIG_AMIGA_PARTITION is not set # CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set -CONFIG_NLS=y +# CONFIG_NLS is not set # -# Native Language Support +# Console drivers +# +CONFIG_KMI_KEYB=y +CONFIG_PC_KEYMAP=y +CONFIG_VGA_CONSOLE=y +# CONFIG_FB is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support # -CONFIG_NLS_CODEPAGE_437=m -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_14 is not set -CONFIG_NLS_ISO8859_15=m -# CONFIG_NLS_KOI8_R is not set +# CONFIG_USB is not set # # Kernel hacking @@ -719,4 +508,4 @@ CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -u --recursive --new-file v2.4.4/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.4.4/linux/arch/arm/kernel/setup.c Fri Apr 27 14:10:31 2001 +++ linux/arch/arm/kernel/setup.c Wed May 16 15:25:16 2001 @@ -51,7 +51,6 @@ extern void paging_init(struct meminfo *, struct machine_desc *desc); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); -extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; diff -u --recursive --new-file v2.4.4/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.4/linux/arch/arm/lib/Makefile Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/lib/Makefile Wed May 16 15:25:16 2001 @@ -48,3 +48,7 @@ endif include $(TOPDIR)/Rules.make + +csumpartialcopy.o: csumpartialcopygeneric.S +csumpartialcopyuser.o: csumpartialcopygeneric.S + diff -u --recursive --new-file v2.4.4/linux/arch/arm/lib/csumpartial.S linux/arch/arm/lib/csumpartial.S --- v2.4.4/linux/arch/arm/lib/csumpartial.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/csumpartial.S Wed May 16 15:25:16 2001 @@ -12,57 +12,119 @@ .text -/* Function: __u32 csum_partial(const char *src, int len, __u32) +/* + * Function: __u32 csum_partial(const char *src, int len, __u32 sum) * Params : r0 = buffer, r1 = len, r2 = checksum * Returns : r0 = new checksum */ +buf .req r0 +len .req r1 +sum .req r2 +td0 .req r3 +td1 .req r4 @ save before use +td2 .req r5 @ save before use +td3 .req lr + +.zero: mov r0, sum + add sp, sp, #4 + ldr pc, [sp], #4 + + /* + * Handle 0 to 7 bytes, with any alignment of source and + * destination pointers. Note that when we get here, C = 0 + */ +.less8: teq len, #0 @ check for zero count + beq .zero + + /* we must have at least one byte. */ + tst buf, #1 @ odd address? + ldrneb td0, [buf], #1 + subne len, len, #1 + adcnes sum, sum, td0, lsl #8 + +.less4: tst len, #6 + beq .less8_byte + + /* we are now half-word aligned */ + +.less8_wordlp: +#ifdef __ARM_ARCH_4__ + ldrh td0, [buf], #2 + sub len, len, #2 +#else + ldrb td0, [buf], #1 + ldrb td3, [buf], #1 + sub len, len, #2 + orr td0, td0, td3, lsl #8 +#endif + adcs sum, sum, td0 + tst len, #6 + bne .less8_wordlp + +.less8_byte: tst len, #1 @ odd number of bytes + ldrneb td0, [buf], #1 @ include last byte + adcnes sum, sum, td0 @ update checksum + +.done: adc r0, sum, #0 @ collect up the last carry + ldr td0, [sp], #4 + tst td0, #1 @ check buffer alignment + movne td0, r0, lsl #8 @ rotate checksum by 8 bits + orrne r0, td0, r0, lsr #24 + ldr pc, [sp], #4 @ return + +.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 + + tst buf, #2 @ 32-bit aligned? +#ifdef __ARM_ARCH_4__ + ldrneh td0, [buf], #2 @ make 32-bit aligned + subne len, len, #2 +#else + ldrneb td0, [buf], #1 + ldrneb ip, [buf], #1 + subne len, len, #2 + orrne td0, td0, ip, lsl #8 +#endif + adcnes sum, sum, td0 @ update checksum + mov pc, lr + ENTRY(csum_partial) - tst r0, #2 - beq 1f - subs r1, r1, #2 - addmi r1, r1, #2 - bmi 3f - bic r0, r0, #3 - ldr r3, [r0], #4 - adds r2, r2, r3, lsr #16 - adcs r2, r2, #0 -1: adds r2, r2, #0 - bics ip, r1, #31 + stmfd sp!, {buf, lr} + cmp len, #8 @ Ensure that we have at least + blo .less8 @ 8 bytes to copy. + + adds sum, sum, #0 @ C = 0 + tst buf, #3 @ Test destination alignment + blne .not_aligned @ aligh destination, return here + +1: bics ip, len, #31 beq 3f - stmfd sp!, {r4 - r6} -2: ldmia r0!, {r3 - r6} - adcs r2, r2, r3 - adcs r2, r2, r4 - adcs r2, r2, r5 - adcs r2, r2, r6 - ldmia r0!, {r3 - r6} - adcs r2, r2, r3 - adcs r2, r2, r4 - adcs r2, r2, r5 - adcs r2, r2, r6 + + stmfd sp!, {r4 - r5} +2: ldmia buf!, {td0, td1, td2, td3} + adcs sum, sum, td0 + adcs sum, sum, td1 + adcs sum, sum, td2 + adcs sum, sum, td3 + ldmia buf!, {td0, td1, td2, td3} + adcs sum, sum, td0 + adcs sum, sum, td1 + adcs sum, sum, td2 + adcs sum, sum, td3 sub ip, ip, #32 teq ip, #0 bne 2b - adcs r2, r2, #0 - ldmfd sp!, {r4 - r6} -3: ands ip, r1, #0x1c - beq 5f -4: ldr r3, [r0], #4 - sub ip, ip, #4 - adcs r2, r2, r3 - teq ip, #0 - bne 4b - adcs r2, r2, #0 -5: ands ip, r1, #3 - moveq r0, r2 - RETINSTR(moveq,pc,lr) - mov ip, ip, lsl #3 - ldr r3, [r0] - rsb ip, ip, #32 - mov r3, r3, lsl ip - adds r2, r2, r3, lsr ip - adc r0, r2, #0 - RETINSTR(mov,pc,lr) + ldmfd sp!, {r4 - r5} +3: tst len, #0x1c @ should not change C + beq .less4 +4: ldr td0, [buf], #4 + sub len, len, #4 + adcs sum, sum, td0 + tst len, #0x1c + bne 4b + b .less4 diff -u --recursive --new-file v2.4.4/linux/arch/arm/lib/csumpartialcopy.S linux/arch/arm/lib/csumpartialcopy.S --- v2.4.4/linux/arch/arm/lib/csumpartialcopy.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/csumpartialcopy.S Wed May 16 15:25:16 2001 @@ -18,11 +18,11 @@ */ .macro save_regs - stmfd sp!, {r4 - r8, fp, ip, lr, pc} + stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} .endm .macro load_regs,flags - LOADREGS(\flags,fp,{r4 - r8, fp, sp, pc}) + LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc}) .endm .macro load1b, reg1 @@ -47,250 +47,6 @@ ldmia r0!, {\reg1, \reg2, \reg3, \reg4} .endm -ENTRY(csum_partial_copy_nocheck) - mov ip, sp - save_regs - sub fp, ip, #4 - cmp r2, #4 - blt .too_small - tst r1, #2 @ Test destination alignment - beq .dst_aligned - load2b ip, r8 - subs r2, r2, #2 @ We do not know if SRC is aligned... - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - adcs r3, r3, #0 - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strb ip, [r1], #1 @ Destination now aligned -.dst_aligned: tst r0, #3 - bne .src_not_aligned - adds r3, r3, #0 - bics ip, r2, #15 @ Routine for src & dst aligned - beq 2f -1: load4l r4, r5, r6, r7 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r4, r5 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - tst ip, #4 - beq 4f -3: load1l r4 - str r4, [r1], #4 - adcs r3, r3, r4 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - load1l r4 - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 -.exit: tst r2, #1 - strneb r4, [r1], #1 - andne r4, r4, #255 - adcnes r3, r3, r4 - adcs r0, r3, #0 - load_regs ea +#define FN_ENTRY ENTRY(csum_partial_copy_nocheck) -.too_small: teq r2, #0 - load_regs eqea - cmp r2, #2 - blt .too_small1 - load2b ip, r8 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - strb ip, [r1], #1 - strb r8, [r1], #1 - tst r2, #1 -.too_small1: @ C = 0 - beq .csum_exit - load1b ip - strb ip, [r1], #1 - adcs r3, r3, ip -.csum_exit: adc r0, r3, #0 - load_regs ea - -.src_not_aligned: - cmp r2, #4 - blt .too_small - and ip, r0, #3 - bic r0, r0, #3 - load1l r4 - cmp ip, #2 - beq .src2_aligned - bhi .src3_aligned - mov r4, r4, lsr #8 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #8 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #8 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #24 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #8 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - b .exit - -.src2_aligned: mov r4, r4, lsr #16 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #16 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #16 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #16 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #16 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - tst r2, #1 - adceq r0, r3, #0 - load_regs eqea - load1b r4 - b .exit - -.src3_aligned: mov r4, r4, lsr #24 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #24 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #24 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #8 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #24 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - load1l r4 - strb r4, [r1], #1 - adcs r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - b .exit +#include "csumpartialcopygeneric.S" diff -u --recursive --new-file v2.4.4/linux/arch/arm/lib/csumpartialcopygeneric.S linux/arch/arm/lib/csumpartialcopygeneric.S --- v2.4.4/linux/arch/arm/lib/csumpartialcopygeneric.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/csumpartialcopygeneric.S Wed May 16 15:25:16 2001 @@ -0,0 +1,327 @@ +/* + * linux/arch/arm/lib/csumpartialcopygeneric.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. + */ + +/* + * unsigned int + * csum_partial_copy_xxx(const char *src, char *dst, int len, int sum, ) + * r0 = src, r1 = dst, r2 = len, r3 = sum + * Returns : r0 = checksum + * + * Note that 'tst' and 'teq' preserve the carry flag. + */ + +src .req r0 +dst .req r1 +len .req r2 +sum .req r3 + +.zero: mov r0, sum + load_regs ea + + /* + * Align an unaligned destination pointer. We know that + * we have >= 8 bytes here, so we don't need to check + * the length. Note that the source pointer hasn't been + * aligned yet. + */ +.dst_unaligned: tst dst, #1 + beq .dst_16bit + + load1b ip + sub len, len, #1 + adcs sum, sum, ip, lsl #8 @ 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 + strb r8, [dst], #1 + adcs sum, sum, ip, lsl #8 + strb ip, [dst], #1 + mov pc, lr @ dst is now 32bit aligned + + /* + * Handle 0 to 7 bytes, with any alignment of source and + * destination pointers. Note that when we get here, C = 0 + */ +.less8: teq len, #0 @ check for zero count + beq .zero + + /* we must have at least one byte. */ + tst dst, #1 @ dst 16-bit aligned + beq .less8_aligned + + /* Align dst */ + load1b ip + sub len, len, #1 + adcs sum, sum, ip, lsl #8 @ update checksum + strb ip, [dst], #1 + tst len, #6 + beq .less8_byteonly + +1: load2b r8, ip + sub len, len, #2 + adcs sum, sum, r8 + strb r8, [dst], #1 + adcs sum, sum, ip, lsl #8 + strb ip, [dst], #1 +.less8_aligned: tst len, #6 + bne 1b +.less8_byteonly: + tst len, #1 + beq .done + load1b r8 + adcs sum, sum, r8 @ update checksum + strb r8, [dst], #1 + b .done + +FN_ENTRY + mov ip, sp + save_regs + sub fp, ip, #4 + + cmp len, #8 @ Ensure that we have at least + blo .less8 @ 8 bytes to copy. + + adds sum, sum, #0 @ C = 0 + tst dst, #3 @ Test destination alignment + blne .dst_unaligned @ align destination, return here + + /* + * Ok, the dst pointer is now 32bit aligned, and we know + * that we must have more than 4 bytes to copy. Note + * that C contains the carry from the dst alignment above. + */ + + tst src, #3 @ Test source alignment + bne .src_not_aligned + + /* Routine for src & dst aligned */ + + bics ip, len, #15 + beq 2f + +1: load4l r4, r5, r6, r7 + stmia dst!, {r4, r5, r6, r7} + adcs sum, sum, r4 + adcs sum, sum, r5 + adcs sum, sum, r6 + adcs sum, sum, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b + +2: ands ip, len, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r4, r5 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + tst ip, #4 + beq 4f + +3: load1l r4 + str r4, [dst], #4 + adcs sum, sum, r4 + +4: ands len, len, #3 + beq .done + load1l r4 + tst len, #2 + beq .exit + adcs sum, sum, r4, lsl #16 + strb r4, [dst], #1 + mov r4, r4, lsr #8 + strb r4, [dst], #1 + mov r4, r4, lsr #8 +.exit: tst len, #1 + strneb r4, [dst], #1 + andne r4, r4, #255 + adcnes sum, sum, r4 + + /* + * If the dst pointer was not 16-bit aligned, we + * need to rotate the checksum here to get around + * the inefficient byte manipulations in the + * architecture independent code. + */ +.done: adc r0, sum, #0 + ldr sum, [sp, #0] @ dst + tst sum, #1 + movne sum, r0, lsl #8 + orrne r0, sum, r0, lsr #24 + load_regs ea + +.src_not_aligned: + adc sum, sum, #0 @ include C from dst alignment + and ip, src, #3 + bic src, src, #3 + load1l r4 + cmp ip, #2 + beq .src2_aligned + bhi .src3_aligned + mov r4, r4, lsr #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 + 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 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + 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 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, lsr #8 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #24 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, lsr #8 +4: ands len, len, #3 + beq .done + tst len, #2 + beq .exit + adcs sum, sum, r4, lsl #16 + strb r4, [dst], #1 + mov r4, r4, lsr #8 + strb r4, [dst], #1 + mov r4, r4, lsr #8 + b .exit + +.src2_aligned: mov r4, r4, lsr #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 + 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 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + 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 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, lsr #16 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #16 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, lsr #16 +4: ands len, len, #3 + beq .done + tst len, #2 + beq .exit + adcs sum, sum, r4, lsl #16 + strb r4, [dst], #1 + mov r4, r4, lsr #8 + strb r4, [dst], #1 + tst len, #1 + beq .done + load1b r4 + b .exit + +.src3_aligned: mov r4, r4, lsr #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 + 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 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + 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 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, lsr #24 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #8 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, lsr #24 +4: ands len, len, #3 + beq .done + tst len, #2 + beq .exit + adcs sum, sum, r4, lsl #16 + strb r4, [dst], #1 + load1l r4 + strb r4, [dst], #1 + adcs sum, sum, r4, lsl #24 + mov r4, r4, lsr #8 + b .exit diff -u --recursive --new-file v2.4.4/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S --- v2.4.4/linux/arch/arm/lib/csumpartialcopyuser.S Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/lib/csumpartialcopyuser.S Wed May 16 15:25:16 2001 @@ -15,10 +15,6 @@ .text -/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr) - * Params : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err - * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT - */ #if defined(CONFIG_CPU_32) .macro save_regs @@ -152,253 +148,16 @@ #error Unknown CPU architecture #endif -ENTRY(csum_partial_copy_from_user) - mov ip, sp - save_regs - sub fp, ip, #4 - cmp r2, #4 - blt .too_small - tst r1, #2 @ Test destination alignment - beq .dst_aligned - load2b ip, r8 - subs r2, r2, #2 @ We do not know if SRC is aligned... - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - adcs r3, r3, #0 - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strb ip, [r1], #1 @ Destination now aligned -.dst_aligned: tst r0, #3 - bne .src_not_aligned - adds r3, r3, #0 - bics ip, r2, #15 @ Routine for src & dst aligned - beq 2f -1: load4l r4, r5, r6, r7 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r4, r5 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - tst ip, #4 - beq 4f -3: load1l r4 - str r4, [r1], #4 - adcs r3, r3, r4 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - load1l r4 - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 -.exit: tst r2, #1 - strneb r4, [r1], #1 - andne r4, r4, #255 - adcnes r3, r3, r4 - adcs r0, r3, #0 - load_regs ea - -.too_small: teq r2, #0 - load_regs eqea - cmp r2, #2 - blt .too_small1 - load2b ip, r8 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - strb ip, [r1], #1 - strb r8, [r1], #1 - tst r2, #1 -.too_small1: @ C = 0 - beq .csum_exit - load1b ip - strb ip, [r1], #1 - adcs r3, r3, ip -.csum_exit: adc r0, r3, #0 - load_regs ea - -.src_not_aligned: - cmp r2, #4 - blt .too_small - and ip, r0, #3 - bic r0, r0, #3 - load1l r4 - cmp ip, #2 - beq .src2_aligned - bhi .src3_aligned - mov r4, r4, lsr #8 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #8 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #8 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #24 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #8 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - b .exit - -.src2_aligned: mov r4, r4, lsr #16 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #16 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #16 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #16 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #16 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - tst r2, #1 - adceq r0, r3, #0 - load_regs eqea - load1b r4 - b .exit - -.src3_aligned: mov r4, r4, lsr #24 - adds r3, r3, #0 - bics ip, r2, #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 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #24 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - 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 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #24 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #8 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #24 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - load1l r4 - strb r4, [r1], #1 - adcs r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - b .exit +/* + * unsigned int + * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr) + * r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr + * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT + */ + +#define FN_ENTRY ENTRY(csum_partial_copy_from_user) + +#include "csumpartialcopygeneric.S" /* * FIXME: minor buglet here @@ -411,13 +170,13 @@ #endif .align 4 6001: mov r4, #-EFAULT - ldr r5, [fp, #4] + ldr r5, [fp, #4] @ *err_ptr str r4, [r5] - ldmia sp, {r1, r2} @ retrieve original arguments + ldmia sp, {r1, r2} @ retrieve dst, len add r2, r2, r1 - mov r3, #0 @ zero the buffer + mov r0, #0 @ zero the buffer 6002: teq r2, r1 - strneb r3, [r1], #1 + strneb r0, [r1], #1 bne 6002b load_regs ea #if defined(CONFIG_CPU_32) diff -u --recursive --new-file v2.4.4/linux/arch/arm/mach-ebsa110/io.c linux/arch/arm/mach-ebsa110/io.c --- v2.4.4/linux/arch/arm/mach-ebsa110/io.c Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/mach-ebsa110/io.c Sun May 20 12:11:38 2001 @@ -20,7 +20,6 @@ * Luckily, the work-around for this is not too horrible. See * __isamem_convert_addr for the details. */ -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/arm/mach-sa1100/dma.h linux/arch/arm/mach-sa1100/dma.h --- v2.4.4/linux/arch/arm/mach-sa1100/dma.h Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/mach-sa1100/dma.h Sun May 20 12:11:38 2001 @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include /* * DMA channel structure. diff -u --recursive --new-file v2.4.4/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.4.4/linux/arch/arm/mm/fault-armv.c Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/mm/fault-armv.c Wed May 16 15:25:16 2001 @@ -132,7 +132,7 @@ #define get8_unaligned_check(val,addr,err) \ __asm__( \ - "1: ldrb %1, [%2]\n" \ + "1: ldrb %1, [%2], #1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -148,7 +148,7 @@ #define get8t_unaligned_check(val,addr,err) \ __asm__( \ - "1: ldrbt %1, [%2]\n" \ + "1: ldrbt %1, [%2], #1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ diff -u --recursive --new-file v2.4.4/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.4.4/linux/arch/arm/vmlinux-armv.lds.in Tue Mar 6 19:44:35 2001 +++ linux/arch/arm/vmlinux-armv.lds.in Wed May 16 15:25:16 2001 @@ -44,11 +44,12 @@ *(.rodata) *(.glue_7) *(.glue_7t) - *(.kstrtab) *(.got) /* Global offset table */ _etext = .; /* End of text section */ } + + .kstrtab : { *(.kstrtab) } . = ALIGN(16); __ex_table : { /* Exception table */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.4/linux/arch/cris/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/Makefile Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $ +# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -25,8 +25,8 @@ # regenerating stuff (even for incremental linking of subsystems!) is # even more nauseating. LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \ - sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \ - -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ + sed -e s/@CONFIG_ETRAX_DRAM_VIRTUAL_BASE@/0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)/ \ + -e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ else true; \ fi && $(CROSS_COMPILE)ld -mcriself @@ -42,7 +42,7 @@ CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__ -ifdef CONFIG_KGDB +ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif @@ -76,7 +76,7 @@ cramfs: ## cramfs - Creates a cramfs image - mkcramfs -b 8192 root cramfs.img + mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img cat vmlinux.bin cramfs.img >timage clinux: vmlinux.bin decompress.bin rescue.bin diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile --- v2.4.4/linux/arch/cris/boot/compressed/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/Makefile Tue May 1 16:04:56 2001 @@ -24,7 +24,7 @@ vmlinuz: piggy.img decompress.bin - cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz + cat decompress.bin piggy.img > vmlinuz rm -f piggy.img head.o: head.S diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S --- v2.4.4/linux/arch/cris/boot/compressed/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/head.S Tue May 1 16:04:56 2001 @@ -1,16 +1,19 @@ /* - * arch/etrax100/boot/compressed/head.S + * arch/cris/boot/compressed/head.S * - * Copyright (C) 1999 Axis Communications AB + * Copyright (C) 1999, 2001 Axis Communications AB * * Code that sets up the DRAM registers, calls the * decompressor to unpack the piggybacked kernel, and jumps. * */ +#include #define ASSEMBLER_MACROS_ONLY #include +#define RAM_INIT_MAGIC 0x56902387 + ;; Exported symbols .globl _input_data @@ -21,23 +24,28 @@ nop di - ;; We need to initialze DRAM registers before we start using the DRAM -#include "../../lib/dram_init.S" +;; We need to initialze DRAM registers before we start using the DRAM -dram_init_finished: + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../../lib/dram_init.S" +dram_init_finished: + ;; Initiate the PA and PB ports - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] ;; Setup the stack to a suitably high address. @@ -70,6 +78,7 @@ move.d r5, [_input_data] ; for the decompressor + ;; Clear the decompressors BSS (between _edata and _end) moveq 0, r0 @@ -81,19 +90,22 @@ nop ;; Do the decompression and save compressed size in _inptr - + jsr _decompress_kernel - ;; Put start address of cramfs in r9 so the kernel can use it + ;; Put start address of root partition in r9 so the kernel can use it ;; when mounting from flash move.d [_input_data], r9 ; flash address of compressed kernel add.d [_inptr], r9 ; size of compressed kernel - + ;; Enter the decompressed kernel + move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized jump 0x40004000 ; kernel is linked to this address .data _input_data: .dword 0 ; used by the decompressor + +#include "../../lib/hw_settings.S" diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c --- v2.4.4/linux/arch/cris/boot/compressed/misc.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/misc.c Tue May 1 16:04:56 2001 @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $ + * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $ * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. @@ -21,6 +21,7 @@ #define KERNEL_LOAD_ADR 0x40004000 #include + #include #include @@ -143,21 +144,21 @@ static void puts(const char *s) { -#ifndef CONFIG_DEBUG_PORT_NULL +#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL while(*s) { -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 while(!(*R_SERIAL0_STATUS & (1 << 5))) ; *R_SERIAL0_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 while(!(*R_SERIAL1_STATUS & (1 << 5))) ; *R_SERIAL1_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 while(!(*R_SERIAL2_STATUS & (1 << 5))) ; *R_SERIAL2_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 while(!(*R_SERIAL3_STATUS & (1 << 5))) ; *R_SERIAL3_TR_DATA = *s++; #endif @@ -227,33 +228,45 @@ void decompress_kernel() { + char revision; + /* input_data is set in head.S */ inbuf = input_data; -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 *R_SERIAL0_XOFF = 0; *R_SERIAL0_BAUD = 0x99; *R_SERIAL0_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 *R_SERIAL1_XOFF = 0; *R_SERIAL1_BAUD = 0x99; *R_SERIAL1_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 + *R_GEN_CONFIG = 0x08; *R_SERIAL2_XOFF = 0; *R_SERIAL2_BAUD = 0x99; *R_SERIAL2_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 + *R_GEN_CONFIG = 0x100; *R_SERIAL3_XOFF = 0; *R_SERIAL3_BAUD = 0x99; *R_SERIAL3_TR_CTRL = 0x40; #endif - + setup_normal_output_buffer(); makecrc(); + + __asm__ volatile ("move vr,%0" : "=rm" (revision)); + if (revision < 10) + { + puts("You need an ETRAX 100LX to run linux 2.4\n"); + while(1); + } + puts("Uncompressing Linux...\n"); gunzip(); puts("Done. Now booting the kernel.\n"); diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S --- v2.4.4/linux/arch/cris/boot/rescue/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/head.S Tue May 1 16:04:56 2001 @@ -1,66 +1,67 @@ - ;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv Exp $ - ;; - ;; Rescue code, made to reside at the beginning of the - ;; flash-memory. when it starts, it checks a partition - ;; table at the first sector after the rescue sector. - ;; the partition table was generated by the product builder - ;; script and contains offsets, lengths, types and checksums - ;; for each partition that this code should check. - ;; - ;; If any of the checksums fail, we assume the flash is so - ;; corrupt that we cant use it to boot into the ftp flash - ;; loader, and instead we initialize the serial port to - ;; receive a flash-loader and new flash image. we dont include - ;; any flash code here, but just accept a certain amount of - ;; bytes from the serial port and jump into it. the downloaded - ;; code is put in the cache. - ;; - ;; The partitiontable is designed so that it is transparent to - ;; code execution - it has a relative branch opcode in the - ;; beginning that jumps over it. each entry contains extra - ;; data so we can add stuff later. - ;; - ;; Partition table format: - ;; - ;; Code transparency: - ;; - ;; 2 bytes [opcode 'nop'] - ;; 2 bytes [opcode 'di'] - ;; 4 bytes [opcode 'ba ', 8-bit or 16-bit version] - ;; 2 bytes [opcode 'nop', delay slot] - ;; - ;; Table validation (at +10): - ;; - ;; 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] - ;; 2 bytes [length of all entries plus the end marker] - ;; 4 bytes [checksum for the partitiontable itself] - ;; - ;; Entries, each with the following format, last has offset -1: - ;; - ;; 4 bytes [offset in bytes, from start of flash] - ;; 4 bytes [length in bytes of partition] - ;; 4 bytes [checksum, simple longword sum] - ;; 2 bytes [partition type] - ;; 2 bytes [flags, only bit 0 used, ro/rw = 1/0] - ;; 16 bytes [reserved for future use] - ;; - ;; End marker - ;; - ;; 4 bytes [-1] - ;; - ;; 10 bytes [0, padding] - ;; - ;; Bit 0 in flags signifies RW or RO. The rescue code only bothers - ;; to check the checksum for RO partitions, since the others will - ;; change its data without updating the checksums. A 1 in bit 0 - ;; means RO, 0 means RW. That way, it is possible to set a partition - ;; in RO mode initially, and later mark it as RW, since you can always - ;; write 0's to the flash. - ;; - ;; During the wait for serial input, the status LED will flash so the - ;; user knows something went wrong. - ;; - ;; Copyright (C) 1999 Axis Communications AB +/* $Id: head.S,v 1.7 2001/04/18 12:05:07 bjornw Exp $ + * + * Rescue code, made to reside at the beginning of the + * flash-memory. when it starts, it checks a partition + * table at the first sector after the rescue sector. + * the partition table was generated by the product builder + * script and contains offsets, lengths, types and checksums + * for each partition that this code should check. + * + * If any of the checksums fail, we assume the flash is so + * corrupt that we cant use it to boot into the ftp flash + * loader, and instead we initialize the serial port to + * receive a flash-loader and new flash image. we dont include + * any flash code here, but just accept a certain amount of + * bytes from the serial port and jump into it. the downloaded + * code is put in the cache. + * + * The partitiontable is designed so that it is transparent to + * code execution - it has a relative branch opcode in the + * beginning that jumps over it. each entry contains extra + * data so we can add stuff later. + * + * Partition table format: + * + * Code transparency: + * + * 2 bytes [opcode 'nop'] + * 2 bytes [opcode 'di'] + * 4 bytes [opcode 'ba ', 8-bit or 16-bit version] + * 2 bytes [opcode 'nop', delay slot] + * + * Table validation (at +10): + * + * 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] + * 2 bytes [length of all entries plus the end marker] + * 4 bytes [checksum for the partitiontable itself] + * + * Entries, each with the following format, last has offset -1: + * + * 4 bytes [offset in bytes, from start of flash] + * 4 bytes [length in bytes of partition] + * 4 bytes [checksum, simple longword sum] + * 2 bytes [partition type] + * 2 bytes [flags, only bit 0 used, ro/rw = 1/0] + * 16 bytes [reserved for future use] + * + * End marker + * + * 4 bytes [-1] + * + * 10 bytes [0, padding] + * + * Bit 0 in flags signifies RW or RO. The rescue code only bothers + * to check the checksum for RO partitions, since the others will + * change its data without updating the checksums. A 1 in bit 0 + * means RO, 0 means RW. That way, it is possible to set a partition + * in RO mode initially, and later mark it as RW, since you can always + * write 0's to the flash. + * + * During the wait for serial input, the status LED will flash so the + * user knows something went wrong. + * + * Copyright (C) 1999,2001 Axis Communications AB + */ #include #define ASSEMBLER_MACROS_ONLY @@ -69,7 +70,7 @@ ;; The partitiontable is looked for at the first sector after the boot ;; sector. Sector size is 65536 bytes in all flashes we use. -#define PTABLE_START 0x10000 +#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR #define PTABLE_MAGIC 0xbeef ;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0. @@ -82,28 +83,28 @@ #define CODE_START 0x40000000 #define CODE_LENGTH 784 -#ifdef CONFIG_RESCUE_SER0 +#ifdef CONFIG_ETRAX_RESCUE_SER0 #define SERXOFF R_SERIAL0_XOFF #define SERBAUD R_SERIAL0_BAUD #define SERRECC R_SERIAL0_REC_CTRL #define SERRDAT R_SERIAL0_REC_DATA #define SERSTAT R_SERIAL0_STATUS #endif -#ifdef CONFIG_RESCUE_SER1 +#ifdef CONFIG_ETRAX_RESCUE_SER1 #define SERXOFF R_SERIAL1_XOFF #define SERBAUD R_SERIAL1_BAUD #define SERRECC R_SERIAL1_REC_CTRL #define SERRDAT R_SERIAL1_REC_DATA #define SERSTAT R_SERIAL1_STATUS #endif -#ifdef CONFIG_RESCUE_SER2 +#ifdef CONFIG_ETRAX_RESCUE_SER2 #define SERXOFF R_SERIAL2_XOFF #define SERBAUD R_SERIAL2_BAUD #define SERRECC R_SERIAL2_REC_CTRL #define SERRDAT R_SERIAL2_REC_DATA #define SERSTAT R_SERIAL2_STATUS #endif -#ifdef CONFIG_RESCUE_SER3 +#ifdef CONFIG_ETRAX_RESCUE_SER3 #define SERXOFF R_SERIAL3_XOFF #define SERBAUD R_SERIAL3_BAUD #define SERRECC R_SERIAL3_REC_CTRL @@ -112,7 +113,8 @@ #endif #define NOP_DI 0xf025050f - +#define RAM_INIT_MAGIC 0x56902387 + .text ;; This is the entry point of the rescue code @@ -221,14 +223,14 @@ ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] ;; setup the serial port at 115200 baud @@ -250,10 +252,10 @@ addq 1, r1 #ifndef CONFIG_ETRAX_NO_LEDS #ifdef CONFIG_ETRAX_PA_LEDS - move.b DEF_R_PORT_PA_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 #endif #ifdef CONFIG_ETRAX_PB_LEDS - move.b DEF_R_PORT_PB_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 #endif move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 btstq 16, r1 @@ -293,7 +295,8 @@ nop ;; jump into downloaded code - + + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized jump CODE_START flash_ok: @@ -303,7 +306,8 @@ bne 1f nop move.d PTABLE_START, r7; otherwise use the ptable start -1: +1: + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized jump r7 ; boot! diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S --- v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/kimagerescue.S Tue May 1 16:04:56 2001 @@ -1,41 +1,42 @@ - ;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv Exp $ - ;; - ;; Rescue code to be prepended on a kimage and copied to the - ;; rescue serial port. - ;; This is called from the rescue code, it will copy received data to - ;; 4000500 and after a timeout jump to it. - +/* $Id: kimagerescue.S,v 1.4 2001/04/18 12:04:46 bjornw Exp $ + * + * Rescue code to be prepended on a kimage and copied to the + * rescue serial port. + * This is called from the rescue code, it will copy received data to + * 4004000 and after a timeout jump to it. + */ + #include #define ASSEMBLER_MACROS_ONLY #include -#define CODE_START 0x40000500 +#define CODE_START 0x40004000 #define CODE_LENGTH 784 #define TIMEOUT_VALUE 1000 -#ifdef CONFIG_RESCUE_SER0 +#ifdef CONFIG_ETRAX_RESCUE_SER0 #define SERXOFF R_SERIAL0_XOFF #define SERBAUD R_SERIAL0_BAUD #define SERRECC R_SERIAL0_REC_CTRL #define SERRDAT R_SERIAL0_REC_DATA #define SERSTAT R_SERIAL0_STATUS #endif -#ifdef CONFIG_RESCUE_SER1 +#ifdef CONFIG_ETRAX_RESCUE_SER1 #define SERXOFF R_SERIAL1_XOFF #define SERBAUD R_SERIAL1_BAUD #define SERRECC R_SERIAL1_REC_CTRL #define SERRDAT R_SERIAL1_REC_DATA #define SERSTAT R_SERIAL1_STATUS #endif -#ifdef CONFIG_RESCUE_SER2 +#ifdef CONFIG_ETRAX_RESCUE_SER2 #define SERXOFF R_SERIAL2_XOFF #define SERBAUD R_SERIAL2_BAUD #define SERRECC R_SERIAL2_REC_CTRL #define SERRDAT R_SERIAL2_REC_DATA #define SERSTAT R_SERIAL2_STATUS #endif -#ifdef CONFIG_RESCUE_SER3 +#ifdef CONFIG_ETRAX_RESCUE_SER3 #define SERXOFF R_SERIAL3_XOFF #define SERBAUD R_SERIAL3_BAUD #define SERRECC R_SERIAL3_REC_CTRL @@ -55,14 +56,14 @@ ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] ;; We need to setup the bus registers before we start using the DRAM @@ -99,10 +100,10 @@ nop #ifndef CONFIG_ETRAX_NO_LEDS #ifdef CONFIG_ETRAX_PA_LEDS - move.b DEF_R_PORT_PA_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 #endif #ifdef CONFIG_ETRAX_PB_LEDS - move.b DEF_R_PORT_PB_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 #endif move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 btstq 16, r1 diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S --- v2.4.4/linux/arch/cris/boot/rescue/testrescue.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/testrescue.S Tue May 1 16:04:56 2001 @@ -1,9 +1,10 @@ - ;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana Exp $ - ;; - ;; Simple testcode to download by the rescue block. - ;; Just lits some LEDs to show it was downloaded correctly. - ;; - ;; Copyright (C) 1999 Axis Communications AB +/* $Id: testrescue.S,v 1.2 2001/04/18 12:05:07 bjornw Exp $ + * + * Simple testcode to download by the rescue block. + * Just lits some LEDs to show it was downloaded correctly. + * + * Copyright (C) 1999 Axis Communications AB + */ #define ASSEMBLER_MACROS_ONLY #include diff -u --recursive --new-file v2.4.4/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.4/linux/arch/cris/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/cris/config.in Tue May 1 16:04:56 2001 @@ -24,14 +24,10 @@ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi -bool 'Use kernel gdb debugger' CONFIG_KGDB +bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG -bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE - -bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG - endmenu mainmenu_option next_comment @@ -46,20 +42,19 @@ if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then define_bool CONFIG_CRIS_LOW_MAP y - define_hex ETRAX_DRAM_VIRTUAL_BASE 60000000 + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000 else - define_hex ETRAX_DRAM_VIRTUAL_BASE c0000000 + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE c0000000 fi -int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8 +int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8 -int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2 choice 'Product LED port' \ "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \ Port-PB-LEDs CONFIG_ETRAX_PB_LEDS \ - Mem-0x90000000-LEDs CONFIG_ETRAX_90000000_LEDS \ + Port-CSP0-LEDs CONFIG_ETRAX_CSP0_LEDS \ None CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then @@ -71,38 +66,54 @@ int ' Third red LED bit' CONFIG_ETRAX_LED3G 2 fi +if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then + int ' Fourth red LED bit' CONFIG_ETRAX_LED4R 2 + int ' Fourth green LED bit' CONFIG_ETRAX_LED4G 2 + int ' Fifth red LED bit' CONFIG_ETRAX_LED5R 2 + int ' Fifth green LED bit' CONFIG_ETRAX_LED5G 2 + int ' Sixth red LED bit' CONFIG_ETRAX_LED6R 2 + int ' Sixth green LED bit' CONFIG_ETRAX_LED6G 2 + int ' Seventh red LED bit' CONFIG_ETRAX_LED7R 2 + int ' Seventh green LED bit' CONFIG_ETRAX_LED7G 2 + int ' Eigth yellow LED bit' CONFIG_ETRAX_LED8Y 2 + int ' Ninth yellow LED bit' CONFIG_ETRAX_LED9Y 2 + int ' Tenth yellow LED bit' CONFIG_ETRAX_LED10Y 2 + int ' Eleventh yellow LED bit' CONFIG_ETRAX_LED11Y 2 + int ' Twelfth red LED bit' CONFIG_ETRAX_LED12R 2 +fi + choice 'Product debug-port' \ - "Serial-0 CONFIG_DEBUG_PORT0 \ - Serial-1 CONFIG_DEBUG_PORT1 \ - Serial-2 CONFIG_DEBUG_PORT2 \ - Serial-3 CONFIG_DEBUG_PORT3 \ - disabled CONFIG_DEBUG_PORT_NULL" Serial-0 + "Serial-0 CONFIG_ETRAX_DEBUG_PORT0 \ + Serial-1 CONFIG_ETRAX_DEBUG_PORT1 \ + Serial-2 CONFIG_ETRAX_DEBUG_PORT2 \ + Serial-3 CONFIG_ETRAX_DEBUG_PORT3 \ + disabled CONFIG_ETRAX_DEBUG_PORT_NULL" Serial-0 choice 'Product rescue-port' \ - "Serial-0 CONFIG_RESCUE_SER0 \ - Serial-1 CONFIG_RESCUE_SER1 \ - Serial-2 CONFIG_RESCUE_SER2 \ - Serial-3 CONFIG_RESCUE_SER3" Serial-0 - -hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6 -hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104 - -bool 'SDRAM support' CONFIG_SDRAM n -if [ "$CONFIG_SDRAM" = "n" ]; then - hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 - hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 + "Serial-0 CONFIG_ETRAX_RESCUE_SER0 \ + Serial-1 CONFIG_ETRAX_RESCUE_SER1 \ + Serial-2 CONFIG_ETRAX_RESCUE_SER2 \ + Serial-3 CONFIG_ETRAX_RESCUE_SER3" Serial-0 + +hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6 +hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104 + +bool 'SDRAM support' CONFIG_ETRAX_SDRAM n +if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then + hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040 + hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611 fi -if [ "$CONFIG_SDRAM" = "y" ]; then - hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878 - hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801 +if [ "$CONFIG_ETRAX_SDRAM" = "y" ]; then + hex 'R_SDRAM_CONFIG' CONFIG_ETRAX_DEF_R_SDRAM_CONFIG d2fa7878 + hex 'R_SDRAM_TIMING' CONFIG_ETRAX_DEF_R_SDRAM_TIMING 80004801 fi -hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c -hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00 -hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00 -hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00 -hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff +hex 'R_PORT_PA_DIR' CONFIG_ETRAX_DEF_R_PORT_PA_DIR 1c +hex 'R_PORT_PA_DATA' CONFIG_ETRAX_DEF_R_PORT_PA_DATA 00 +hex 'R_PORT_PB_CONFIG' CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG 00 +hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00 +hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff endmenu diff -u --recursive --new-file v2.4.4/linux/arch/cris/cris.ld linux/arch/cris/cris.ld --- v2.4.4/linux/arch/cris/cris.ld Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/cris.ld Tue May 1 16:04:56 2001 @@ -1,10 +1,16 @@ /* ld script to make the Linux/CRIS kernel * Authors: Bjorn Wesen (bjornw@axis.com) + * + * It is VERY DANGEROUS to fiddle around with the symbols in this + * script. It is for example quite vital that all generated sections + * that are used are actually named here, otherwise the linker will + * put them at the end, where the init stuff is which is FREED after + * the kernel has booted. */ SECTIONS { - . = @ETRAX_DRAM_VIRTUAL_BASE@; + . = @CONFIG_ETRAX_DRAM_VIRTUAL_BASE@; _dram_start = .; _ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -75,5 +81,5 @@ *(.exitcall.exit) } - _dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024; + _dram_end = _dram_start + @CONFIG_ETRAX_DRAM_SIZE_M@*1024*1024; } diff -u --recursive --new-file v2.4.4/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.4/linux/arch/cris/defconfig Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/defconfig Tue May 1 16:04:56 2001 @@ -15,10 +15,8 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_JAVA is not set -# CONFIG_KGDB is not set +# CONFIG_ETRAX_KGDB is not set # CONFIG_ETRAX_WATCHDOG is not set -CONFIG_USE_SERIAL_CONSOLE=y -# CONFIG_KERNEL_IFCONFIG is not set # # Hardware setup @@ -27,8 +25,8 @@ # CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set CONFIG_CRIS_LOW_MAP=y -ETRAX_DRAM_VIRTUAL_BASE=60000000 -ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 +CONFIG_ETRAX_DRAM_SIZE=8 CONFIG_ETRAX_FLASH_LENGTH=2 CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_PA_LEDS=y @@ -39,24 +37,24 @@ CONFIG_ETRAX_LED1R=2 CONFIG_ETRAX_LED2G=2 CONFIG_ETRAX_LED2R=2 -CONFIG_DEBUG_PORT0=y -# CONFIG_DEBUG_PORT1 is not set -# CONFIG_DEBUG_PORT2 is not set -# CONFIG_DEBUG_PORT3 is not set -CONFIG_RESCUE_SER0=y -# CONFIG_RESCUE_SER1 is not set -# CONFIG_RESCUE_SER2 is not set -# CONFIG_RESCUE_SER3 is not set -DEF_R_WAITSTATES=95a6 -DEF_R_BUS_CONFIG=104 -# CONFIG_SDRAM is not set -DEF_R_DRAM_CONFIG=1a200040 -DEF_R_DRAM_TIMING=5611 -DEF_R_PORT_PA_DIR=1d -DEF_R_PORT_PA_DATA=f0 -DEF_R_PORT_PB_CONFIG=00 -DEF_R_PORT_PB_DIR=1e -DEF_R_PORT_PB_DATA=f3 +CONFIG_ETRAX_DEBUG_PORT0=y +# CONFIG_ETRAX_DEBUG_PORT1 is not set +# CONFIG_ETRAX_DEBUG_PORT2 is not set +# CONFIG_ETRAX_DEBUG_PORT3 is not set +CONFIG_ETRAX_RESCUE_SER0=y +# CONFIG_ETRAX_RESCUE_SER1 is not set +# CONFIG_ETRAX_RESCUE_SER2 is not set +# CONFIG_ETRAX_RESCUE_SER3 is not set +CONFIG_ETRAX_DEF_R_WAITSTATES=95a6 +CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 +# CONFIG_ETRAX_SDRAM is not set +CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 +CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 +CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d +CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 +CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e +CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 # # Drivers for Etrax built-in interfaces @@ -69,7 +67,7 @@ # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set # CONFIG_ETRAX_SERIAL_PORT2 is not set # CONFIG_ETRAX_SERIAL_PORT3 is not set -# CONFIG_RS485 is not set +# CONFIG_ETRAX_RS485 is not set # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set # CONFIG_ETRAX_IDE is not set CONFIG_ETRAX_AXISFLASHMAP=y @@ -84,15 +82,10 @@ CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y CONFIG_ETRAX_GPIO=y CONFIG_ETRAX_PA_BUTTON_BITMASK=02 -CONFIG_PA_CHANGEABLE_DIR=00 -CONFIG_PA_CHANGEABLE_BITS=FF -CONFIG_PB_CHANGEABLE_DIR=00 -CONFIG_PB_CHANGEABLE_BITS=FF -# CONFIG_JULIETTE is not set -# CONFIG_JULIETTE_VIDEO is not set -# CONFIG_JULIETTE_CCD is not set -# CONFIG_JULIETTE_SS1M is not set -# CONFIG_JULIETTE_MEGCCD is not set +CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF +CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF # CONFIG_ETRAX_USB_HOST is not set # diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.4/linux/arch/cris/drivers/Config.in Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/Config.in Tue May 1 16:04:56 2001 @@ -1,5 +1,5 @@ mainmenu_option next_comment -comment 'Drivers for Etrax built-in interfaces' +comment 'Drivers for ETRAX 100LX built-in interfaces' bool 'Ethernet support' CONFIG_ETRAX_ETHERNET if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then @@ -46,13 +46,13 @@ fi fi bool ' Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3 - bool ' RS-485 support' CONFIG_RS485 - if [ "$CONFIG_RS485" = "y" ]; then - bool ' RS-485 mode on PA' CONFIG_RS485_ON_PA - if [ "$CONFIG_RS485_ON_PA" = "y" ]; then - int ' RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3 + bool ' RS-485 support' CONFIG_ETRAX_RS485 + if [ "$CONFIG_ETRAX_RS485" = "y" ]; then + bool ' RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA + if [ "$CONFIG_ETRAX_RS485_ON_PA" = "y" ]; then + int ' RS-485 mode on PA bit' CONFIG_ETRAX_RS485_ON_PA_BIT 3 fi - bool ' Disable serial receiver' CONFIG_RS485_DISABLE_RECEIVER + bool ' Disable serial receiver' CONFIG_ETRAX_RS485_DISABLE_RECEIVER fi fi @@ -60,14 +60,29 @@ if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then bool ' Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then - bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA y + bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA fi bool ' Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then - bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA y + bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA fi fi +bool 'Parallel port support' CONFIG_ETRAX_PARPORT +if [ "$CONFIG_ETRAX_PARPORT" = "y" ]; then + bool ' Parallel port 0 enabled' CONFIG_ETRAX_PARALLEL_PORT0 + bool ' Parallel port 1 enabled' CONFIG_ETRAX_PARALLEL_PORT1 +# here we define the CONFIG_'s necessary to enable parallel port support + define_tristate CONFIG_PARPORT y + define_bool CONFIG_PARPORT_1284 y + define_tristate CONFIG_PRINTER y +else + define_tristate CONFIG_PARPORT n + define_bool CONFIG_PARPORT_1284 n + define_tristate CONFIG_PRINTER n +fi + + bool 'ATA/IDE support' CONFIG_ETRAX_IDE if [ "$CONFIG_ETRAX_IDE" = "y" ]; then @@ -89,7 +104,8 @@ choice 'IDE reset pin' \ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\ - Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 + Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET\ + Port_CSP0_Bit_08 CONFIG_ETRAX_IDE_CSP0_8_RESET" Port_PB_Bit_7 else define_bool CONFIG_IDE n fi @@ -97,6 +113,7 @@ bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then + int ' Byte-offset of partition table sector' CONFIG_ETRAX_PTABLE_SECTOR 65536 # here we define the CONFIG_'s necessary to enable MTD support # for the flash define_bool CONFIG_MTD y @@ -118,16 +135,25 @@ bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C fi +bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM +if [ "$CONFIG_ETRAX_I2C_EEPROM" = "y" ]; then + choice ' EEPROM size' \ + "Probed CONFIG_ETRAX_I2C_EEPROM_PROBE \ + 2kB CONFIG_ETRAX_I2C_EEPROM_2KB \ + 8kB CONFIG_ETRAX_I2C_EEPROM_8KB \ + 16kB CONFIG_ETRAX_I2C_EEPROM_16KB" Probed +fi + bool 'GPIO support' CONFIG_ETRAX_GPIO if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then hex ' PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02 - hex ' PA user changeable dir mask' CONFIG_PA_CHANGEABLE_DIR 00 - hex ' PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF - hex ' PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00 - hex ' PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF + hex ' PA user changeable dir mask' CONFIG_ETRAX_PA_CHANGEABLE_DIR 00 + hex ' PA user changeable bits mask' CONFIG_ETRAX_PA_CHANGEABLE_BITS FF + hex ' PB user changeable dir mask' CONFIG_ETRAX_PB_CHANGEABLE_DIR 00 + hex ' PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF fi -bool 'Juliette support' CONFIG_JULIETTE n +bool 'ARTPEC-1 support' CONFIG_JULIETTE if [ "$CONFIG_JULIETTE" = "y" ]; then source arch/cris/drivers/juliette/Config.in @@ -136,8 +162,18 @@ bool 'USB host' CONFIG_ETRAX_USB_HOST if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then define_bool CONFIG_USB y - bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 n - bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n + bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 + bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 +else + define_bool CONFIG_USB n +fi + +bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302 +if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then + bool ' DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + int ' DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2 + int ' DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1 + int ' DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0 fi endmenu diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile --- v2.4.4/linux/arch/cris/drivers/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/Makefile Tue May 1 16:04:56 2001 @@ -12,10 +12,13 @@ obj-$(CONFIG_ETRAX_IDE) += ide.o obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o obj-$(CONFIG_ETRAX_I2C) += i2c.o +obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o obj-$(CONFIG_ETRAX_GPIO) += gpio.o obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_JULIETTE) += juliette/juliette.o -subdir-$(CONFIG_JULIETTE) += juliette +obj-$(CONFIG_ETRAX_PARPORT) += parport.o +obj-$(CONFIG_ETRAX_DS1302) += ds1302.o + + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.4/linux/arch/cris/drivers/axisflashmap.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/axisflashmap.c Tue May 1 16:04:56 2001 @@ -11,6 +11,15 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.7 2001/04/05 13:41:46 markusl + * Updated according to review remarks + * + * Revision 1.6 2001/03/07 09:21:21 bjornw + * No need to waste .data + * + * Revision 1.5 2001/03/06 16:27:01 jonashg + * Probe the entire flash area for flash devices. + * * Revision 1.4 2001/02/23 12:47:15 bjornw * Uncached flash in LOW_MAP moved from 0xe to 0x8 * @@ -50,19 +59,13 @@ #endif /* - * WINDOW_SIZE is the total size where the flash chips are mapped, - * my guess is that this can be the total memory area even if there - * are many flash chips inside the area or if they are not all mounted. - * So possibly we can get rid of the CONFIG_ here and just write something - * like 32 MB always. - */ - -#define WINDOW_SIZE (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024) - -/* Byte-offset where the partition-table is placed in the first chip + * WINDOW_SIZE is the total size where the flash chips may be mapped. + * MTD probes should find all devices there and it does not matter + * if there are unmapped gaps or aliases (mirrors of flash devices). + * The MTD probes will ignore them. */ -#define PTABLE_SECTOR 65536 +#define WINDOW_SIZE (128 * 1024 * 1024) /* * Map driver @@ -70,8 +73,6 @@ * Ok this is the scoop - we need to access the flash both with and without * the cache - without when doing all the fancy flash interfacing, and with * when we do actual copying because otherwise it will be slow like molasses. - * I hope this works the way it's intended, so that there won't be any cases - * of non-synchronicity because of the different access modes below... */ static __u8 flash_read8(struct map_info *map, unsigned long ofs) @@ -110,12 +111,6 @@ *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; } -static void flash_copy_to(struct map_info *map, unsigned long to, - const void *from, ssize_t len) -{ - memcpy((void *)(FLASH_CACHED_ADDR + to), from, len); -} - static struct map_info axis_map = { name: "Axis flash", size: WINDOW_SIZE, @@ -127,7 +122,6 @@ write8: flash_write8, write16: flash_write16, write32: flash_write32, - copy_to: flash_copy_to }; /* If no partition-table was found, we use this default-set. @@ -139,18 +133,18 @@ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { { name: "boot firmware", - size: PTABLE_SECTOR, + size: CONFIG_ETRAX_PTABLE_SECTOR, offset: 0 }, { name: "kernel", size: 0x1a0000, - offset: PTABLE_SECTOR + offset: CONFIG_ETRAX_PTABLE_SECTOR }, { name: "filesystem", size: 0x50000, - offset: (0x1a0000 + PTABLE_SECTOR) + offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR) } }; @@ -214,11 +208,11 @@ printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", WINDOW_SIZE, FLASH_CACHED_ADDR); - mymtd = do_cfi_probe(&axis_map); + mymtd = (struct mtd_info *)do_cfi_probe(&axis_map); #ifdef CONFIG_MTD_AMDSTD if (!mymtd) { - mymtd = do_amd_flash_probe(&axis_map); + mymtd = (struct mtd_info *)do_amd_flash_probe(&axis_map); } #endif @@ -236,18 +230,15 @@ */ ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + - PTABLE_SECTOR + PARTITION_TABLE_OFFSET); + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size - < (MAX_PARTITIONS - * sizeof(struct partitiontable_entry) + 4)) - && (*(unsigned long*) - ((void*)ptable_head - + sizeof(*ptable_head) - + ptable_head->size - 4) - == PARTITIONTABLE_END_MARKER)) { + && (ptable_head->size < + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4)) + && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + + ptable_head->size - 4) + == PARTITIONTABLE_END_MARKER)) { /* Looks like a start, sane length and end of a * partition table, lets check csum etc. */ @@ -256,7 +247,7 @@ (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head) + ptable_head->size); - unsigned long offset = PTABLE_SECTOR; + unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; unsigned char *p; unsigned long csum = 0; @@ -293,16 +284,7 @@ && ptable->offset != 0xffffffff && ptable < max_addr && pidx < MAX_PARTITIONS) { -#if 0 - /* wait with multi-chip support until we know - * how mtd detects multiple chips - */ - if ((offset + ptable->offset) >= chips[0].size) { - partitions[pidx].start - = offset + chips[1].start - + ptable->offset - chips[0].size; - } -#endif + axis_partitions[pidx].offset = offset + ptable->offset; axis_partitions[pidx].size = ptable->size; diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c --- v2.4.4/linux/arch/cris/drivers/ds1302.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/ds1302.c Tue May 1 16:04:56 2001 @@ -0,0 +1,488 @@ +/*!*************************************************************************** +*! +*! FILE NAME : ds1302.c +*! +*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O +*! +*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status +*! +*! $Log: ds1302.c,v $ +*! Revision 1.3 2001/03/26 16:03:06 bjornw +*! Needs linux/config.h +*! +*! Revision 1.2 2001/03/20 19:42:00 bjornw +*! Use the ETRAX prefix on the DS1302 options +*! +*! Revision 1.1 2001/03/20 09:13:50 magnusmn +*! Linux 2.4 port +*! +*! Revision 1.10 2000/07/05 15:38:23 bjornw +*! Dont update kernel time when a RTC_SET_TIME is done +*! +*! Revision 1.9 2000/03/02 15:42:59 macce +*! * Hack to make RTC work on all 2100/2400 +*! +*! Revision 1.8 2000/02/23 16:59:18 torbjore +*! added setup of R_GEN_CONFIG when RTC is connected to the generic port. +*! +*! Revision 1.7 2000/01/17 15:51:43 johana +*! Added RTC_SET_CHARGE ioctl to enable trickle charger. +*! +*! Revision 1.6 1999/10/27 13:19:47 bjornw +*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel. +*! /dev/rtc calls it now. +*! +*! Revision 1.5 1999/10/27 12:39:37 bjornw +*! Disabled superuser check. Anyone can now set the time. +*! +*! Revision 1.4 1999/09/02 13:27:46 pkj +*! Added shadow for R_PORT_PB_CONFIG. +*! Renamed port_g_shadow to port_g_data_shadow. +*! +*! Revision 1.3 1999/09/02 08:28:06 pkj +*! Made it possible to select either port PB or the generic port for the RST +*! signal line to the DS1302 RTC. +*! Also make sure the RST bit is configured as output on Port PB (if used). +*! +*! Revision 1.2 1999/09/01 14:47:20 bjornw +*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read +*! and set the date. Register as major 121. +*! +*! Revision 1.1 1999/09/01 09:45:29 bjornw +*! Implemented a DS1302 RTC driver. +*! +*! +*! --------------------------------------------------------------------------- +*! +*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! +*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $ +*! +*!***************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define RTC_MAJOR_NR 121 /* local major, change later */ + +/* The DS1302 might be connected to different bits on different products. + * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, + * but SDA can have a selected direction. + * For now, only PORT_PB is hardcoded. + */ + +/* The RST bit may be on either the Generic Port or Port PB */ +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) +#else +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#endif + + +#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + +#define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) +/* 1 is out, 0 is in */ +#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + + +/* + * The reason for tempudelay and not udelay is that loops_per_usec + * (used in udelay) is not set when functions here are called from time.c + */ + +static void tempudelay(int time) +{ + int i; + for(i = 0; i < time * 10000; i++); +} + + +/* send 8 bits */ +static void +out_byte(int x) +{ + int i; + TK_SDA_DIR(1); + for (i = 8; i--;) { + /* the chip latches incoming bits on the rising edge of SCL */ + TK_SCL_OUT(0); + TK_SDA_OUT(x & 1); + tempudelay(1); + TK_SCL_OUT(1); + tempudelay(1); + x >>= 1; + } + TK_SDA_DIR(0); +} + +static unsigned char +in_byte(void) +{ + unsigned char x = 0; + int i; + + /* Read byte. Bits come LSB first, on the falling edge of SCL. + * Assume SDA is in input direction already + */ + TK_SDA_DIR(0); + + for (i = 8; i--;) { + TK_SCL_OUT(0); + tempudelay(1); + x >>= 1; + x |= (TK_SDA_IN() << 7); + TK_SCL_OUT(1); + tempudelay(1); + } + + return x; +} + +/* prepares for a transaction by de-activating RST (active-low) */ + +static void +start(void) +{ + TK_SCL_OUT(0); + tempudelay(1); + TK_RST_OUT(0); + tempudelay(5); + TK_RST_OUT(1); +} + +/* ends a transaction by taking RST active again */ + +static void +stop(void) +{ + tempudelay(2); + TK_RST_OUT(0); +} + +/* enable writing */ + +static void +ds1302_wenable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x00); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* disable writing */ + +static void +ds1302_wdisable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x80); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* probe for the chip by writing something to its RAM and try reading it back */ + +static int +ds1302_probe(void) +{ + int retval, res; + + TK_RST_DIR(1); + TK_SCL_DIR(1); + TK_SDA_DIR(0); + + /* try to talk to timekeeper */ + + ds1302_wenable(); + start(); + out_byte(0xc0); /* write RAM byte 0 */ + out_byte(0x42); /* write something magic */ + start(); + out_byte(0xc1); /* read RAM byte 0 */ + + if((res = in_byte()) == 0x42) { + char buf[100]; + stop(); + ds1302_wdisable(); + printk("DS1302 RTC found.\n"); + printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n", + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + "GENIO", +#else + "PB", +#endif + CONFIG_ETRAX_DS1302_RSTBIT + ); + get_rtc_status(buf); + printk(buf); + retval = 1; + } else { + stop(); + printk("DS1302 RTC not found.\n"); + retval = 0; + } + + return retval; +} + + +/* read a byte from the selected register in the DS1302 */ + +unsigned char +ds1302_readreg(int reg) +{ + unsigned char x; + + start(); + out_byte(0x81 | (reg << 1)); /* Read register */ + x = in_byte(); + stop(); + + return x; +} + +/* write a byte to the selected register */ + +void +ds1302_writereg(int reg, unsigned char val) +{ + ds1302_wenable(); + start(); + out_byte(0x80 | (reg << 1)); /* Write register */ + out_byte(val); + stop(); + ds1302_wdisable(); +} + +void +get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + + restore_flags(flags); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + + if (rtc_tm->tm_year <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static unsigned char days_in_mo[] = + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */ + +static int +rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long flags; + + switch(cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + struct rtc_time rtc_tm; + + get_rtc_time(&rtc_tm); + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; + return 0; + } + + 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, save_freq_select; + unsigned int yrs; +#if 0 + if (!suser()) + return -EACCES; +#endif + 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) || (yrs > 2069)) + 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 >= 2000) + yrs -= 2000; /* RTC (0, 1, ... 69) */ + else + yrs -= 1900; /* RTC (70, 71, ... 99) */ + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + save_flags(flags); + cli(); + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + restore_flags(flags); + + /* notice that at this point, the RTC is updated but the kernel + * is still running with the old time. you need to set that + * separately with settimeofday or adjtimex. + */ + return 0; + } + + case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */ + { + int tcs_val; + unsigned char save_control, save_freq_select; +#if 0 + if (!suser()) + return -EACCES; +#endif + + if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) + return -EFAULT; + + tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); + ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +/* + * Info exported via "/proc/rtc". + */ + +int +get_rtc_status(char *buf) +{ + char *p; + struct rtc_time tm; + + p = buf; + + get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + return p - buf; +} + + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + ioctl: rtc_ioctl, +}; + +/* just probe for the RTC and register the device to handle the ioctl needed */ + +int +ds1302_init(void) +{ + + /* Ugly hack to handle both 2100 and 2400 hardware. + Remove... + */ + if(!ds1302_probe()) { +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + /* + * Make sure that R_GEN_CONFIG is + * setup correct. + */ + genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | + ( IO_STATE( R_GEN_CONFIG, ata, select ) ) ); + *R_GEN_CONFIG = genconfig_shadow; + if(!ds1302_probe()) + return -1; +#else + return -1; +#endif + } + + if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) { + printk("unable to get major %d for rtc\n", RTC_MAJOR_NR); + return -1; + } + return 0; +} + + diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c --- v2.4.4/linux/arch/cris/drivers/eeprom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/eeprom.c Tue May 1 16:04:56 2001 @@ -0,0 +1,1161 @@ +/*!************************************************************************** +*! +*! FILE NAME: e100eeprom.c +*! +*! DESCRIPTION: Implements an interface for i2c compatible eeproms to run +*! under linux. +*! Supports 2k, 8k(?) and 16k +*! Uses adaptive timing adjustents by Johan.Adolfsson@axis.com +*! Probing results: +*! 8k or not is detected (the assumes 2k or 16k) +*! 2k or 16k detected using test reads and writes. +*! +*! FUNCTIONS: +*! +*! (Exported) +*! eeprom_init() +*! +*! (Local) +*! +*! eeprom_open() +*! eeprom_lseek() +*! eeprom_read() +*! eeprom_write() +*! eeprom_close() +*! eeprom_address() +*! eeprom_disable_write_protect() +*! +*! +*! $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $ +*! +*!------------------------------------------------------------------------ +*! HISTORY +*! +*! DATE NAME CHANGES +*! ---- ---- ------- +*! Aug 28 1999 Edgar Iglesias Initial Version +*! Aug 31 1999 Edgar Iglesias Allow simultaneous users. +*! Sep 03 1999 Edgar Iglesias Updated probe. +*! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*! in the spin-lock. +*! +*! $Log: eeprom.c,v $ +*! Revision 1.3 2001/03/19 16:04:46 markusl +*! Fixed init of fops struct +*! +*! Revision 1.2 2001/03/19 10:35:07 markusl +*! 2.4 port of eeprom driver +*! +*! Revision 1.8 2000/05/18 10:42:25 edgar +*! Make sure to end write cycle on _every_ write +*! +*! Revision 1.7 2000/01/17 17:41:01 johana +*! Adjusted probing and return -ENOSPC when writing outside EEPROM +*! +*! Revision 1.6 2000/01/17 15:50:36 johana +*! Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?) +*! EEPROMs +*! +*! Revision 1.5 1999/09/03 15:07:37 edgar +*! Added bail-out check to the spinlock +*! +*! Revision 1.4 1999/09/03 12:11:17 bjornw +*! Proper atomicity (need to use spinlocks, not if's). users -> busy. +*! +*! +*! (c) 1999 Axis Communications AB, Lund, Sweden +*!**************************************************************************/ + +/********************** INCLUDE FILES SECTION ******************************/ + +#include +#include +#include +#include +#include +#include +#include "i2c.h" + +/********************** CONSTANT AND MACRO SECTION *************************/ +#define D(x) + +/* If we should use adaptive timing or not: */ +//#define EEPROM_ADAPTIVE_TIMING + +#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */ +#define EEPROM_MINOR_NR 0 + +#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ +/* + * this one defines how many times to try when eeprom fails. + */ +#define EEPROM_RETRIES 10 + +#define EEPROM_2KB (2 * 1024) +/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */ +#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */ +#define EEPROM_16KB (16 * 1024) + +#define i2c_delay(x) udelay(x) + +/********************** TYPE DEFINITION SECTION ****************************/ + +/* + * This structure describes the attached eeprom chip. + * The values are probed for. + */ + +struct eeprom_type +{ + unsigned long size; + unsigned long sequential_write_pagesize; + unsigned char select_cmd; + unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */ + unsigned long int usec_delay_step; /* For adaptive algorithm */ + int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */ + + /* this one is to keep the read/write operations atomic */ + wait_queue_head_t wait_q; + int busy; + int retry_cnt_addr; /* Used to keep track of number of retries for + adaptive timing adjustments */ + int retry_cnt_read; + + + +}; + +/********************** LOCAL FUNCTION DECLARATION SECTION *****************/ + +static int eeprom_open (struct inode * inode, struct file * file); +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig); +static ssize_t eeprom_read (struct file * file, char * buf, size_t count, loff_t *off); +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off); +static int eeprom_close(struct inode * inode, struct file * file); + +static int eeprom_address(unsigned long addr); +static int read_from_eeprom(char * buf, int count); +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count); +static int eeprom_read_buf(unsigned long addr, + char * buf, int count); + +static void eeprom_disable_write_protect(void); + + +/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/ + +/********************** LOCAL VARIABLE DECLARATION SECTION *****************/ + +/* chip description */ +static struct eeprom_type eeprom; + +/* + * This is the exported file-operations structure + * for this device. + */ + +struct file_operations eeprom_fops = +{ + llseek: eeprom_lseek, + read: eeprom_read, + write: eeprom_write, + open: eeprom_open, + release: eeprom_close +}; + +/********************** FUNCTION DEFINITION SECTION ************************/ + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_init +*# +*# PARAMETERS : none +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : eeprom init call. Probes for different eeprom models. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Updated probing. Added forced values. +*# +*#**************************************************************************/ + +int __init eeprom_init(void) +{ + init_waitqueue_head(&eeprom.wait_q); + eeprom.busy = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE +#define EETEXT "Found" +#else +#define EETEXT "Assuming" +#endif + if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops)) + { + printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR); + return -1; + } + + printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n"); + + /* + * Note: Most of this probing method was taken from the printserver (5470e) + * codebase. It did not contain a way of finding the 16Kb chips + * (M24128 or variants). The method used here might not work + * for all models. If you encounter problems the easiest way + * is probably to define your model within #ifdef's, and hard- + * code it. + * + */ + + eeprom.size = 0; + eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/ + eeprom.usec_delay_step = 128; + eeprom.adapt_state = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE + i2c_start(); + i2c_outbyte(0x80); + if(!i2c_getack()) + { + /* It's not 8k.. */ + int success = 0; + unsigned char buf_2k_start[16]; + + /* Im not sure this will work... :) */ + /* assume 2Kb, if failure go for 16Kb */ + /* Test with 16kB settings.. */ + /* If it's a 2kB EEPROM and we address it outside it's range + * it will mirror the address space: + * 1. We read two locations (that are mirrored), + * if the content differs * it's a 16kB EEPROM. + * 2. if it doesn't differ - write diferent value to one of the locations, + * check the other - if content still is the same it's a 2k EEPROM, + * restore original data. + * + */ +#define LOC1 8 +#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */ + + /* 2k settings */ + i2c_stop(); + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 ) + { + D(printk("2k start: '%16.16s'\n", buf_2k_start)); + } + else + { + printk("Failed to read in 2k mode!\n"); + } + + /* 16k settings */ + eeprom.size = EEPROM_16KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 64; + + { + unsigned char loc1[4], loc2[4], tmp[4]; + if( eeprom_read_buf(LOC2, loc2, 4) == 4) + { + if( eeprom_read_buf(LOC1, loc1, 4) == 4) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); +#if 0 + if (memcmp(loc1, loc2, 4) != 0 ) + { + /* It's 16k */ + printk("16k detected in step 1\n"); + eeprom.size = EEPROM_16KB; + success = 1; + } + else +#endif + { + /* Do step 2 check */ + /* Invert value */ + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + /* If 2k EEPROM this write will actually write 10 bytes + * from pos 0 + */ + D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if( eeprom_read_buf(LOC1, tmp, 4) == 4) + { + D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", + LOC1, loc1, tmp)); + if (memcmp(loc1, tmp, 4) != 0 ) + { + printk("read and write differs! Not 16kB\n"); + loc1[0] = ~loc1[0]; + + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + i2c_stop(); + /* Go to 2k mode and write original data */ + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_write_buf(0, buf_2k_start, 16) == 16) + { + } + else + { + printk("Failed to write back 2k start!\n"); + } + + eeprom.size = EEPROM_2KB; + } + } + + if(!success) + { + if( eeprom_read_buf(LOC2, loc2, 1) == 1) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if (memcmp(loc1, loc2, 4) == 0 ) + { + /* Data the same, must be mirrored -> 2k */ + /* Restore data */ + printk("2k detected in step 2\n"); + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + + eeprom.size = EEPROM_2KB; + } + else + { + printk("16k detected in step 2\n"); + loc1[0] = ~loc1[0]; + /* Data differs, assume 16k */ + /* Restore data */ + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n"); + } + + eeprom.size = EEPROM_16KB; + } + } + } + } + } /* read LOC1 */ + } /* address LOC1 */ + if (!success) + { + printk("eeprom: Probing failed!, using 2KB!\n"); + eeprom.size = EEPROM_2KB; + } + } /* read */ + } + } + else + { + i2c_outbyte(0x00); + if(!i2c_getack()) + { + /* No 8k */ + eeprom.size = EEPROM_2KB; + } + else + { + i2c_start(); + i2c_outbyte(0x81); + if (!i2c_getack()) + { + eeprom.size = EEPROM_2KB; + } + else + { + /* It's a 8kB */ + i2c_inbyte(); + eeprom.size = EEPROM_8KB; + } + } + } + i2c_stop(); +#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB) + eeprom.size = EEPROM_16KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB) + eeprom.size = EEPROM_8KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB) + eeprom.size = EEPROM_2KB; +#endif + + switch(eeprom.size) + { + case (EEPROM_2KB): + printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0xA0; + break; + case (EEPROM_8KB): + printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0x80; + break; + case (EEPROM_16KB): + printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 64; + eeprom.select_cmd = 0xA0; + break; + default: + eeprom.size = 0; + printk("e100eeprom: Did not find a supported eeprom\n"); + break; + } + + + + eeprom_disable_write_protect(); + + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_open +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Opens the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed users check. +*# +*#**************************************************************************/ + +static int eeprom_open(struct inode * inode, struct file * file) +{ + + if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) + return -ENXIO; + if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) + return -ENXIO; + + if( eeprom.size > 0 ) + { + /* OK */ + return 0; + } + + /* No EEprom found */ + return -EFAULT; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_lseek +*# +*# PARAMETERS : file : Pointer to the file +*# offset : The offset (in bytes) +*# orig : look at the note +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Changes the current file position. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Return -EOVERFLOW when beyond eeprom size. +*# +*#**************************************************************************/ + +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) +{ +/* + * orig 0: position from begning of eeprom + * orig 1: relative from current position + * orig 2: position from last eeprom address + */ + + switch (orig) + { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = eeprom.size - offset; + break; + default: + return -EINVAL; + } + + /* truncate position */ + if (file->f_pos < 0) + { + file->f_pos = 0; + return(-EOVERFLOW); + } + + if (file->f_pos >= eeprom.size) + { + file->f_pos = eeprom.size - 1; + return(-EOVERFLOW); + } + + return ( file->f_pos ); +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial version +*# +*#**************************************************************************/ +static int eeprom_read_buf(unsigned long addr, + char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + return eeprom_read(&f, buf, count, &addr); +} + + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# +*#**************************************************************************/ + +static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) +{ + int i, read=0; + unsigned long p = file->f_pos; + + unsigned char page; + + if(p >= eeprom.size) /* Address i 0 - (size-1) */ + { + return -EFAULT; + } + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + + } + eeprom.busy++; + + page = (unsigned char) (p >> 8); + + if(!eeprom_address(p)) + { + printk("eeprom: Read failed to address the eeprom: " + "0x%08X (%i) page: %i\n", p, p, page); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } + + if( (p + count) > eeprom.size) + { + /* truncate count */ + count = eeprom.size - p; + } + + /* stop dummy write op and initiate the read op */ + i2c_start(); + + /* special case for small eeproms */ + if(eeprom.size < EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) ); + } + + /* go on with the actual read */ + read = read_from_eeprom( buf, count); + + if(read > 0) + { + file->f_pos += read; + } + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write_buf +*# +*# PARAMETERS : addr : Address to write to +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : None +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial vesion +*# +*#**************************************************************************/ +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + + return eeprom_write(&f, buf, count, &addr); +} + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Moved the actual reading to read_from_eeprom +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# May 18 2000 Edgar Iglesias Make sure to end write cycle after every write. +*# +*#**************************************************************************/ + +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + int i, written, restart=1; + unsigned long p; + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + } + eeprom.busy++; + for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) + { + restart = 0; + written = 0; + p = file->f_pos; + + + while( (written < count) && (p < eeprom.size)) + { + /* address the eeprom */ + if(!eeprom_address(p)) + { + printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", + p, p); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } +#ifdef EEPROM_ADAPTIVE_TIMING + /* Adaptive algorithm to adjust timing */ + if (eeprom.retry_cnt_addr > 0) + { + /* To Low now */ + D(printk(">D=%i d=%i\n", + eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); + + if (eeprom.usec_delay_step < 4) + { + eeprom.usec_delay_step++; + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else + { + + if (eeprom.adapt_state > 0) + { + /* To Low before */ + eeprom.usec_delay_step *= 2; + if (eeprom.usec_delay_step > 2) + { + eeprom.usec_delay_step--; + } + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else if (eeprom.adapt_state < 0) + { + /* To High before (toggle dir) */ + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + } + } + + eeprom.adapt_state = 1; + } + else + { + /* To High (or good) now */ + D(printk(" 1) + { + if (eeprom.usec_delay_step > 0) + { + eeprom.usec_delay_step *= 2; + eeprom.usec_delay_step--; + } + + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + } + } + else if (eeprom.adapt_state > 0) + { + /* To Low before (toggle dir) */ + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + + eeprom.adapt_state = -1; + } + + if (eeprom.adapt_state > -100) + { + eeprom.adapt_state--; + } + else + { + /* Restart adaption */ + D(printk("#Restart\n")); + eeprom.usec_delay_step++; + } + } +#endif /* EEPROM_ADAPTIVE_TIMING */ + /* write until we hit a page boundary or count */ + do + { + i2c_outbyte(buf[written]); + if(!i2c_getack()) + { + restart=1; + printk("eeprom: write error, retrying. %d\n", i); + i2c_stop(); + break; + } + written++; + p++; + } while( written < count && ( p % eeprom.sequential_write_pagesize )); + + /* end write cycle */ + i2c_stop(); + i2c_delay(eeprom.usec_delay_writecycles); + } /* while */ + } /* for */ + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + if (written == 0 && file->f_pos >= eeprom.size){ + return -ENOSPC; + } + file->f_pos += written; + return written; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_close +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Closes the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed eeprom.users stuff. +*# +*#**************************************************************************/ + +static int eeprom_close(struct inode * inode, struct file * file) +{ + /* do nothing for now */ + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_address +*# +*# PARAMETERS : addr : Address to be given to eeprom +*# +*# RETURNS : 1 if OK, 0 if failure. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Sets the current address of the eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Corrected typo. +*# +*#**************************************************************************/ + +static int eeprom_address(unsigned long addr) +{ + int i, j; + unsigned char page, offset; + + page = (unsigned char) (addr >> 8); + offset = (unsigned char) addr; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + /* start a dummy write for addressing */ + i2c_start(); + + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd ); + i2c_getack(); + i2c_outbyte(page); + } + else + { + i2c_outbyte( eeprom.select_cmd | (page << 1) ); + } + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + /* Must have a delay here.. 500 works, >50, 100->works 5th time*/ + i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i); + /* The chip needs up to 10 ms from write stop to next start */ + + } + else + { + i2c_outbyte(offset); + + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + } + else + break; + } + } + + + eeprom.retry_cnt_addr = i; + D(printk("%i\n", eeprom.retry_cnt_addr)); + if(eeprom.retry_cnt_addr == EEPROM_RETRIES) + { + /* failed */ + return 0; + } + return 1; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: read_from_eeprom +*# +*# PARAMETERS : buf : Destination buffer. +*# count : Number of bytes to read. +*# +*# RETURNS : number of read bytes or -EFAULT. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Reads from current adress. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Sep 03 1999 Edgar Iglesias Initial version +*# +*#**************************************************************************/ + +static int read_from_eeprom(char * buf, int count) +{ + int i, read=0; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 ); + } + + if(i2c_getack()); + { + break; + } + } + + if(i == EEPROM_RETRIES) + { + printk("eeprom: failed to read from eeprom\n"); + i2c_stop(); + + return -EFAULT; + } + + while( (read < count)) + { + buf[read++] = i2c_inbyte(); + + /* + * make sure we don't ack last byte or you will get very strange + * results! + */ + if(read < count) + { + i2c_sendack(); + } + } + + /* stop the operation */ + i2c_stop(); + + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_disable_write_protect +*# +*# PARAMETERS : None +*# +*# RETURNS : Nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Disables write protection if applicable +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 14 2000 Johan Adolfsson Initial version (from PS pareerom.c) +*# +*#**************************************************************************/ +#define DBP_SAVE(x) +#define ax_printf printk +static void eeprom_disable_write_protect(void) +{ + /* Disable write protect */ + if (eeprom.size == EEPROM_8KB) + { + /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 2\n")); + } + i2c_outbyte(0x02); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 3\n")); + } + i2c_stop(); + + i2c_delay(1000); + + /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 55\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 52\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 53\n")); + } + i2c_stop(); + + /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 56\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 57\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 58\n")); + } + i2c_stop(); + + /* Write protect disabled */ + } +} + +module_init(eeprom_init); + +/********************** END OF FILE e100eeprom.c *****************************/ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c --- v2.4.4/linux/arch/cris/drivers/ethernet.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/ethernet.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ +/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,21 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.12 2001/04/05 11:43:11 tobiasa + * Check dev before panic. + * + * Revision 1.11 2001/04/04 11:21:05 markusl + * Updated according to review remarks + * + * Revision 1.10 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.9 2001/03/19 14:47:48 pkj + * * Make sure there is always a pause after the network LEDs are + * changed so they will not look constantly lit during heavy traffic. + * * Always use HZ when setting times relative to jiffies. + * * Use LED_NETWORK_SET() when setting the network LEDs. + * * Revision 1.8 2001/02/27 13:52:48 bjornw * malloc.h -> slab.h * @@ -40,10 +55,13 @@ * */ +#include + #include #include #include +#include #include #include #include @@ -52,11 +70,7 @@ #include #include #include -#include -#include #include -#include -#include #include #include @@ -65,11 +79,17 @@ #include #include /* DMA and register descriptions */ +#include /* LED_* I/O functions */ +#include +#include +#include //#define ETHDEBUG - #define D(x) +#define ETH_TX_DMA 0 +#define ETH_RX_DMA 1 + /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -126,12 +146,12 @@ #define MDIO_PHYS_ADDR 0x0 /* Network flash constants */ -#define NET_FLASH_TIME 2 /* 20 ms */ -#define NET_LINK_UP_CHECK_INTERVAL 200 /* 2 s */ +#define NET_FLASH_TIME (HZ/50) /* 20 ms */ +#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ +#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ -/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer - * alignment bug in Etrax 100 release 1 - */ +#define NO_NETWORK_ACTIVITY 0 +#define NETWORK_ACTIVITY 1 #define RX_DESC_BUF_SIZE 256 #define NBR_OF_RX_DESC (RX_BUF_SIZE / \ @@ -146,8 +166,8 @@ static unsigned char RxBuf[RX_BUF_SIZE]; -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC]; -static etrax_dma_descr TxDesc; +static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); +static etrax_dma_descr TxDesc __attribute__ ((aligned(4))); static struct sk_buff *tx_skb; @@ -155,8 +175,8 @@ static struct timer_list speed_timer; static struct timer_list clear_led_timer; static int current_speed; -static int led_clear_time; -static int nolink; +static int led_next_time; +static int led_active; /* Index to functions, as function prototypes. */ @@ -184,6 +204,7 @@ static void e100_reset_tranceiver(void); static void e100_clear_network_leds(unsigned long dummy); +static void e100_set_network_leds(int active); #define tx_done(dev) (*R_DMA_CH0_CMD == 0) @@ -201,7 +222,7 @@ int i; int anOffset = 0; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n"); + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ @@ -212,6 +233,8 @@ if (!dev) { printk("dev == NULL. Should this happen?\n"); dev = init_etherdev(dev, sizeof(struct net_local)); + if (!dev) + panic("init_etherdev failed\n"); } /* setup generic handlers and stuff in the dev struct */ @@ -272,13 +295,12 @@ /* Initialize speed indicator stuff. */ - nolink = 0; current_speed = 10; speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.function = e100_check_speed; add_timer(&speed_timer); clear_led_timer.function = e100_clear_network_leds; - clear_led_timer.expires = jiffies + 10; + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); return 0; @@ -345,8 +367,17 @@ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Reset and wait for the DMA channels */ @@ -383,17 +414,17 @@ * and clean up on failure. */ - if(request_dma(0, cardname)) { + if(request_dma(ETH_TX_DMA, cardname)) { goto grace_exit; } - if(request_dma(1, cardname)) { + if(request_dma(ETH_RX_DMA, cardname)) { grace_exit: /* this will cause some 'trying to free free irq' but what the heck... */ - free_dma(0); - free_irq(NETWORK_DMARX_IRQ, NULL); - free_irq(NETWORK_DMATX_IRQ, NULL); - free_irq(NETWORK_STATUS_IRQ, NULL); + free_dma(ETH_TX_DMA); + free_irq(NETWORK_DMARX_IRQ, (void *)dev); + free_irq(NETWORK_DMATX_IRQ, (void *)dev); + free_irq(NETWORK_STATUS_IRQ, (void *)dev); return -EAGAIN; } @@ -466,21 +497,19 @@ e100_check_speed(unsigned long dummy) { unsigned long data; + int old_speed = current_speed; + data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG); if (!(data & MDIO_LINK_UP_MASK)) { - nolink = 1; - LED_NETWORK_TX_SET(1); /* Make it red, link is down. */ + current_speed = 0; } else { - nolink = 0; - LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */ data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); - if (data & MDIO_SPEED) { - current_speed = 100; - } else { - current_speed = 10; - } + current_speed = (data & MDIO_SPEED ? 100 : 10); } + if (old_speed != current_speed) + e100_set_network_leds(NO_NETWORK_ACTIVITY); + /* Reinitialize the timer. */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; add_timer(&speed_timer); @@ -534,23 +563,26 @@ static void e100_send_mdio_bit(unsigned char bit) { - volatile int i; - *R_NETWORK_MGM_CTRL = 2 | bit&1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 6 | bit&1; - for (i=40; i; i--); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_MASK(R_NETWORK_MGM_CTRL, mdck) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); } static unsigned char e100_receive_mdio_bit() { unsigned char bit; - volatile int i; *R_NETWORK_MGM_CTRL = 0; - bit = *R_NETWORK_STAT & 1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 4; - for (i=40; i; i--); + bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT); + udelay(1); + *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck); + udelay(1); return bit; } @@ -566,7 +598,7 @@ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); - e100_send_mdio_cmd(cmd, 0); + e100_send_mdio_cmd(cmd, 1); data |= 0x8000; @@ -656,8 +688,8 @@ { struct net_device *dev = (struct net_device *)dev_id; unsigned long irqbits = *R_IRQ_MASK2_RD; - - if(irqbits & (1U << 3)) { + + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -671,10 +703,15 @@ */ e100_rx(dev); ((struct net_local *)dev->priv)->stats.rx_packets++; - *R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */ - *R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */ - /* now, we might have gotten another packet so we have to loop back - and check if so */ + /* restart/continue on the channel, for safety */ + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); + /* clear dma channel 1 eop/descr irq bits */ + *R_DMA_CH1_CLR_INTR = + IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); + + /* now, we might have gotten another packet + so we have to loop back and check if so */ } } } @@ -692,8 +729,9 @@ unsigned long irqbits = *R_IRQ_MASK2_RD; struct net_local *np = (struct net_local *)dev->priv; - if(irqbits & 2) { /* check for a dma0_eop interrupt */ - + /* check for a dma0_eop interrupt */ + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { + /* This protects us from concurrent execution of * our dev->hard_start_xmit function above. */ @@ -727,12 +765,14 @@ struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK0_RD; - if(irqbits & (1 << 19)) { /* check for overrun irq */ + /* check for overrun irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ D(printk("ethernet receiver overrun!\n")); } - if(irqbits & (1 << 17)) { /* check for excessive collision irq */ - *R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */ + /* check for excessive collision irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { + *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); } @@ -746,23 +786,19 @@ struct sk_buff *skb; int length=0; int i; + struct net_local *np = (struct net_local *)dev->priv; struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; - /* light the network rx packet depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else - LED_NETWORK_RX_SET(1); - - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* If the packet is broken down in many small packages then merge * count how much space we will need to alloc with skb_alloc() for * it to fit. @@ -790,6 +826,7 @@ skb = dev_alloc_skb(length - ETHER_HEAD_LEN); if (!skb) { + np->stats.rx_errors++; printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); return; @@ -798,7 +835,7 @@ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ -#if 0 +#ifdef ETHDEBUG printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", skb->head, skb->data, skb->tail, skb->end); printk("copying packet to 0x%x.\n", skb_data_ptr); @@ -849,9 +886,17 @@ *R_NETWORK_GEN_CONFIG = IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); - - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Stop the receiver and the transmitter */ @@ -864,8 +909,8 @@ free_irq(NETWORK_DMATX_IRQ, (void *)dev); free_irq(NETWORK_STATUS_IRQ, (void *)dev); - free_dma(0); - free_dma(1); + free_dma(ETH_TX_DMA); + free_dma(ETH_RX_DMA); /* Update the statistics here. */ @@ -997,22 +1042,16 @@ e100_hardware_send_packet(char *buf, int length) { D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); - /* light the network leds depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) { - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else { - LED_NETWORK_RX_SET(1); - } - } - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* configure the tx dma descriptor */ TxDesc.sw_len = length; @@ -1028,16 +1067,41 @@ static void e100_clear_network_leds(unsigned long dummy) { - if (jiffies > led_clear_time) { - if (nolink) - LED_NETWORK_TX_SET(1); - else - LED_NETWORK_TX_SET(0); - LED_NETWORK_RX_SET(0); + if (led_active && jiffies > led_next_time) { + e100_set_network_leds(NO_NETWORK_ACTIVITY); + + /* Set the earliest time we may set the LED */ + led_next_time = jiffies + NET_FLASH_PAUSE; + led_active = 0; } - - clear_led_timer.expires = jiffies + 10; + + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); +} + +static void +e100_set_network_leds(int active) +{ +#ifdef CONFIG_LED_OFF_DURING_ACTIVITY + int light_leds = (active == NO_NETWORK_ACTIVITY); +#else + int light_leds = (active == NETWORK_ACTIVITY); +#endif + + if (!current_speed) { + /* Make LED red, link is down */ + LED_NETWORK_SET(LED_RED); + } + else if (light_leds) { + if (current_speed == 10) { + LED_NETWORK_SET(LED_ORANGE); + } else { + LED_NETWORK_SET(LED_GREEN); + } + } + else { + LED_NETWORK_SET(LED_OFF); + } } static struct net_device dev_etrax_ethernet; /* only got one */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c --- v2.4.4/linux/arch/cris/drivers/gpio.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/gpio.c Sat May 19 17:43:05 2001 @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.4 2001/02/27 13:52:48 bjornw Exp $ +/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $ * * Etrax general port I/O device * @@ -9,6 +9,15 @@ * Johan Adolfsson (read/set directions) * * $Log: gpio.c,v $ + * Revision 1.7 2001/04/04 13:30:08 matsfg + * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping + * + * Revision 1.6 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.5 2001/03/26 14:22:03 bjornw + * Namechange of some config options + * * Revision 1.4 2001/02/27 13:52:48 bjornw * malloc.h -> slab.h * @@ -25,6 +34,7 @@ */ #include + #include #include #include @@ -78,25 +88,25 @@ &port_pa_data_shadow, &port_pb_data_shadow }; /* What direction bits that are user changeable 1=changeable*/ -#ifndef CONFIG_PA_CHANGEABLE_DIR -#define CONFIG_PA_CHANGEABLE_DIR 0x00 +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR +#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 #endif -#ifndef CONFIG_PB_CHANGEABLE_DIR -#define CONFIG_PB_CHANGEABLE_DIR 0x00 +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR +#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 #endif -#ifndef CONFIG_PA_CHANGEABLE_BITS -#define CONFIG_PA_CHANGEABLE_BITS 0xFF +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS +#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF #endif -#ifndef CONFIG_PB_CHANGEABLE_BITS -#define CONFIG_PB_CHANGEABLE_BITS 0xFF +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS +#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF #endif -static unsigned char changeable_dir[2] = { CONFIG_PA_CHANGEABLE_DIR, - CONFIG_PB_CHANGEABLE_DIR }; -static unsigned char changeable_bits[2] = { CONFIG_PA_CHANGEABLE_BITS, - CONFIG_PB_CHANGEABLE_BITS }; +static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR, + CONFIG_ETRAX_PB_CHANGEABLE_DIR }; +static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS, + CONFIG_ETRAX_PB_CHANGEABLE_BITS }; static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR }; @@ -240,7 +250,7 @@ default: if(priv->minor == LEDS) return gpio_leds_ioctl(cmd, arg); - else + else return -EINVAL; } @@ -252,7 +262,12 @@ { unsigned char green; unsigned char red; - + static int initialized = 0; + if(!initialized) + { + initialized = 1; + init_ioremap(); + } switch (_IOC_NR(cmd)) { case IO_LEDACTIVE_SET: green = ((unsigned char) arg) & 1; @@ -260,6 +275,11 @@ LED_ACTIVE_SET_G(green); LED_ACTIVE_SET_R(red); break; + case IO_LED_SETBIT: + LED_BIT_SET(arg); + break; + case IO_LED_CLRBIT: + LED_BIT_CLR(arg); default: return -EINVAL; } diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/i2c.c linux/arch/cris/drivers/i2c.c --- v2.4.4/linux/arch/cris/drivers/i2c.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/i2c.c Sat May 19 17:43:05 2001 @@ -12,6 +12,12 @@ *! don't use PB_I2C if DS1302 uses same bits, *! use PB. *! $Log: i2c.c,v $ +*! Revision 1.7 2001/04/04 13:11:36 markusl +*! Updated according to review remarks +*! +*! Revision 1.6 2001/03/19 12:43:00 markusl +*! Made some symbols unstatic (used by the eeprom driver) +*! *! Revision 1.5 2001/02/27 13:52:48 bjornw *! malloc.h -> slab.h *! @@ -37,7 +43,7 @@ *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ -/* $Id: i2c.c,v 1.5 2001/02/27 13:52:48 bjornw Exp $ */ +/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */ /****************** INCLUDE FILES SECTION ***********************************/ #include @@ -144,50 +150,50 @@ /* generate i2c start condition */ -static void +void i2c_start(void) { - // - // SCL=1 SDA=1 - // + /* + * SCL=1 SDA=1 + */ i2c_dir_out(); i2c_delay(CLOCK_HIGH_TIME/6); i2c_data(I2C_DATA_HIGH); i2c_clk(I2C_CLOCK_HIGH); i2c_delay(CLOCK_HIGH_TIME); - // - // SCL=1 SDA=0 - // + /* + * SCL=1 SDA=0 + */ i2c_data(I2C_DATA_LOW); i2c_delay(START_CONDITION_HOLD_TIME); - // - // SCL=0 SDA=0 - // + /* + * SCL=0 SDA=0 + */ i2c_clk(I2C_CLOCK_LOW); i2c_delay(CLOCK_LOW_TIME); } /* generate i2c stop condition */ -static void +void i2c_stop(void) { i2c_dir_out(); - // - // SCL=0 SDA=0 - // + /* + * SCL=0 SDA=0 + */ i2c_clk(I2C_CLOCK_LOW); i2c_data(I2C_DATA_LOW); i2c_delay(CLOCK_LOW_TIME*2); - // - // SCL=1 SDA=0 - // + /* + * SCL=1 SDA=0 + */ i2c_clk(I2C_CLOCK_HIGH); i2c_delay(CLOCK_HIGH_TIME*2); - // - // SCL=1 SDA=1 - // + /* + * SCL=1 SDA=1 + */ i2c_data(I2C_DATA_HIGH); i2c_delay(STOP_CONDITION_HOLD_TIME); @@ -196,7 +202,7 @@ /* write a byte to the i2c interface */ -static void +void i2c_outbyte(unsigned char x) { int i; @@ -219,78 +225,75 @@ i2c_data(I2C_DATA_LOW); i2c_delay(CLOCK_LOW_TIME/2); - // - // enable input - // + /* + * enable input + */ i2c_dir_in(); } /* read a byte from the i2c interface */ -static unsigned char +unsigned char i2c_inbyte(void) { unsigned char aBitByte = 0; int i; int iaa; - //int dd= 0; - // - // enable output - // + /* + * enable output + */ i2c_dir_out(); - // - // Release data bus by setting - // data high - // + /* + * Release data bus by setting + * data high + */ i2c_data(I2C_DATA_HIGH); - // - // enable input - // + /* + * enable input + */ i2c_dir_in(); - // - // Use PORT PB instead of I2C - // for input. (I2C not working) - // + /* + * Use PORT PB instead of I2C + * for input. (I2C not working) + */ i2c_clk(1); i2c_data(1); -/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ - // - // get bits - // + /* + * get bits + */ for (i = 0; i < 8; i++) { i2c_delay(CLOCK_LOW_TIME/2); - // - // low clock period - // + /* + * low clock period + */ i2c_clk(I2C_CLOCK_HIGH); - // - // switch off I2C - // + /* + * switch off I2C + */ i2c_data(1); i2c_disable(); i2c_dir_in(); - // - // wait before getting bit - // + /* + * wait before getting bit + */ i2c_delay(CLOCK_HIGH_TIME/2); aBitByte = (aBitByte << 1); iaa = i2c_getbit(); aBitByte = aBitByte | iaa ; - //if (iaa > 0) dd++; - // - // wait - // + /* + * wait + */ i2c_delay(CLOCK_HIGH_TIME/2); - // - // end clock puls - // + /* + * end clock puls + */ i2c_enable(); i2c_dir_out(); i2c_clk(I2C_CLOCK_LOW); - // - // low clock period - // + /* + * low clock period + */ i2c_delay(CLOCK_LOW_TIME/2); } i2c_dir_out(); @@ -305,49 +308,47 @@ *# *#--------------------------------------------------------------------------*/ -static int +int i2c_getack(void) { int ack = 1; - // - // enable output - // + /* + * enable output + */ i2c_dir_out(); - // - // Release data bus by setting - // data high - // + /* + * Release data bus by setting + * data high + */ i2c_data(I2C_DATA_HIGH); - // - // enable input - // + /* + * enable input + */ i2c_dir_in(); i2c_delay(CLOCK_HIGH_TIME/4); - // - // generate ACK clock pulse - // + /* + * generate ACK clock pulse + */ i2c_clk(I2C_CLOCK_HIGH); - // - // Use PORT PB instead of I2C - // for input. (I2C not working) - // + /* + * Use PORT PB instead of I2C + * for input. (I2C not working) + */ i2c_clk(1); i2c_data(1); - -/* *R_PORT_PB_DATA = *R_PORT_PB_READ | 0x03;*/ - // - // switch off I2C - // + /* + * switch off I2C + */ i2c_data(1); i2c_disable(); i2c_dir_in(); - // - // now wait for ack - // + /* + * now wait for ack + */ i2c_delay(CLOCK_HIGH_TIME/2); - // - // check for ack - // + /* + * check for ack + */ if(i2c_getbit()) ack = 0; i2c_delay(CLOCK_HIGH_TIME/2); @@ -357,20 +358,20 @@ i2c_delay(CLOCK_HIGH_TIME/2); } - // - // end clock pulse - // + /* + * end clock pulse + */ i2c_enable(); i2c_dir_out(); i2c_clk(I2C_CLOCK_LOW); i2c_delay(CLOCK_HIGH_TIME/4); - // - // enable output - // + /* + * enable output + */ i2c_dir_out(); - // - // remove ACK clock pulse - // + /* + * remove ACK clock pulse + */ i2c_data(I2C_DATA_HIGH); i2c_delay(CLOCK_LOW_TIME/2); return ack; @@ -383,32 +384,32 @@ *# DESCRIPTION : Send ACK on received data *# *#--------------------------------------------------------------------------*/ -static void +void i2c_sendack(void) { - // - // enable output - // + /* + * enable output + */ i2c_delay(CLOCK_LOW_TIME); i2c_dir_out(); - // - // set ack pulse high - // + /* + * set ack pulse high + */ i2c_data(I2C_DATA_LOW); - // - // generate clock pulse - // + /* + * generate clock pulse + */ i2c_delay(CLOCK_HIGH_TIME/6); i2c_clk(I2C_CLOCK_HIGH); i2c_delay(CLOCK_HIGH_TIME); i2c_clk(I2C_CLOCK_LOW); i2c_delay(CLOCK_LOW_TIME/6); - // - // reset data out - // + /* + * reset data out + */ i2c_data(I2C_DATA_HIGH); i2c_delay(CLOCK_LOW_TIME); - // + i2c_dir_in(); } @@ -424,20 +425,22 @@ unsigned char theValue) { int error, cntr = 3; + unsigned long flags; do { error = 0; - // - // we don't like to be interrupted - // + /* + * we don't like to be interrupted + */ + save_flags(flags); cli(); - // - // generate start condition - // + /* + * generate start condition + */ i2c_start(); - // - // dummy preamble - // + /* + * dummy preamble + */ i2c_outbyte(0x01); i2c_data(I2C_DATA_HIGH); i2c_clk(I2C_CLOCK_HIGH); @@ -452,42 +455,42 @@ i2c_delay(CLOCK_LOW_TIME); i2c_start(); - // - // send slave address - // + /* + * send slave address + */ i2c_outbyte(theSlave); - // - // wait for ack - // + /* + * wait for ack + */ if(!i2c_getack()) error = 1; - // - // now select register - // + /* + * now select register + */ i2c_dir_out(); i2c_outbyte(theReg); - // - // now it's time to wait for ack - // + /* + * now it's time to wait for ack + */ if(!i2c_getack()) error |= 2; - // - // send register register data - // + /* + * send register register data + */ i2c_outbyte(theValue); - // - // now it's time to wait for ack - // + /* + * now it's time to wait for ack + */ if(!i2c_getack()) error |= 4; - // - // end byte stream - // + /* + * end byte stream + */ i2c_stop(); - // - // enable interrupt again - // - sti(); + /* + * enable interrupt again + */ + restore_flags(flags); } while(error && cntr--); @@ -508,20 +511,22 @@ { unsigned char b = 0; int error, cntr = 3; + unsigned long flags; do { error = 0; - // - // we don't like to be interrupted - // + /* + * we don't like to be interrupted + */ + save_flags(flags); cli(); - // - // generate start condition - // + /* + * generate start condition + */ i2c_start(); - // - // dummy preamble - // + /* + * dummy preamble + */ i2c_outbyte(0x01); i2c_data(I2C_DATA_HIGH); i2c_clk(I2C_CLOCK_HIGH); @@ -537,55 +542,56 @@ i2c_start(); - // - // send slave address - // + /* + * send slave address + */ i2c_outbyte(theSlave); - // - // wait for ack - // + /* + * wait for ack + */ if(!i2c_getack()) error = 1; - // - // now select register - // + /* + * now select register + */ i2c_dir_out(); i2c_outbyte(theReg); - // - // now it's time to wait for ack - // + /* + * now it's time to wait for ack + */ if(!i2c_getack()) error = 1; - // - // repeat start condition - // + /* + * repeat start condition + */ i2c_delay(CLOCK_LOW_TIME); i2c_start(); - // - // send slave address - // + /* + * send slave address + */ i2c_outbyte(theSlave | 0x01); - // - // wait for ack - // + /* + * wait for ack + */ if(!i2c_getack()) error = 1; - // - // fetch register - // + /* + * fetch register + */ b = i2c_inbyte(); - // - // send Ack - // + /* + * send Ack + */ i2c_sendack(); - // - // end sequence - // + /* + * end sequence + */ i2c_stop(); - // - // enable interrupt again - // - sti(); + /* + * enable interrupt again + */ + restore_flags(flags); + } while(error && cntr--); return b; @@ -616,7 +622,7 @@ switch (_IOC_NR(cmd)) { case I2C_WRITEREG: - // write to an i2c slave + /* write to an i2c slave */ D(printk("i2cw %d %d %d\n", I2C_ARGSLAVE(arg), I2C_ARGREG(arg), @@ -628,7 +634,7 @@ case I2C_READREG: { unsigned char val; - // read from an i2c slave + /* read from an i2c slave */ D(printk("i2cr %d %d ", I2C_ARGSLAVE(arg), I2C_ARGREG(arg))); @@ -682,6 +688,8 @@ } printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); + + return 0; } /* this makes sure that i2c_init is called during boot */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/i2c.h linux/arch/cris/drivers/i2c.h --- v2.4.4/linux/arch/cris/drivers/i2c.h Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/i2c.h Sat May 19 17:43:05 2001 @@ -1,16 +1,16 @@ -/* $Id: i2c.h,v 1.2 2001/01/18 15:49:30 bjornw Exp $ */ +/* $Id: i2c.h,v 1.3 2001/03/19 12:43:01 markusl Exp $ */ /* High level I2C actions */ int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); /* Low level I2C */ -static void i2c_start(void); -static void i2c_stop(void); -static void i2c_outbyte(unsigned char x); -static unsigned char i2c_inbyte(void); -static int i2c_getack(void); -static void i2c_sendack(void); +void i2c_start(void); +void i2c_stop(void); +void i2c_outbyte(unsigned char x); +unsigned char i2c_inbyte(void); +int i2c_getack(void); +void i2c_sendack(void); diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c --- v2.4.4/linux/arch/cris/drivers/parport.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/parport.c Tue May 1 16:04:56 2001 @@ -0,0 +1,591 @@ +/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $ + * + * Elinux parallel port driver + * NOTE! + * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 + * this should be handled if both are enabled at the same time. + * THIS IS NOT HANDLED YET! + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Fredrik Hugosson + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK(void *nothing, ...) {return 0;} +#endif + +/* + * Etrax100 DMAchannels: + * Par0 out : DMA2 + * Par0 in : DMA3 + * Par1 out : DMA4 + * Par1 in : DMA5 + * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding + * DMA and DMA irq + */ + +//#define CONFIG_PAR0_INT 1 +//#define CONFIG_PAR1_INT 1 + +#define SETF(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val) + +#define SETS(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val) + +struct etrax100par_struct { + /* parallell port control */ + volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ + const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ + volatile u32 *reg_config; /* R_PARx_CONFIG */ + volatile u32 *reg_delay; /* R_PARx_DELAY */ + + /* DMA control */ + int odma; + unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + + volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + + /* Non DMA interrupt stuff */ + unsigned long int_irq; /* R_VECT_MASK_RD */ + const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ + volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ + const volatile u32 *irq_read; /* R_IRQ_READX */ + volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ + unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ + unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ + unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ + unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ + int portnr; + + /* ----- end of fields initialised in port_table[] below ----- */ + + // struct etrax_dma_descr tr_descr; + // unsigned char tr_buf[LP_BUFFER_SIZE]; + // const unsigned char *tr_buf_curr; /* current char sent */ + // const unsigned char *tr_buf_last; /* last char in buf */ + + // int fifo_magic; /* fifo amount - bytes left in dma buffer */ + // unsigned char fifo_didmagic; /* a fifo eop has been forced */ + // volatile int tr_running; /* 1 if output is running */ + + struct parport *port; + + /* Shadow registers */ + volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ + volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ + volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */ +}; + +/* Always have the complete structs here, even if the port is not used! + * (that way we can index this by the port number) + */ +static struct etrax100par_struct port_table[] = { + { + R_PAR0_CTRL_DATA, + R_PAR0_STATUS_DATA, + R_PAR0_CONFIG, + R_PAR0_DELAY, + /* DMA interrupt stuff */ + 2, + 1U << 4, /* uses DMA 2 and 3 */ + R_DMA_CH2_CLR_INTR, + R_DMA_CH2_FIRST, + R_DMA_CH2_CMD, + R_DMA_CH3_CLR_INTR, + R_DMA_CH3_FIRST, + R_DMA_CH3_CMD, + R_DMA_CH3_STATUS, + R_DMA_CH3_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par0), + R_IRQ_MASK0_RD, + R_IRQ_MASK0_CLR, + R_IRQ_READ0, + R_IRQ_MASK0_SET, + IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ + 0 + }, + { + R_PAR1_CTRL_DATA, + R_PAR1_STATUS_DATA, + R_PAR1_CONFIG, + R_PAR1_DELAY, + /* DMA interrupt stuff */ + 4, + 1U << 8, /* uses DMA 4 and 5 */ + + R_DMA_CH4_CLR_INTR, + R_DMA_CH4_FIRST, + R_DMA_CH4_CMD, + R_DMA_CH5_CLR_INTR, + R_DMA_CH5_FIRST, + R_DMA_CH5_CMD, + R_DMA_CH5_STATUS, + R_DMA_CH5_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par1), + R_IRQ_MASK1_RD, + R_IRQ_MASK1_CLR, + R_IRQ_READ1, + R_IRQ_MASK1_SET, + IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ + 1 + } +}; + + +#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct)) + +static void +parport_etrax_write_data(struct parport *p, unsigned char value) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_data(struct parport *p) +{ + unsigned char ret; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); + + DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_write_control(struct parport *p, unsigned char control) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); + + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, + (control & PARPORT_CONTROL_STROBE) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, + (control & PARPORT_CONTROL_AUTOFD) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, + (control & PARPORT_CONTROL_INIT) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, + (control & PARPORT_CONTROL_SELECT) > 0); + + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_control( struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_STROBE; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_AUTOFD; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_INIT; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_SELECT; + + DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); + return ret; +} + + +static unsigned char +parport_etrax_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + unsigned char old; + + DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", + p->portnum, mask, val); + old = parport_etrax_read_control(p); + parport_etrax_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char +parport_etrax_read_status(struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) + ret |= PARPORT_STATUS_ERROR; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) + ret |= PARPORT_STATUS_SELECT; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) + ret |= PARPORT_STATUS_PAPEROUT; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) + ret |= PARPORT_STATUS_ACK; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) + ret |= PARPORT_STATUS_BUSY; + + DPRINTK("* E100 PP %d: status register %04x\n", + p->portnum, *info->reg_status_data); + DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_enable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_set = info->irq_mask_tx; + DPRINTK("* E100 PP %d: enable irq\n", p->portnum); +} + + +static void +parport_etrax_disable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_clr = info->irq_mask_tx; + DPRINTK("* E100 PP %d: disable irq\n", p->portnum); +} + + +static void +parport_etrax_data_forward(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: forward mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_data_reverse(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: reverse mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_init_state(struct pardevice *dev, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_init_state\n"); +} + + +static void +parport_etrax_save_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_save_state\n"); +} + + +static void +parport_etrax_restore_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_restore_state\n"); +} + + +static void +parport_etrax_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + + +static void +parport_etrax_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + + +static struct +parport_operations pp_etrax_ops = { + parport_etrax_write_data, + parport_etrax_read_data, + + parport_etrax_write_control, + parport_etrax_read_control, + parport_etrax_frob_control, + + parport_etrax_read_status, + + parport_etrax_enable_irq, + parport_etrax_disable_irq, + + parport_etrax_data_forward, + parport_etrax_data_reverse, + + parport_etrax_init_state, + parport_etrax_save_state, + parport_etrax_restore_state, + + parport_etrax_inc_use_count, + parport_etrax_dec_use_count, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, +}; + + +static void +parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct etrax100par_struct *info = (struct etrax100par_struct *) + ((struct parport *)dev_id)->private_data; + DPRINTK("* E100 PP %d: Interrupt received\n", + ((struct parport *)dev_id)->portnum); + *info->irq_mask_clr = info->irq_mask_tx; + parport_generic_irq(irq, (struct parport *)dev_id, regs); +} + +/* ----------- Initialisation code --------------------------------- */ + +static void +parport_etrax_show_parallel_version(void) +{ + printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); +} + +#ifdef CONFIG_ETRAX_PAR0_DMA +#define PAR0_USE_DMA 1 +#else +#define PAR0_USE_DMA 0 +#endif + +#ifdef CONFIG_ETRAX_PAR1_DMA +#define PAR1_USE_DMA 1 +#else +#define PAR1_USE_DMA 0 +#endif + +static void +parport_etrax_init_registers(void) +{ + struct etrax100par_struct *info; + int i; + + /* The different times below will be (value*160 + 20) ns, */ + /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6), */ + /* the setup time will be (6*160+20) = 980ns. */ + + for (i = 0, info = port_table; i < 2; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + info->reg_config_shadow = + IO_STATE(R_PAR0_CONFIG, iseli, inv) | + IO_STATE(R_PAR0_CONFIG, iautofd, inv) | + IO_STATE(R_PAR0_CONFIG, istrb, inv) | + IO_STATE(R_PAR0_CONFIG, iinit, inv) | + IO_STATE(R_PAR0_CONFIG, rle_in, disable) | + IO_STATE(R_PAR0_CONFIG, rle_out, disable) | + IO_STATE(R_PAR0_CONFIG, enable, on) | + IO_STATE(R_PAR0_CONFIG, force, off) | + IO_STATE(R_PAR0_CONFIG, ign_ack, wait) | + IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe) | + IO_STATE(R_PAR0_CONFIG, mode, manual); + + if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA)) + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, enable); + else + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, disable); + + *info->reg_config = info->reg_config_shadow; + + info->reg_ctrl_data_shadow = + IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop) | + IO_STATE(R_PAR0_CTRL_DATA, oe, enable) | + IO_STATE(R_PAR0_CTRL_DATA, seli, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, strb, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, init, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data) | + IO_FIELD(R_PAR0_CTRL_DATA, data, 0); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; + + /* Clear peri int without setting shadow */ + *info->reg_ctrl_data = info->reg_ctrl_data_shadow | + IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack); + + info->reg_delay_shadow = + IO_FIELD(R_PAR0_DELAY, setup, 5) | + IO_FIELD(R_PAR0_DELAY, strobe, 5) | + IO_FIELD(R_PAR0_DELAY, hold, 5); + *info->reg_delay = info->reg_delay_shadow; + } + +#ifdef CONFIG_ETRAX_PARALLEL_PORT0 +#ifdef CONFIG_ETRAX_PAR0_DMA + RESET_DMA(2); + WAIT_DMA(2); +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + printk(" Warning - DMA clash with ser2!\n"); +#endif /* SERIAL_PORT2 */ +#endif /* DMA */ +#endif /* PORT0 */ + +#ifdef CONFIG_ETRAX_PARALLEL_PORT1 +#ifdef CONFIG_ETRAX_PAR1_DMA + RESET_DMA(4); + WAIT_DMA(4); +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + printk(" Warning - DMA clash with ser3!\n"); +#endif /* SERIAL_PORT3 */ +#endif /* DMA */ +#endif /* PORT1 */ +} + + +int __init +parport_etrax_init(void) +{ + struct parport *p; + int port_exists = 0; + int i; + struct etrax100par_struct *info; + const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" }; + + parport_etrax_show_parallel_version(); + parport_etrax_init_registers(); + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + p = parport_register_port((unsigned long)0, info->int_irq, + PARPORT_DMA_NONE, &pp_etrax_ops); + if (!p) + continue; + + info->port = p; + p->private_data = info; + /* Axis FIXME: Set mode flags. */ + /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */ + + if(request_irq(info->int_irq, parport_etrax_interrupt, + SA_SHIRQ, names[i], p)) { + parport_unregister_port (p); + continue; + } + + printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n", + p->name, i); + parport_proc_register(p); + parport_announce_port(p); + port_exists = 1; + } + + return port_exists; +} + +void __exit +parport_etrax_exit(void) +{ + int i; + struct etrax100par_struct *info; + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + if (info->int_irq != PARPORT_IRQ_NONE) + free_irq(info->int_irq, info->port); + parport_proc_unregister(info->port); + parport_unregister_port(info->port); + } +} diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.4/linux/arch/cris/drivers/serial.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/serial.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.10 2001/03/05 13:14:07 bjornw Exp $ +/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,15 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.12 2001/04/19 12:23:07 bjornw + * CONFIG_RS485 -> CONFIG_ETRAX_RS485 + * + * Revision 1.11 2001/04/05 14:29:48 markusl + * Updated according to review remarks i.e. + * -Use correct types in port structure to avoid compiler warnings + * -Try to use IO_* macros whenever possible + * -Open should never return -EBUSY + * * Revision 1.10 2001/03/05 13:14:07 bjornw * Another spelling fix * @@ -190,7 +199,7 @@ * */ -static char *serial_version = "$Revision: 1.10 $"; +static char *serial_version = "$Revision: 1.12 $"; #include #include @@ -299,6 +308,18 @@ #define REG_BAUD 3 #define REG_XOFF 4 /* this is a 32 bit register */ +/* + * General note regarding the use of IO_* macros in this file: + * + * We will use the bits defined for DMA channel 6 when using various + * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are + * the same for all channels (which of course they are). + * + * We will also use the bits defined for serial port 0 when writing commands + * to the different ports, as these bits too are the same for all ports. + */ + + /* this is the data for the four serial ports in the etrax100 */ /* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ /* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ @@ -343,9 +364,9 @@ /* RS-485 */ -#if defined(CONFIG_RS485) -#if defined(CONFIG_RS485_ON_PA) -static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) +#if defined(CONFIG_ETRAX_RS485_ON_PA) +static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #endif @@ -421,8 +442,8 @@ } }; -#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA) -unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA) +unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #define E100_RTS_MASK 0x20 @@ -668,7 +689,8 @@ { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl &= + ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -677,7 +699,8 @@ { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl |= + IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -747,14 +770,14 @@ } #endif -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif @@ -766,7 +789,6 @@ return 0; } -/* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) { @@ -782,7 +804,7 @@ * the receiver before initiating a DMA transfer */ e100_rts(info, info->rs485.rts_on_send); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_disable_rx(info); e100_disable_rxdma_irq(info); #endif @@ -824,14 +846,16 @@ max_j = jiffies + (delay_ms * HZ)/1000 + 10; while (jiffies < max_j ) { - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { for( i=0 ; i<100; i++ ) {}; - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { /* ~25 for loops per usec */ - stop_delay = 25 * (1000000 / info->baud); + stop_delay = 1000000 / info->baud; if(cflags & CSTOPB) stop_delay *= 2; - for( i=0 ; irs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -942,7 +966,9 @@ return; #endif /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->oclrintradr = 3; + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); #ifdef SERIAL_DEBUG_INTR if(info->line == SERIAL_DEBUG_LINE) @@ -987,19 +1013,20 @@ /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Check if we should toggle RTS now */ if (info->rs485.enabled) { /* Make sure fifo is empty */ int in_fifo = 0 ; do{ - in_fifo = (*info->ostatusadr) & 0x007F ; + in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, + *info->ostatusadr); } while (in_fifo > 0) ; /* Any way to really check transmitter empty? (TEMT) */ /* Control RTS to set to RX mode */ e100_rts(info, info->rs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -1060,7 +1087,9 @@ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->iclrintradr = 3; + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if(!tty) /* something wrong... */ return; @@ -1088,7 +1117,9 @@ /* read the status register so we can detect errors */ rstat = info->port[REG_STATUS]; - if(rstat & 0xe) { + if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) | + IO_MASK(R_SERIAL0_STATUS, par_err) | + IO_MASK(R_SERIAL0_STATUS, framing_err))) { /* if we got an error, we must reset it by reading the * data_in field */ @@ -1148,7 +1179,7 @@ descr->status = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); #ifdef SERIAL_HANDLE_EARLY_ERRORS e100_enable_serial_data_irq(info); @@ -1170,8 +1201,9 @@ /* reset the input dma channel to be sure it works */ - *info->icmdadr = 4; - while((*info->icmdadr & 7) == 4); + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); descr = &info->rec_descr; @@ -1186,7 +1218,8 @@ info->tty->flip.count = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); + } @@ -1293,7 +1326,7 @@ static struct timer_list flush_timer; static void -timed_flush_handler(void) +timed_flush_handler(unsigned long ptr) { struct e100_serial *info; int i; @@ -1381,7 +1414,7 @@ PROCSTAT(early_errors_cnt[info->line]++); /* restart the DMA */ - *info->icmdadr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); } else { /* it was a valid byte, now let the dma do the rest */ #ifdef SERIAL_DEBUG_INTR @@ -1472,7 +1505,7 @@ if (info->flags & ASYNC_INITIALIZED) { free_page(page); restore_flags(flags); - return -EBUSY; + return 0; } if (info->xmit.buf) @@ -1518,14 +1551,22 @@ * Reset the DMA channels and make sure their interrupts are cleared */ - *info->icmdadr = 4; /* reset command */ - *info->ocmdadr = 4; /* reset command */ - - while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */ - while((*info->ocmdadr & 7) == 4); - - *info->iclrintradr = 3; /* make sure the irqs are cleared */ - *info->oclrintradr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + + /* wait until reset cycle is complete */ + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1597,8 +1638,8 @@ /* reset both dma channels */ - *info->icmdadr = 4; - *info->ocmdadr = 4; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); #endif /* CONFIG_SVINTO_SIM */ @@ -1658,42 +1699,51 @@ #ifndef CONFIG_SVINTO_SIM info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); /* start with default settings and then fill in changes */ - - info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */ - info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */ + + /* 8 bit, no/even parity */ + info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); + + /* 8 bit, no/even parity, 1 stop bit, no cts */ + info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | + IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | + IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); if ((cflag & CSIZE) == CS7) { /* set 7 bit mode */ - info->tx_ctrl |= 0x01; - info->rx_ctrl |= 0x01; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); } if (cflag & CSTOPB) { /* set 2 stop bit mode */ - info->tx_ctrl |= 0x10; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); } if (cflag & PARENB) { /* enable parity */ - info->tx_ctrl |= 0x02; - info->rx_ctrl |= 0x02; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); } if (cflag & PARODD) { /* set odd parity */ - info->tx_ctrl |= 0x04; - info->rx_ctrl |= 0x04; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); } if (cflag & CRTSCTS) { /* enable automatic CTS handling */ - info->tx_ctrl |= 0x20; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); } /* make sure the tx and rx are enabled */ - info->tx_ctrl |= 0x40; - info->rx_ctrl |= 0x40; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); /* actually write the control regs to the hardware */ @@ -2330,7 +2380,7 @@ return -EFAULT; return 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct rs485_control)); @@ -2488,10 +2538,10 @@ /* port closed */ -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) if (info->rs485.enabled) { info->rs485.enabled = 0; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif } diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h --- v2.4.4/linux/arch/cris/drivers/serial.h Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/serial.h Tue May 1 16:04:56 2001 @@ -25,26 +25,26 @@ struct e100_serial { int baud; - volatile unsigned char * port; /* R_SERIALx_CTRL */ - unsigned long irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + volatile u8 *port; /* R_SERIALx_CTRL */ + u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile unsigned long *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - const volatile unsigned short *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ - volatile unsigned long *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ + volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ + volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ - volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile unsigned long *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - const volatile unsigned short *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ - volatile unsigned long *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ int flags; /* defined in tty.h */ - unsigned char rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - unsigned char tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - unsigned char iseteop; /* bit number for R_SET_EOP for the input dma */ + u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + u8 iseteop; /* bit number for R_SET_EOP for the input dma */ /* end of fields defined in rs_table[] in .c-file */ unsigned char fifo_didmagic; /* a fifo eop has been forced */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c --- v2.4.4/linux/arch/cris/drivers/sync_serial.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/sync_serial.c Tue May 1 16:04:56 2001 @@ -2,8 +2,9 @@ * Simple synchronous serial port driver for ETRAX 100LX. * * Synchronous serial ports are used for continous streamed data like audio. - * The deault setting for this driver is compatible with the STA 013 MP3 decoder - * The driver can easily be tuned to fit other audio encoder/decoders and SPI + * The default setting for this driver is compatible with the STA 013 MP3 + * decoder. The driver can easily be tuned to fit other audio encoder/decoders + * and SPI * * Copyright (c) 2001 Axis Communications AB * @@ -29,37 +30,43 @@ #include /* The receiver is a bit tricky beacuse of the continous stream of data. */ -/* */ -/* Two DMA descriptors are linked together. Each DMA descriptor is */ -/* responsible for one half of a common buffer. */ -/* */ -/* ------------------------------ */ -/* | ---------- ---------- | */ -/* --> | Descr1 |-->| Descr2 |--- */ -/* ---------- ---------- */ -/* | | */ -/* v v */ -/* ----------------------------- */ -/*  | BUFFER | */ -/* ----------------------------- */ -/* | | */ -/* readp writep */ -/* */ +/* */ +/* Two DMA descriptors are linked together. Each DMA descriptor is */ +/* responsible for one half of a common buffer. */ +/* */ +/* ------------------------------ */ +/* | ---------- ---------- | */ +/* --> | Descr1 |-->| Descr2 |--- */ +/* ---------- ---------- */ +/* | | */ +/* v v */ +/* ----------------------------- */ +/* | BUFFER | */ +/* ----------------------------- */ +/* | | */ +/* readp writep */ +/* */ /* If the application keeps up the pace readp will be right after writep.*/ -/* If the application can't keep the pace we have to throw away data. */ +/* If the application can't keep the pace we have to throw away data. */ /* The idea is that readp should be ready with the data pointed out by */ /* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ /* the rest of the data pointed out by Descr1 and set readp to the start */ -/* of Descr2 */ +/* of Descr2 */ #define SYNC_SERIAL_MAJOR 125 -#define IN_BUFFER_SIZE 8192 +/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ +/* words can be handled */ + +#define IN_BUFFER_SIZE 12288 #define OUT_BUFFER_SIZE 4096 +#define DEFAULT_FRAME_RATE 0 +#define DEFAULT_WORD_RATE 7 + #define DEBUG(x) -/* Define some macros to access Etrax 100 registers */ +/* Define some macros to access ETRAX 100 registers */ #define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ IO_FIELD(##reg##, field, val) #define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ @@ -81,10 +88,8 @@ char data_avail_bit; /* In R_IRQ_MASK1_RD */ char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ - char input_dma_eop_bit; /* In R_IRQ_MASK2_RD */ char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ char output_dma_bit; /* In R_IRQ_MASK2_RD */ - char eop_bit; /* In R_SET_EOP */ int enabled; /* 1 if port is enabled */ int use_dma; /* 1 if port uses dma */ @@ -125,7 +130,6 @@ static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void flush_handler(void); /* The ports */ static struct sync_port ports[]= @@ -133,40 +137,36 @@ { R_SYNC_SERIAL1_STATUS, /* status */ R_SYNC_SERIAL1_CTRL, /* ctrl_data */ - R_DMA_CH8_FIRST, /* output_dma_first */ - R_DMA_CH8_CMD, /* output_dma_cmd */ - R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH9_FIRST, /* input_dma_first */ - R_DMA_CH9_CMD, /* input_dma_cmd */ - R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ + R_DMA_CH8_FIRST, /* output_dma_first */ + R_DMA_CH8_CMD, /* output_dma_cmd */ + R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH9_FIRST, /* input_dma_first */ + R_DMA_CH9_CMD, /* input_dma_cmd */ + R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ R_SYNC_SERIAL1_TR_DATA, /* data_out */ R_SYNC_SERIAL1_REC_DATA,/* data in */ IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma9_eop), /* input_dma_eop_bit */ IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ - IO_BITNR(R_SET_EOP, ch9_eop) /* eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ }, { R_SYNC_SERIAL3_STATUS, /* status */ R_SYNC_SERIAL3_CTRL, /* ctrl_data */ - R_DMA_CH4_FIRST, /* output_dma_first */ - R_DMA_CH4_CMD, /* output_dma_cmd */ - R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH5_FIRST, /* input_dma_first */ - R_DMA_CH5_CMD, /* input_dma_cmd */ - R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ + R_DMA_CH4_FIRST, /* output_dma_first */ + R_DMA_CH4_CMD, /* output_dma_cmd */ + R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH5_FIRST, /* input_dma_first */ + R_DMA_CH5_CMD, /* input_dma_cmd */ + R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ R_SYNC_SERIAL3_TR_DATA, /* data_out */ R_SYNC_SERIAL3_REC_DATA,/* data in */ IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_eop), /* input_dma_eop_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_eop_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ - IO_BITNR(R_SET_EOP, ch5_eop) /* eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ } }; @@ -174,9 +174,6 @@ static unsigned sync_serial_prescale_shadow = 0; static unsigned gen_config_ii_shadow = 0; -/* Timer used to flush data from the DMA */ -static struct timer_list flush_timer; - #define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) static struct file_operations sync_serial_fops = { @@ -213,24 +210,25 @@ #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) ports[0].use_dma = 1; initialize_port(0); - if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", NULL)) + if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0])) panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL)) + if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) panic("Can't allocate sync serial port 1 IRQ"); RESET_DMA(8); WAIT_DMA(8); RESET_DMA(9); WAIT_DMA(9); - *R_DMA_CH8_CLR_INTR = 3; /* Clear IRQ */ - *R_DMA_CH9_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); start_dma_in(&ports[0]); #else ports[0].use_dma = 0; initialize_port(0); - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0])) panic("Can't allocate sync serial manual irq"); *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); #endif @@ -243,18 +241,19 @@ #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) ports[1].use_dma = 1; initialize_port(1); - if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", NULL)) + if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1])) panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL)) + if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1])) panic("Can't allocate sync serial port 1 IRQ"); RESET_DMA(4); WAIT_DMA(4); RESET_DMA(5); WAIT_DMA(5); - *R_DMA_CH4_CLR_INTR = 3; /* Clear IRQ */ - *R_DMA_CH5_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); start_dma_in(&ports[1]); #else @@ -262,7 +261,7 @@ initialize_port(1); if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ { - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1])) panic("Can't allocate sync serial manual irq"); } *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); @@ -278,22 +277,14 @@ IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, 0) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); /* Select synchronous ports */ *R_GEN_CONFIG_II = gen_config_ii_shadow; - /*Initialize DMA flush timer if dma is used */ - if (ports[0].use_dma || ports[1].use_dma) - { - init_timer(&flush_timer); - flush_timer.function = flush_handler; - mod_timer(&flush_timer, jiffies + 10); - } - - printk("Etrax100LX synchronous serial port driver\n"); + printk("ETRAX 100LX synchronous serial port driver\n"); return 0; } @@ -321,9 +312,9 @@ IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, running) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped) | IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable) | IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | @@ -365,27 +356,43 @@ static int sync_serial_release(struct inode *inode, struct file *file) { - ports[MINOR(inode->i_rdev)].busy = 0; + int dev = MINOR(inode->i_rdev); + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + ports[dev].busy = 0; return 0; } static int sync_serial_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int return_val = 0; int dev = MINOR(file->f_dentry->d_inode->i_rdev); - sync_port* port = &ports[dev]; + sync_port* port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -1; + } + port = &ports[dev]; /* Disable port while changing config */ if (dev) { RESET_DMA(4); WAIT_DMA(4); - *R_DMA_CH4_CLR_INTR = 3; + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); } else { RESET_DMA(8); WAIT_DMA(8); - *R_DMA_CH8_CLR_INTR = 3; + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); } *R_GEN_CONFIG_II = gen_config_ii_shadow; @@ -516,7 +523,7 @@ } break; default: - return -EINVAL; + return_val = -1; } /* Set config and enable port */ *port->ctrl_data = port->ctrl_data_shadow; @@ -527,15 +534,23 @@ SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); *R_GEN_CONFIG_II = gen_config_ii_shadow; - return 0; + return return_val; } static ssize_t sync_serial_manual_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + int dev = MINOR(file->f_dentry->d_inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + sync_port* port; + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + + port = &ports[dev]; copy_from_user(port->out_buffer, buf, count); port->outp = port->out_buffer; port->out_count = count; @@ -547,17 +562,36 @@ schedule(); set_current_state(TASK_RUNNING); remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } return count; } static ssize_t sync_serial_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { - DECLARE_WAITQUEUE(wait, current); - sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + sync_port *port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); + count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count; + + /* Make sure transmitter is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; + if (!port->use_dma) { return sync_serial_manual_write(file, buf, count, ppos); @@ -570,26 +604,47 @@ schedule(); set_current_state(TASK_RUNNING); remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } return count; } static ssize_t sync_serial_read(struct file * file, char * buf, size_t count, loff_t *ppos) { + int dev = MINOR(file->f_dentry->d_inode->i_rdev); int avail; - sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + sync_port *port; char* start; char* end; unsigned long flags; - DEBUG(printk("Read dev %d count\n")); + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; + + DEBUG(printk("Read dev %d count %d\n", dev, count)); + + /* Make sure receiver is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; /* Calculate number of available bytes */ while (port->readp == port->writep) /* No data */ { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + interruptible_sleep_on(&port->in_wait_q); + if (signal_pending(current)) + { + return -EINTR; + } } /* Save pointers to avoid that they are modified by interrupt */ @@ -673,12 +728,12 @@ return; } port->in_descr1.hw_len = 0; - port->in_descr1.ctrl = d_eop | d_int; + port->in_descr1.ctrl = d_int; port->in_descr1.status = 0; port->in_descr1.next = virt_to_phys(&port->in_descr2); port->in_descr2.hw_len = 0; port->in_descr2.next = virt_to_phys(&port->in_descr1); - port->in_descr2.ctrl = d_eop | d_int; + port->in_descr2.ctrl = d_int; port->in_descr2.status = 0; /* Find out which descriptor to start */ @@ -766,22 +821,6 @@ start_dma_in(port); wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ } - else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */ - { - /* EOP interrupt means that DMA has not reached end of descriptor */ - *port->input_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - - /* Find out the current descriptor */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - port->writep += port->in_descr2.hw_len; - else - port->writep += port->in_descr1.hw_len; - - start_dma_in(port); - wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ - } } } @@ -853,21 +892,6 @@ } } } -} - -static void flush_handler(void) -{ - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - if (ports[i].enabled) - { - *R_SET_EOP = 1 << ports[i].eop_bit; - } - } - /* restart flush timer */ - mod_timer(&flush_timer, jiffies + 10); } module_init(etrax_sync_serial_init); diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c --- v2.4.4/linux/arch/cris/drivers/usb-host.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/usb-host.c Tue May 1 16:04:56 2001 @@ -623,7 +623,7 @@ traffic_ep->nep = tmp_ep->nep; tmp_ep->nep = virt_to_phys(traffic_ep); - dbg_intr("One ep successfully inserted"); + dbg_intr("One ep sucessfully inserted"); } i++; } @@ -1804,7 +1804,7 @@ r_usb_ept_data); if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* no_error means that this urb was successfully sent or that we have + /* no_error means that this urb was sucessfully sent or that we have some undefinde error*/ if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || @@ -1888,9 +1888,9 @@ /* This means that the endpoint has no error, is disabled and had inserted traffic, - i.e. transfer successfully completed + i.e. transfer sucessfully completed */ - dbg_ctrl("Last SB for CTRL %d sent successfully", epid); + dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); handle_control_transfer_attn(epid, 0); } } @@ -1905,9 +1905,9 @@ /* This means that the endpoint has no error, is disabled and had inserted traffic, - i.e. transfer successfully completed + i.e. transfer sucessfully completed */ - dbg_bulk("Last SB for BULK %d sent successfully", epid); + dbg_bulk("Last SB for BULK %d sent sucessfully", epid); handle_bulk_transfer_attn(epid, 0); } } diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.4/linux/arch/cris/kernel/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/Makefile Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $ +# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $ # # Makefile for the linux kernel. # @@ -18,7 +18,7 @@ ptrace.o setup.o time.o sys_cris.o shadows.o \ debugport.o semaphore.o -obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_ETRAX_KGDB) += kgdb.o clean: diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/debugport.c linux/arch/cris/kernel/debugport.c --- v2.4.4/linux/arch/cris/kernel/debugport.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/debugport.c Tue May 1 16:04:56 2001 @@ -12,6 +12,12 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.6 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.5 2001/03/26 14:22:05 bjornw + * Namechange of some config options + * * Revision 1.4 2000/10/06 12:37:26 bjornw * Use physical addresses when talking to DMA * @@ -29,7 +35,7 @@ /* Which serial-port is our debug port ? */ -#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL) +#if defined(CONFIG_ETRAX_DEBUG_PORT0) || defined(CONFIG_ETRAX_DEBUG_PORT_NULL) #define DEBUG_PORT_IDX 0 #define DEBUG_OCMD R_DMA_CH6_CMD #define DEBUG_FIRST R_DMA_CH6_FIRST @@ -43,7 +49,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 #define DEBUG_PORT_IDX 1 #define DEBUG_OCMD R_DMA_CH8_CMD #define DEBUG_FIRST R_DMA_CH8_FIRST @@ -57,7 +63,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 #define DEBUG_PORT_IDX 2 #define DEBUG_OCMD R_DMA_CH2_CMD #define DEBUG_FIRST R_DMA_CH2_FIRST @@ -71,7 +77,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 #define DEBUG_PORT_IDX 3 #define DEBUG_OCMD R_DMA_CH4_CMD #define DEBUG_FIRST R_DMA_CH4_FIRST @@ -97,7 +103,7 @@ unsigned long flags; int in_progress; -#ifdef CONFIG_DEBUG_PORT_NULL +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL /* no debug printout at all */ return; #endif @@ -111,7 +117,7 @@ save_flags(flags); cli(); -#ifdef CONFIG_KGDB +#ifdef CONFIG_ETRAX_KGDB /* kgdb needs to output debug info using the gdb protocol */ putDebugString(buf, len); restore_flags(flags); diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.4/linux/arch/cris/kernel/entry.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/entry.S Sun May 20 12:11:38 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw Exp $ +/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,40 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.22 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.21 2001/04/17 11:33:29 orjanf + * Updated according to review: + * * Included asm/sv_addr_ag.h to get macro for internal register. + * * Corrected comment regarding system call argument passing. + * * Removed comment about instruction being in a delay slot. + * * Added comment about SYMBOL_NAME macro. + * + * Revision 1.20 2001/04/12 08:51:07 hp + * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ... + * - .rept to fill table to safe state with sys_ni_syscall. + * + * Revision 1.19 2001/04/04 09:43:32 orjanf + * * Moved do_sigtrap from traps.c to entry.S. + * * LTASK_PID need not be global anymore. + * + * Revision 1.18 2001/03/26 09:25:02 markusl + * Updated after review, should now handle USB interrupts correctly. + * + * Revision 1.17 2001/03/21 16:12:55 bjornw + * * Always make room for the cpu status record in the frame, in order to + * use the same framelength and layout for both mmu busfaults and normal + * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore. + * * Fixed bug with using addq for popping the stack in the epilogue - it + * destroyed the flag register. Use instructions that don't affect the + * flag register instead. + * * Removed write to R_PORT_PA_DATA during spurious_interrupt + * + * Revision 1.16 2001/03/20 19:43:02 bjornw + * * Get rid of esp0 setting + * * Give a 7th argument to a systemcall - the stackframe + * * Revision 1.15 2001/03/05 13:14:30 bjornw * Spelling fix * @@ -78,9 +112,11 @@ * */ +#include #include #include - +#include + ;; functions exported from this file .globl _system_call @@ -95,10 +131,11 @@ .globl _spurious_interrupt .globl _hw_bp_trigs .globl _mmu_bus_fault - + .globl _do_sigtrap + .globl _gdb_handle_breakpoint + .globl _sys_call_table - .globl LTASK_PID ;; syscall error codes LENOSYS = 38 @@ -115,11 +152,6 @@ PT_TRACESYS_BIT = 1 - ;; Offset for esp0 into task_struct: current->thread.esp0. - ;; FIXME: In need of padding somewhere, to get dword-alignment. - -THREAD_ESP0 = 597 - ;; some pt_regs offsets (from ptrace.h) LORIG_R10 = 4 @@ -182,7 +214,7 @@ ;; Since we can't have system calls inside interrupts, it should not matter ;; that we don't stack IRP. ;; - ;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0 + ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp ;; ;; This function looks on the _surface_ like spaghetti programming, but it's ;; really designed so that the fast-path does not force cache-loading of non-used @@ -190,7 +222,7 @@ _system_call: ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call - push brp ; this is normally push irp + move brp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -202,15 +234,11 @@ movs.w -LENOSYS,r0 move.d r0,[sp+LR10] ; put the default return value in r10 in the frame - ;; Perform "current->thread.esp0 = sp". - ;; This used to be a separate function; set_esp0(ssp). - movs.w -8192,r0 ; THREAD_SIZE == 8192 - and.d sp,r0 - - move.d sp,[r0+THREAD_ESP0] - ;; check if this process is syscall-traced + movs.w -8192,r0 ; THREAD_SIZE == 8192 + and.d sp,r0 + move.d [r0+LTASK_PTRACE],r0 btstq PT_TRACESYS_BIT, r0 bmi tracesys @@ -222,6 +250,11 @@ bcc _ret_from_sys_call lslq 2,r9 ; multiply by 4, in the delay slot + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. + + push sp + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. ;; the fifth and sixth parameters (if any) was in mof and srp ;; respectively, and we need to put them on the stack. @@ -230,8 +263,8 @@ push mof jsr [r9+_sys_call_table] ; actually do the system call - addq 2*4,sp ; pop the mof and srp parameters - move.d r10,[sp+LR10] ; save the return value + addq 3*4,sp ; pop the mof, srp and regs parameters + move.d r10,[sp+LR10] ; save the return value moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call @@ -274,31 +307,20 @@ pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer - jmpu [sp+] ; return by popping irp and jumping there - ;; jmpu takes the U-flag into account to see if we return to - ;; user-mode or kernel mode. + ;; now we have a 4-word SBFS frame which we do not want to restore + ;; using RBF since it was not stacked with SBFS. instead we would like to + ;; just get the PC value to restart it with, and skip the rest of + ;; the frame. + move [sp=sp+16], p8 ; pop the SBFS frame from the sp + jmpu [sp-16] ; return through the irp field in the sbfs frame RBFexit: - cmpq 2, r10 ; was it CRIS_FRAME_FIXUP ? - beq 2f movem [sp+],r13 ; registers r0-r13, in delay slot pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer rbf [sp+] ; return by popping the CPU status -2: pop mof ; multiply overflow register - pop dccr ; condition codes - pop srp ; subroutine return pointer - ;; now we have a 4-word SBFS frame which we do not want to restore - ;; using RBF since we have made a fixup. instead we would like to - ;; just get the PC value to restart it with, and skip the rest of - ;; the frame. - pop irp ; fixup location will be here - reti ; return to IRP, taking U-flag into account - addq 12,sp ; Skip rest of SBFS frame. - - tracesys: ;; this first invocation of syscall_trace _requires_ that ;; LR10 in the frame contains -LENOSYS (as is set in the beginning @@ -332,13 +354,19 @@ move [sp+LMOF], mof move [sp+LSRP], srp + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. + + push sp + ;; the fifth and sixth parameters needs to be put on the stack for ;; the system call to find them push srp push mof + jsr r9 ; actually call the system-call - addq 2*4,sp ; pop the r0 parameter + addq 3*4,sp ; pop the srp, mof and regs parameters 1: move.d r10,[sp+LR10] ; save the return value @@ -354,8 +382,7 @@ LTHREAD_KSP = 0 LTHREAD_USP = 4 -LTHREAD_ESP0 = 8 -LTHREAD_DCCR = 12 +LTHREAD_DCCR = 8 ;; _resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct @@ -468,8 +495,6 @@ _IRQ1_interrupt: _spurious_interrupt: di - move.b 4,r0 - move.b r0,[0xb0000030] basse2: ba basse2 nop @@ -479,7 +504,7 @@ _multiple_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! - push irp + move irp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -491,15 +516,15 @@ move.d _irq_shortcuts + 8,r1 moveq 2,r2 ; first bit we care about is the timer0 irq - move.d [0xb00000d8],r0 ; read the irq bits that triggered the multiple irq + move.d [R_VECT_MASK_RD],r0 ; read the irq bits that triggered the multiple irq multloop: btst r2,r0 ; check for the irq given by bit r2 bmi do_shortcut ; actually do the shortcut nop - addq 1,r2 ; next vector bit - remember this is in the delay slot! + addq 1,r2 ; next vector bit addq 4,r1 ; next vector - cmpq 26,r2 - bne multloop ; process all irq's up to and including number 25 + cmp.b 32,r2 + bne multloop ; process all irq's up to and including number 31 nop ;; strange, we didn't get any set vector bits.. oh well, just return @@ -513,6 +538,48 @@ nop jump [r1] ; jump to the irq handlers shortcut +_do_sigtrap: + ;; + ;; SIGTRAP the process that executed the break instruction. + ;; Make a frame that Rexit in entry.S expects. + ;; + move brp,[sp=sp-16] ; Push BRP while faking a cpu status record. + push srp ; Push subroutine return pointer. + push dccr ; Push condition codes. + push mof ; Push multiply overflow reg. + di ; Need to disable irq's at this point. + subq 14*4,sp ; Make room for r0-r13. + movem r13,[sp] ; Push the r0-r13 registers. + push r10 ; Push orig_r10. + clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. + + movs.w -8192,r9 ; THREAD_SIZE == 8192 + and.d sp,r9 + move.d [r9+LTASK_PID],r10 ; current->pid as arg1. + moveq 5,r11 ; SIGTRAP as arg2. + jsr _sys_kill + jump _ret_from_intr ; Use the return routine for interrupts. + +_gdb_handle_breakpoint: + push dccr + push r0 +#ifdef CONFIG_ETRAX_KGDB + move dccr,r0 ; U-flag not affected by previous insns. + btstq 8,r0 ; Test the U-flag. + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Empty delay slot (cannot pop r0 here). + pop r0 ; Restore r0. + ba _kgdb_handle_breakpoint ; Go to kernel debugging. + pop dccr ; Restore dccr in delay slot. +#endif + +_ugdb_handle_breakpoint: + move brp,r0 ; Use r0 temporarily for calculation. + subq 2,r0 ; Set to address of previous instruction. + move r0,brp + pop r0 ; Restore r0. + ba _do_sigtrap ; SIGTRAP the offending process. + pop dccr ; Restore dccr in delay slot. .data @@ -521,8 +588,11 @@ _hw_bp_trig_ptr: .dword _hw_bp_trigs -/* linux/linkage.h got it wrong for this compiler currently */ - +/* Because we compile this file with -traditional, we need to redefine + token-concatenation to the traditional trick, using an empty comment. + Normally (in other files, with ISO C as in gcc default) this is done + with the ## preprocessor operator. */ + #undef SYMBOL_NAME #define SYMBOL_NAME(X) _/**/X @@ -748,6 +818,8 @@ .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ /* * NOTE!! This doesn't have to be exact - we just have @@ -756,9 +828,7 @@ * been shrunk every time we add a new system call. */ - ;; TODO: this needs to actually generate sys_ni_syscall entires - ;; since we now have removed the check for NULL entries in this - ;; table in system_call! - - .space (NR_syscalls-220)*4 + .rept NR_syscalls-221 + .long SYMBOL_NAME(sys_ni_syscall) + .endr diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.4/linux/arch/cris/kernel/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/head.S Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.20 2001/02/23 12:47:56 bjornw Exp $ +/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,40 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.29 2001/04/18 12:51:59 orjanf + * * Reverted review change regarding the use of bcs/bcc. + * * Removed non-working LED-clearing code. + * + * Revision 1.28 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.27 2001/04/17 11:42:35 orjanf + * Changed according to review: + * * Added comment explaining memory map bug. + * * Changed bcs and bcc to blo and bhs, respectively. + * * Removed mentioning of Stallone and Olga boards. + * + * Revision 1.26 2001/04/06 12:31:07 jonashg + * Check for cramfs in flash before RAM instead of RAM before flash. + * + * Revision 1.25 2001/04/04 06:23:53 starvik + * Initialize DRAM if not already initialized + * + * Revision 1.24 2001/04/03 11:12:00 starvik + * Removed dram init (done by rescue or etrax100boot + * Corrected include + * + * Revision 1.23 2001/04/03 09:53:03 starvik + * Include hw_settings.S + * + * Revision 1.22 2001/03/26 14:23:26 bjornw + * Namechange of some config options + * + * Revision 1.21 2001/03/08 12:14:41 bjornw + * * Config name for ETRAX IDE was renamed + * * Removed G27 auto-setting when JULIETTE is chosen (need to make this + * a new config option later) + * * Revision 1.20 2001/02/23 12:47:56 bjornw * MMU regs during LOW_MAP updated to reflect a newer reality * @@ -76,7 +110,8 @@ #include #define CRAMFS_MAGIC 0x28cd3d45 - +#define RAM_INIT_MAGIC 0x56902387 + ;; exported symbols .globl _etrax_irv @@ -92,9 +127,9 @@ ;; since etrax actually starts at address 2 when booting from flash, we ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; - ;; NOTICE! The register r9 is used as a parameter carrying register from - ;; the decompressor (if the kernel was compressed). It should not be - ;; used in the code below until it is read. + ;; NOTICE! The registers r8 and r9 are used as a parameter carrying + ;; information from the decompressor (if the kernel was compressed). + ;; They should not be used in the code below until it is read. nop di @@ -109,6 +144,7 @@ ;; ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory ;; slightly different. We also let the simulator get this mapping for now. + ;; (The bug is that you can't remap bit 31.) #ifdef CONFIG_CRIS_LOW_MAP move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 @@ -161,8 +197,14 @@ inflash: ;; We need to initialze DRAM registers before we start using the DRAM -#include "../lib/dram_init.S" + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../lib/dram_init.S" + +dram_init_finished: ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -218,7 +260,39 @@ moveq 0, r0 move.d r0, [_romfs_length] ; default if there is no cramfs - ;; First check if there is a cramfs (magic value) + ;; The kernel could have been unpacked to DRAM by the loader, but + ;; the cramfs image could still be in the Flash directly after the + ;; compressed kernel image. The loader passes the address of the + ;; byte succeeding the last compressed byte in the flash in the + ;; register r9 when starting the kernel. Check if r9 points to a + ;; decent cramfs image! + ;; (Notice that if this is not booted from the loader, r9 will be + ;; garbage but we do sanity checks on it, the chance that it points + ;; to a cramfs magic is small.. ) + + cmp.d 0x0ffffff8, r9 + bcc no_romfs_in_flash ; r9 points outside the flash area + nop + move.d [r9], r0 ; cramfs_super.magic + cmp.d CRAMFS_MAGIC, r0 + bne no_romfs_in_flash + nop + move.d [r9+4], r0 ; cramfs_super.length + move.d r0, [_romfs_length] +#ifdef CONFIG_CRIS_LOW_MAP + add.d 0x50000000, r9 ; add flash start in virtual memory (cached) +#else + add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) +#endif + move.d r9, [_romfs_start] + + moveq 1, r0 + move.d r0, [_romfs_in_flash] + + jump start_it ; enter code, cached this time + +no_romfs_in_flash: + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does ;; not need this mechanism anyway) @@ -226,7 +300,7 @@ move.d __vmlinux_end, r0 ; the image will be after the vmlinux end address move.d [r0], r1 ; cramfs assumes same endian on host/target cmp.d CRAMFS_MAGIC, r1; magic value in cramfs superblock - bne no_romfs_in_ram + bne 1f nop ;; Ok. What is its size ? @@ -263,40 +337,6 @@ move.d r0, [_romfs_in_flash] jump start_it ; better skip the additional cramfs check below - -no_romfs_in_ram: - - ;; We have still one other possibility at this point - the kernel - ;; could have been unpacked to DRAM by the loader, but the cramfs - ;; image was still in the Flash directly after the compressed kernel - ;; image. The loader passes the address of the byte succeeding the - ;; last compressed byte in the flash in the register r9 when starting - ;; the kernel. Check if r9 points to a decent cramfs image! - ;; (Notice that if this is not booted from the loader, r9 will be - ;; garbage but we do sanity checks on it, the chance that it points - ;; to a cramfs magic is small.. ) - - cmp.d 0x0ffffff8, r9 - bcc 1f ; r9 points outside the flash area - nop - move.d [r9], r0 ; cramfs_super.magic - cmp.d CRAMFS_MAGIC, r0 - bne 1f - nop - move.d [r9+4], r0 ; cramfs_super.length - move.d r0, [_romfs_length] -#ifdef CONFIG_CRIS_LOW_MAP - add.d 0x50000000, r9 ; add flash start in virtual memory (cached) -#else - add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) -#endif - move.d r9, [_romfs_start] - - moveq 1, r0 - move.d r0, [_romfs_in_flash] -1: - - jump start_it ; enter code, cached this time start_it: ;; the kernel stack is overlayed with the task structure for each @@ -368,10 +408,10 @@ ;; Etrax product HW genconfig setup moveq 0,r0 -#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY) +#if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY) or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA #endif -#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) +#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA #endif #ifdef CONFIG_DMA_MEMCPY @@ -389,7 +429,7 @@ #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 #endif -#ifdef CONFIG_BLK_DEV_ETRAXIDE +#ifdef CONFIG_ETRAX_IDE or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled #endif @@ -405,9 +445,6 @@ #ifdef CONFIG_JULIETTE or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette -#ifndef CONFIG_BLK_DEV_ETRAXIDE - or.d 0x41,r0 ; HACK for now! To make G27 connected for the RTC -#endif #endif move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG @@ -447,20 +484,20 @@ ;; setup port PA and PB default initial directions and data ;; including their shadow registers - move.b DEF_R_PORT_PA_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,r0 move.b r0,[_port_pa_dir_shadow] move.b r0,[R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,r0 move.b r0,[_port_pa_data_shadow] move.b r0,[R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_CONFIG,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,r0 move.b r0,[_port_pb_config_shadow] move.b r0,[R_PORT_PB_CONFIG] - move.b DEF_R_PORT_PB_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,r0 move.b r0,[_port_pb_dir_shadow] move.b r0,[R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,r0 move.b r0,[_port_pb_data_shadow] move.b r0,[R_PORT_PB_DATA] move.d 0, r0 @@ -499,12 +536,6 @@ move.b 0x40,r0 ; tr enable move.b r0,[R_SERIAL1_TR_CTRL] -#ifdef CONFIG_ETRAX_90000000_LEDS - ;; clear LED's on Stallone and Olga boards - moveq -1,r0 - move.d r0,[_port_90000000_shadow] - move.d r0,[0x90000000] -#endif #ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes @@ -544,3 +575,5 @@ #else _swapper_pg_dir = 0xc0002000 #endif + +#include "../lib/hw_settings.S" diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.4/linux/arch/cris/kernel/irq.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/irq.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw Exp $ +/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/kernel/irq.c * @@ -160,7 +160,7 @@ BUILD_IRQ(23, 0x800000) BUILD_IRQ(24, 0x1000000) BUILD_IRQ(25, 0x2000000) -/* IRQ 26-30 are resereved */ +/* IRQ 26-30 are reserved */ BUILD_IRQ(31, 0x80000000) /* @@ -261,11 +261,11 @@ irq_enter(cpu); kstat.irqs[cpu][irq]++; - action = *(irq + irq_action); + action = irq_action[irq]; if (action) { if (!(action->flags & SA_INTERRUPT)) __sti(); - action = *(irq + irq_action); + action = irq_action[irq]; do_random = 0; do { do_random |= action->flags; @@ -396,7 +396,7 @@ save_flags(flags); cli(); *p = action->next; - if (!irq[irq_action]) { + if (!irq_action[irq]) { mask_irq(irq); set_int_vector(irq, bad_interrupt[irq], 0); } @@ -419,8 +419,8 @@ */ void system_call(void); /* from entry.S */ -void gdb_handle_breakpoint(void); /* from traps.c */ -void do_sigtrap(void); /* also from traps.c */ +void do_sigtrap(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from entry.S */ void init_IRQ(void) { @@ -475,10 +475,10 @@ /* setup a breakpoint handler for debugging used for both user and kernel mode debugging (which is why it is not inside an ifdef - CONFIG_KGDB) */ + CONFIG_ETRAX_KGDB) */ set_break_vector(8, gdb_handle_breakpoint); -#ifdef CONFIG_KGDB +#ifdef CONFIG_ETRAX_KGDB /* setup kgdb if its enabled, and break into the debugger */ kgdb_init(); breakpoint(); diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c --- v2.4.4/linux/arch/cris/kernel/kgdb.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/kgdb.c Tue May 1 16:04:56 2001 @@ -18,6 +18,9 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.5 2001/04/17 13:58:39 orjanf +*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. +*! *! Revision 1.4 2001/02/23 13:45:19 bjornw *! config.h check *! @@ -49,7 +52,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $ +*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -60,8 +63,8 @@ * kgdb usage notes: * ----------------- * - * If you select CONFIG_KGDB in the configuration, the kernel will be built - * with different gcc flags: "-g" is added to get debug infos, and + * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be + * built with different gcc flags: "-g" is added to get debug infos, and * "-fomit-frame-pointer" is omitted to make debugging easier. Since the * resulting kernel will be quite big (approx. > 7 MB), it will be stripped * before compresion. Such a kernel will behave just as usually, except if diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.4/linux/arch/cris/kernel/process.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/process.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.12 2001/02/27 13:52:52 bjornw Exp $ +/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $ * * linux/arch/cris/kernel/process.c * @@ -7,6 +7,10 @@ * * Authors: Bjorn Wesen (bjornw@axis.com) * + * $Log: process.c,v $ + * Revision 1.13 2001/03/20 19:44:06 bjornw + * Use the 7th syscall argument for regs instead of current_regs + * */ /* @@ -33,6 +37,8 @@ #include #include #include +#include + #include //#define DEBUG @@ -64,13 +70,6 @@ static int hlt_counter=0; -/* in a system call, set_esp0 is called to remember the stack frame, therefore - in the implementation of syscalls we can use that value to access the stack - frame and saved registers. -*/ - -#define currentregs ((struct pt_regs *)current->thread.esp0) - void disable_hlt(void) { hlt_counter++; @@ -178,7 +177,7 @@ * remember that the task_struct doubles as the kernel stack for the task */ - childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1; + childregs = user_regs(p); *childregs = *regs; /* struct copy of pt_regs */ @@ -202,14 +201,11 @@ p->thread.ksp = (unsigned long) swstack; - /* esp0 keeps the pt_regs stacked structure pointer */ - - p->thread.esp0 = (unsigned long) childregs; - #ifdef DEBUG - printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n", - current->kernel_stack_page, usedstack, p->thread.usp, usp); + printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); + show_registers(childregs); #endif + return 0; } @@ -240,33 +236,53 @@ #endif } -asmlinkage int sys_fork(void) +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), currentregs, 0); + return do_fork(SIGCHLD, rdusp(), regs, 0); } /* if newusp is 0, we just grab the old usp */ -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags) +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, + long r12, long r13, long mof, long srp, + struct pt_regs *regs) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, currentregs, 0); + return do_fork(flags, newusp, regs, 0); } /* vfork is a system call in i386 because of register-pressure - maybe * we can remove it and handle it in libc but we put it here until then. */ -asmlinkage int sys_vfork(void) +asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); } /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp) +asmlinkage int sys_execve(const char *fname, char **argv, char **envp, + long r13, long mof, long srp, + struct pt_regs *regs) { int error; char *filename; @@ -276,7 +292,7 @@ if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, currentregs); + error = do_execve(filename, argv, envp, regs); putname(filename); out: return error; diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c --- v2.4.4/linux/arch/cris/kernel/ptrace.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/ptrace.c Tue May 1 16:04:56 2001 @@ -3,11 +3,18 @@ * * Parts taken from the m68k port. * - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.5 2001/03/26 14:24:28 orjanf + * * Changed loop condition. + * * Added comment documenting non-standard ptrace behaviour. + * + * Revision 1.4 2001/03/20 19:44:41 bjornw + * Use the user_regs macro instead of thread.esp0 + * * Revision 1.3 2000/12/18 23:45:25 bjornw * Linux/CRIS first version * @@ -49,8 +56,8 @@ if (regno == PT_USP) return task->thread.usp; - else if (regno <= PT_MAX) - return ((unsigned long *)(task->thread.esp0))[regno]; + else if (regno < PT_MAX) + return ((unsigned long *)user_regs(task))[regno]; else return 0; } @@ -65,12 +72,20 @@ if (regno == PT_USP) task->thread.usp = data; - else if (regno <= PT_MAX) - ((unsigned long *)(task->thread.esp0))[regno] = data; + else if (regno < PT_MAX) + ((unsigned long *)user_regs(task))[regno] = data; else return -1; return 0; } + +/* Note that this implementation of ptrace behaves differently from vanilla + * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, + * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not + * ignored. Instead, the data variable is expected to point at a location + * (in user space) where the result of the ptrace call is written (instead of + * being returned). + */ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.4/linux/arch/cris/kernel/setup.c Fri Apr 27 14:10:31 2001 +++ linux/arch/cris/kernel/setup.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw Exp $ +/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $ * * linux/arch/cris/kernel/setup.c * @@ -60,7 +60,7 @@ * given by the macro __pa(). * * In this DRAM, the kernel code and data is loaded, in the beginning. - * It really starts at c00a0000 to make room for some special pages - + * It really starts at c0004000 to make room for some special pages - * the start address is text_start. The kernel data ends at _end. After * this the ROM filesystem is appended (if there is any). * @@ -77,11 +77,6 @@ unsigned long memory_start; extern void console_print_etrax(const char *b); -#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)) - /* TODO: move this into flash_init I think */ - flash_probe(); -#endif - /* register an initial console printing routine for printk's */ init_etrax_debug(); @@ -167,8 +162,9 @@ paging_init(); - /* we dont use a command line yet, so just let it be an empty string */ - + /* we dont use a command line yet, so just let it be an empty string + to start with */ + *cmdline_p = command_line; strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/shadows.c linux/arch/cris/kernel/shadows.c --- v2.4.4/linux/arch/cris/kernel/shadows.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/shadows.c Tue May 1 16:04:56 2001 @@ -1,20 +1,36 @@ -/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ +/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $ * - * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h + * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ -#include +/* Shadows for internal Etrax-registers */ + +unsigned long genconfig_shadow; +unsigned long port_g_data_shadow; +unsigned char port_pa_dir_shadow; +unsigned char port_pa_data_shadow; +unsigned char port_pb_i2c_shadow; +unsigned char port_pb_config_shadow; +unsigned char port_pb_dir_shadow; +unsigned char port_pb_data_shadow; +unsigned long r_timer_ctrl_shadow; + +/* Shadows for external I/O port registers. + * These are only usable if there actually IS a latch connected + * to the corresponding external chip-select pin. + * + * A common usage is that CSP0 controls LED's and CSP4 video chips. + */ + +unsigned long port_cse1_shadow; +unsigned long port_csp0_shadow; +unsigned long port_csp4_shadow; + +/* Corresponding addresses for the ports. + * These are initialized in arch/cris/mm/init.c using ioremap. + */ + +volatile unsigned long *port_cse1_addr; +volatile unsigned long *port_csp0_addr; +volatile unsigned long *port_csp4_addr; -unsigned long genconfig_shadow = 42; -unsigned long port_g_data_shadow = 42; -unsigned char port_pa_dir_shadow = 42; -unsigned char port_pa_data_shadow = 42; -unsigned char port_pb_i2c_shadow = 42; -unsigned char port_pb_config_shadow = 42; -unsigned char port_pb_dir_shadow = 42; -unsigned char port_pb_data_shadow = 42; -unsigned long r_timer_ctrl_shadow = 42; - -#ifdef CONFIG_ETRAX_90000000_LEDS -unsigned long port_90000000_shadow = 42; -#endif diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c --- v2.4.4/linux/arch/cris/kernel/signal.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/signal.c Tue May 1 16:04:56 2001 @@ -36,6 +36,9 @@ /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ /* manipulate regs so that upon return, it will be re-executed */ +/* We rely on that pc points to the instruction after "break 13", so the + * library must never do strange things like putting it in a delay slot. + */ #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); @@ -76,12 +79,14 @@ } /* - * Atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. Define + * dummy arguments to be able to reach the regs argument. (Note that this + * arrangement relies on old_sigset_t occupying one register.) */ int -sys_sigsuspend(old_sigset_t mask) +sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset; mask &= _BLOCKABLE; @@ -100,10 +105,13 @@ } } +/* Define dummy arguments to be able to reach the regs argument. (Note that + * this arrangement relies on size_t occupying one register.) + */ int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset, newset; /* XXX: Don't preclude handling different sized sigset_t's. */ @@ -225,9 +233,11 @@ return 1; } -asmlinkage int sys_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct sigframe *frame = (struct sigframe *)rdusp(); sigset_t set; @@ -265,9 +275,11 @@ return 0; } -asmlinkage int sys_rt_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); sigset_t set; stack_t st; @@ -389,7 +401,6 @@ /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; /* This is movu.w __NR_sigreturn, r9; break 13; */ - /* TODO: check byteorder */ err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); @@ -535,7 +546,14 @@ * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. + * + * Also note that the regs structure given here as an argument, is the latest + * pushed pt_regs. It may or may not be the same as the first pushed registers + * when the initial usermode->kernelmode transition took place. Therefore + * we can use user_mode(regs) to see if we came directly from kernel or user + * mode below. */ + int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.4/linux/arch/cris/kernel/sys_cris.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/sys_cris.c Tue May 1 16:04:56 2001 @@ -1,6 +1,6 @@ -/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $ +/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $ * - * linux/arch/cris/kernel/sys_etrax.c + * linux/arch/cris/kernel/sys_cris.c * * This file contains various random system calls that * have a non-standard calling sequence on some platforms. @@ -177,20 +177,13 @@ case MSGCTL: return sys_msgctl (first, second, (struct msqid_ds *) ptr); - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); - if (ret) - return ret; - return put_user (raddr, (ulong *) third); - } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); - } + case SHMAT: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } case SHMDT: return sys_shmdt ((char *)ptr); case SHMGET: diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.4/linux/arch/cris/kernel/traps.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/traps.c Sun May 20 12:11:38 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw Exp $ +/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $ * * linux/arch/cris/traps.c * @@ -9,11 +9,9 @@ * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen - * Orjan Friberg * */ -#include #include #include #include @@ -45,8 +43,10 @@ int i; extern char _stext, _etext; - // debugging aid: "show_stack(NULL);" prints the - // back trace for this cpu. + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ if(sp == NULL) sp = (unsigned long*)rdsp(); @@ -107,8 +107,8 @@ { unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n", - regs->irp, regs->srp, regs->dccr, usp ); + printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", @@ -120,7 +120,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); - // TODO, fix in_kernel detection + /* TODO, fix in_kernel detection */ #if 0 /* @@ -168,65 +168,5 @@ void __init trap_init(void) { - + /* Nothing needs to be done */ } - -/* Use static variables instead of the stack for temporary storage. */ -static int saved_r0 = 0; -static int saved_dccr = 0; - -asm (" - .global _gdb_handle_breakpoint - .global _do_sigtrap -_gdb_handle_breakpoint: -;; -;; This handles a break instruction for entering a debug session. -;; - move dccr,[_saved_dccr] ; Save dccr. - move.d r0,[_saved_r0] ; Save r0. " -#ifdef CONFIG_KGDB -" - move ccr,r0 - btstq 8,r0 ; Test the U-flag. - bmi _ugdb_handle_breakpoint ; Go to user mode debugging. - nop ; Delay slot. - move.d [_saved_r0],r0 ; Restore r0. - move [_saved_dccr],dccr ; Restore dccr. - ba _kgdb_handle_breakpoint ; Go to kernel debugging. - nop ; Delay slot. " -#endif -" -_ugdb_handle_breakpoint: -;; -;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it -;; starts talking to the target again, but this way we avoid a 'P' packet. -;; - move brp,r0 ; Use r0 temporarily for calculation. - subq 2,r0 ; Set to address of previous instruction. - move r0,brp ; Restore new brp. - move.d [_saved_r0],r0 ; Restore r0. - move [_saved_dccr],dccr ; Restore dccr. - -_do_sigtrap: -;; -;; SIGTRAP the process that executed the break instruction. -;; Make a frame that Rexit in entry.S expects. -;; - push brp ; Push breakpoint return pointer. - push srp ; Push subroutine return pointer. - push dccr ; Push condition codes. - push mof ; Push multiply overflow reg. - di ; Need to disable irq's at this point. - subq 14*4,sp ; Make room for r0-r13. - movem r13,[sp] ; Push the r0-r13 registers. - push r10 ; Push orig_r10. - clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. - - movs.w -8192,r9 ; THREAD_SIZE == 8192 - and.d sp,r9 - move.d [r9+LTASK_PID],r10 ; current->pid as arg1. - moveq 5,r11 ; SIGTRAP as arg2. - jsr _sys_kill - - jump _ret_from_intr ; Use the return routine for interrupts. -"); diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S --- v2.4.4/linux/arch/cris/lib/dram_init.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/lib/dram_init.S Tue May 1 16:04:56 2001 @@ -1,63 +1,97 @@ - ;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $ - ;; - ;; DRAM/SDRAM initialization - alter with care - ;; This file is intended to be included from other assembler files - ;; - ;; Copyright (C) 2000 Axis Communications AB - ;; - ;; Authors: Mikael Starvik (starvik@axis.com) - ;; Bjorn Wesen (bjornw@axis.com) - ;; - ;; $Log: dram_init.S,v $ - ;; Revision 1.2 2001/02/08 15:20:00 starvik - ;; Corrected SDRAM initialization - ;; Should now be included as inline - ;; - ;; Revision 1.1 2001/01/29 13:08:02 starvik - ;; Initial version - ;; This file should be included from all assembler files that needs to - ;; initialize DRAM/SDRAM. - ;; - ;; - ;; +/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $ + * + * DRAM/SDRAM initialization - alter with care + * This file is intended to be included from other assembler files + * + * Note: This file may not modify r9 because r9 is used to carry + * information from the decompresser to the kernel + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Mikael Starvik (starvik@axis.com) + * + * $Log: dram_init.S,v $ + * Revision 1.7 2001/04/18 12:05:39 bjornw + * Fixed comments, and explicitely include config.h to be sure its there + * + * Revision 1.6 2001/04/10 06:20:16 starvik + * Delay should be 200us, not 200ns + * + * Revision 1.5 2001/04/09 06:01:13 starvik + * Added support for 100 MHz SDRAMs + * + * Revision 1.4 2001/03/26 14:24:01 bjornw + * Namechange of some config options + * + * Revision 1.3 2001/03/23 08:29:41 starvik + * Corrected calculation of mrs_data + * + * Revision 1.2 2001/02/08 15:20:00 starvik + * Corrected SDRAM initialization + * Should now be included as inline + * + * Revision 1.1 2001/01/29 13:08:02 starvik + * Initial version + * This file should be included from all assembler files that needs to + * initialize DRAM/SDRAM. + * + */ + +/* Just to be certain the config file is included, we include it here + * explicitely instead of depending on it being included in the file that + * uses this code. + */ #include + #ifndef CONFIG_SVINTO_SIM - move.d DEF_R_WAITSTATES, r0 + move.d CONFIG_ETRAX_DEF_R_WAITSTATES, r0 move.d r0, [R_WAITSTATES] - move.d DEF_R_BUS_CONFIG, r0 + move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, r0 move.d r0, [R_BUS_CONFIG] -#ifndef CONFIG_SDRAM - move.d DEF_R_DRAM_CONFIG, r0 +#ifndef CONFIG_ETRAX_SDRAM + move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, r0 move.d r0, [R_DRAM_CONFIG] - move.d DEF_R_DRAM_TIMING, r0 + move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, r0 move.d r0, [R_DRAM_TIMING] #else ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization ; Bank configuration - move.d DEF_R_SDRAM_CONFIG, r0 + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r0 move.d r0, [R_SDRAM_CONFIG] ; Calculate value of mrs_data - ; cas_delay = 2 && bus_width = 32 => 0x40 - ; cas_delay = 3 && bus_width = 32 => 0x60 - ; cas_delay = 2 && bus_width = 16 => 0x20 - ; cas_delay = 3 && bus_width = 16 => 0x30 + ; CAS latency = 2 && bus_width = 32 => 0x40 + ; CAS latency = 3 && bus_width = 32 => 0x60 + ; CAS latency = 2 && bus_width = 16 => 0x20 + ; CAS latency = 3 && bus_width = 16 => 0x30 - move.d 0x40, r2 ; Assume 32 bits and cas_delay = 2 - move.d DEF_R_SDRAM_TIMING, r1 - and.d 0x0c, r1 ; Get cas delay - cmp.d 0x08, r1 ; cas_delay = 2? - beq bw_check + move.d 0x40, r2 ; Assume 32 bits and CAS latency = 2 + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + move.d r1, r3 + and.d 0x03, r1 ; Get CAS latency + and.d 0x1000, r3 ; 50 or 100 MHz? + beq speed_50 + nop +speed_100: + cmp.d 0x00, r1 ; CAS latency = 2? + beq bw_check + nop + or.d 0x20, r2 ; CAS latency = 3 + ba bw_check + nop +speed_50: + cmp.d 0x01, r1 ; CAS latency = 2? + beq bw_check nop - or.d 0x20, r2 ; cas_delay = 3 + or.d 0x20, r2 ; CAS latency = 3 bw_check: - move.d DEF_R_SDRAM_CONFIG, r1 + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r1 and.d 0x800000, r1 ; DRAM width is bit 23 bne set_timing nop @@ -65,14 +99,17 @@ ; Set timing parameters. Starts master clock set_timing: - move.d DEF_R_SDRAM_TIMING, r1 + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + and.d 0x8000f9ff, r1 ; Make sure mrs data and command is 0 or.d 0x80000000, r1 ; Make sure sdram enable bit is set + move.d r1, r5 + or.d 0x0000c000, r1 ; ref = disable lslq 16, r2 ; mrs data starts at bit 16 or.d r2, r1 move.d r1, [R_SDRAM_TIMING] - ; Wait 200ns - move.d 10, r2 + ; Wait 200us + move.d 10000, r2 sdram_loop: bne sdram_loop subq 1, r2 @@ -83,10 +120,10 @@ command_loop: clear.d r4 move.b [r2+], r4 - lslq 9, r4 ; Command starts at bit 9 + lslq 9, r4 ; Command starts at bit 9 or.d r1, r4 move.d r4, [R_SDRAM_TIMING] - nop ; Wait five nop cycles between each command + nop ; Wait five nop cycles between each command nop nop nop @@ -94,6 +131,7 @@ cmp.d r2, r3 bne command_loop nop + move.d r5, [R_SDRAM_TIMING] ba sdram_commands_end nop diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S --- v2.4.4/linux/arch/cris/lib/hw_settings.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/hw_settings.S Sun May 20 12:11:38 2001 @@ -0,0 +1,61 @@ + ;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $ + ;; + ;; This table is used by some tools to extract hardware parameters. + ;; The table should be included in the kernel and the decompressor. + ;; Don't forget to update the tools if you change this table. + ;; + ;; Copyright (C) 2001 Axis Communications AB + ;; + ;; Authors: Mikael Starvik (starvik@axis.com) + + +#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PA_DATA)) +#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DATA)) + + .ascii "HW_PARAM_MAGIC" ; Magic number + .dword 0xc0004000 ; Kernel start address + + ; Debug port +#ifdef CONFIG_ETRAX_DEBUG_PORT0 + .dword 0 +#elif defined(CONFIG_ETRAX_DEBUG_PORT1) + .dword 1 +#elif defined(CONFIG_ETRAX_DEBUG_PORT2) + .dword 2 +#elif defined(CONFIG_ETRAX_DEBUG_PORT3) + .dword 3 +#else + .dword 4 ; No debug +#endif + + ; SDRAM or EDO DRAM? +#ifdef CONFIG_ETRAX_SDRAM + .dword 1 +#else + .dword 0 +#endif + + ; Register values + .dword R_WAITSTATES + .dword CONFIG_ETRAX_DEF_R_WAITSTATES + .dword R_BUS_CONFIG + .dword CONFIG_ETRAX_DEF_R_BUS_CONFIG +#ifdef CONFIG_ETRAX_SDRAM + .dword R_SDRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG + .dword R_SDRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING +#else + .dword R_DRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG + .dword R_DRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_DRAM_TIMING +#endif + .dword R_PORT_PA_SET + .dword PA_SET_VALUE + .dword R_PORT_PB_SET + .dword PB_SET_VALUE + .dword 0 ; No more register values diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/memset.c linux/arch/cris/lib/memset.c --- v2.4.4/linux/arch/cris/lib/memset.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/memset.c Tue May 1 16:04:56 2001 @@ -27,6 +27,8 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + /* No, there's no macro saying 12*4, since it is "hard" to get it into the asm in a good way. Thus better to expose the problem everywhere. */ @@ -39,7 +41,7 @@ void *memset(void *pdst, int c, - unsigned int plen) + size_t plen) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. */ @@ -54,7 +56,12 @@ /* Ugh. This is fragile at best. Check with newer GCC releases, if they compile cascaded "x |= x << 8" sanely! */ - __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0" + __asm__("movu.b %0,r13\n\t" + "lslq 8,r13\n\t" + "move.b %0,r13\n\t" + "move.d r13,%0\n\t" + "lslq 16,r13\n\t" + "or.d r13,%0" : "=r" (lc) : "0" (lc) : "r13"); { diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/string.c linux/arch/cris/lib/string.c --- v2.4.4/linux/arch/cris/lib/string.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/string.c Tue May 1 16:04:56 2001 @@ -31,9 +31,11 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + void *memcpy(void *pdst, const void *psrc, - unsigned int pn) + size_t pn) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/extable.c linux/arch/cris/mm/extable.c --- v2.4.4/linux/arch/cris/mm/extable.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/extable.c Tue May 1 16:04:56 2001 @@ -37,8 +37,7 @@ #ifndef CONFIG_MODULES /* There is only the kernel to search. */ - ret = search_one_table(_start___ex_table, _stop___ex_table-1, addr); - if (ret) return ret; + return search_one_table(_start___ex_table, _stop___ex_table-1, addr); #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.4/linux/arch/cris/mm/fault.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/fault.c Tue May 1 16:04:56 2001 @@ -1,11 +1,20 @@ /* * linux/arch/cris/mm/fault.c * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.12 2001/04/04 10:51:14 bjornw + * mmap_sem is grabbed for reading + * + * Revision 1.11 2001/03/23 07:36:07 starvik + * Corrected according to review remarks + * + * Revision 1.10 2001/03/21 16:10:11 bjornw + * CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL + * * Revision 1.9 2001/03/05 13:22:20 bjornw * Spell-fix and fix in vmalloc_fault handling * @@ -70,12 +79,12 @@ address = cause & PAGE_MASK; /* get faulting address */ - page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + D(page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause)); + D(acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause)); + D(inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause)); + D(index = IO_EXTRACT(R_TLB_SELECT, index, select)); miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); - acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); - inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); - index = IO_EXTRACT(R_TLB_SELECT, index, select); D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " "idx %d pid %d\n", @@ -304,23 +313,32 @@ /* Are we prepared to handle this kernel fault? * * (The kernel has valid exception-points in the source - * when it accesses user-memory. When it fails in one + * when it acesses user-memory. When it fails in one * of those points, we find it in a table and do a jump * to some fixup code that loads an appropriate error * code) */ if ((fixup = search_exception_table(regs->irp)) != 0) { + /* Adjust the instruction pointer in the stackframe */ + regs->irp = fixup; - regs->frametype = CRIS_FRAME_FIXUP; + + /* We do not want to return by restoring the CPU-state + * anymore, so switch frame-types (see ptrace.h) + */ + + regs->frametype = CRIS_FRAME_NORMAL; + D(printk("doing fixup to 0x%x\n", fixup)); return; } -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) (address) < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.4/linux/arch/cris/mm/init.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/init.c Tue May 1 16:04:56 2001 @@ -7,6 +7,22 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.23 2001/04/04 14:35:40 bjornw + * * Removed get_pte_slow and friends (2.4.3 change) + * * Removed bad_pmd handling (2.4.3 change) + * + * Revision 1.22 2001/04/04 13:38:04 matsfg + * Moved ioremap to a separate function instead + * + * Revision 1.21 2001/03/27 09:28:33 bjornw + * ioremap used too early - lets try it in mem_init instead + * + * Revision 1.20 2001/03/23 07:39:21 starvik + * Corrected according to review remarks + * + * Revision 1.19 2001/03/15 14:25:17 bjornw + * More general shadow registers and ioremaped addresses for external I/O + * * Revision 1.18 2001/02/23 12:46:44 bjornw * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O @@ -68,6 +84,7 @@ #include #include #include +#include static unsigned long totalram_pages; @@ -79,128 +96,13 @@ extern void show_net_buffers(void); extern void tlb_init(void); -/* - * empty_bad_page is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * the main point is that when a page table error occurs, we want to get - * out of the kernel safely before killing the process, so we need something - * to feed the MMU with when the fault occurs even if we don't have any - * real PTE's or page tables. - * - * empty_bad_page_table is the accompanying page-table: it is initialized - * to point to empty_bad_page writable-shared entries. - * - * empty_zero_page is a special page that is used for zero-initialized - * data and COW. - */ -unsigned long empty_bad_page_table; -unsigned long empty_bad_page; unsigned long empty_zero_page; -pte_t * __bad_pagetable(void) -{ - /* somehow it is enough to just clear it and not fill it with - * bad page PTE's... - */ - memset((void *)empty_bad_page_table, 0, PAGE_SIZE); - - return (pte_t *) empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - - /* clear the empty_bad_page page. this should perhaps be - * a more simple inlined loop like it is on the other - * architectures. - */ - - memset((void *)empty_bad_page, 0, PAGE_SIZE); - - return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED)); -} - -static pte_t * get_bad_pte_table(void) -{ - pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table; - pte_t v; - int i; - - v = __bad_page(); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set(pmd, get_bad_pte_table()); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set_kernel(pmd, get_bad_pte_table()); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - pmd_set_kernel(pmd, pte); - return pte + offset; - } - pmd_set_kernel(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -#ifndef CONFIG_NO_PGT_CACHE -struct pgtable_cache_struct quicklists; - /* trim the page-table cache if necessary */ -int do_check_pgt_cache(int low, int high) +int +do_check_pgt_cache(int low, int high) { int freed = 0; @@ -211,25 +113,20 @@ freed++; } if(pmd_quicklist) { - free_pmd_slow(get_pmd_fast()); + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); freed++; } if(pte_quicklist) { - free_pte_slow(get_pte_fast()); - freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; } } while(pgtable_cache_size > low); } return freed; } -#else -int do_check_pgt_cache(int low, int high) -{ - return 0; -} -#endif -void show_mem(void) +void +show_mem(void) { int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; int shared = 0; @@ -287,15 +184,51 @@ /* see README.mm for details on the KSEG setup */ -#ifdef CONFIG_CRIS_LOW_MAP +#ifndef CONFIG_CRIS_LOW_MAP + /* This code is for the corrected Etrax-100 LX version 2... */ + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else /* Etrax-100 LX version 1 has a bug so that we cannot map anything * across the 0x80000000 boundary, so we need to shrink the user-virtual * area to 0x50000000 instead of 0xb0000000 and map things slightly * different. The unused areas are marked as paged so that we can catch * freak kernel accesses there. * - * The Juliette chip is mapped at 0xa so we pass that segment straight + * The ARTPEC chip is mapped at 0xa so we pass that segment straight * through. We cannot vremap it because the vmalloc area is below 0x8 * and Juliette needs an uncached area above 0x8. * @@ -308,7 +241,7 @@ IO_STATE(R_MMU_KSEG, seg_d, page ) | IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */ + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ @@ -337,44 +270,7 @@ IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#else - /* This code is for the hopefully corrected Etrax-100 LX version 2... */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ - IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | - IO_STATE(R_MMU_KSEG, seg_7, page ) | - IO_STATE(R_MMU_KSEG, seg_6, page ) | - IO_STATE(R_MMU_KSEG, seg_5, page ) | - IO_STATE(R_MMU_KSEG, seg_4, page ) | - IO_STATE(R_MMU_KSEG, seg_3, page ) | - IO_STATE(R_MMU_KSEG, seg_2, page ) | - IO_STATE(R_MMU_KSEG, seg_1, page ) | - IO_STATE(R_MMU_KSEG, seg_0, page ) ); - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#endif +#endif *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); @@ -393,8 +289,6 @@ * to a couple of allocated pages */ - empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)empty_zero_page, 0, PAGE_SIZE); @@ -412,6 +306,7 @@ */ free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0); + } extern unsigned long loops_per_jiffy; /* init/main.c */ @@ -462,7 +357,7 @@ datasize >> 10, initsize >> 10 ); - + /* HACK alert - calculate a loops_per_usec for asm/delay.h here * since this is called just after calibrate_delay in init/main.c * but before places which use udelay. cannot be in time.c since @@ -474,9 +369,52 @@ return; } +/* Initialize remaps of some I/O-ports. This is designed to be callable + * multiple times from the drivers init-sections, because we don't know + * beforehand which driver will get initialized first. + */ + +void +init_ioremap(void) +{ + + /* Give the external I/O-port addresses their values */ + + static int initialized = 0; + + if( !initialized ) { + initialized++; + +#ifdef CONFIG_CRIS_LOW_MAP + /* Simply a linear map (see the KSEG map above in paging_init) */ + port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | + MEM_NON_CACHEABLE); + port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | + MEM_NON_CACHEABLE); + port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | + MEM_NON_CACHEABLE); +#else + /* Note that nothing blows up just because we do this remapping + * it's ok even if the ports are not used or connected + * to anything (or connected to a non-I/O thing) */ + port_cse1_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSE1_START | + MEM_NON_CACHEABLE), 16); + port_csp0_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP0_START | + MEM_NON_CACHEABLE), 16); + port_csp4_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP4_START | + MEM_NON_CACHEABLE), 16); +#endif + } +} + + /* free the pages occupied by initialization code */ -void free_initmem(void) +void +free_initmem(void) { #if 0 /* currently this is a bad idea since the cramfs image is catted onto @@ -497,7 +435,8 @@ #endif } -void si_meminfo(struct sysinfo *val) +void +si_meminfo(struct sysinfo *val) { int i; diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/ioremap.c linux/arch/cris/mm/ioremap.c --- v2.4.4/linux/arch/cris/mm/ioremap.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/ioremap.c Tue May 1 16:04:56 2001 @@ -51,7 +51,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -64,6 +64,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -72,19 +73,23 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; - pmd = pmd_alloc_kernel(dir, address); + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, - phys_addr + address, flags)) - return -ENOMEM; + phys_addr + address, flags)) + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c --- v2.4.4/linux/arch/cris/mm/tlb.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/tlb.c Tue May 1 16:04:56 2001 @@ -288,7 +288,7 @@ /* clear the page_id map */ - for(i = 0; i < 64; i++) + for(i = 0; i < NUM_PAGEID; i++) page_id_map[i] = NULL; /* invalidate the entire TLB */ diff -u --recursive --new-file v2.4.4/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.4/linux/arch/i386/boot/setup.S Wed Apr 11 18:50:25 2001 +++ linux/arch/i386/boot/setup.S Tue May 1 16:04:56 2001 @@ -32,6 +32,16 @@ * * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * + * + * Fix to work around buggy BIOSes which dont use carry bit correctly + * and/or report extended memory in CX/DX for e801h memory size detection + * call. As a result the kernel got wrong figures. The int15/e801h docs + * from Ralf Brown interrupt list seem to indicate AX/BX should be used + * anyway. So to avoid breaking many machines (presumably there was a reason + * to orginally use CX/DX instead of AX/BX), we do a kludge to see + * if CX/DX have been changed in the e801 call and if so use AX/BX . + * Michael Miller, April 2001 + * */ #define __ASSEMBLY__ @@ -336,10 +346,24 @@ # to write everything into the same place.) meme801: + stc # fix to work around buggy + xorw %cx,%cx # BIOSes which dont clear/set + xorw %dx,%dx # carry on pass/error of + # e801h memory size call + # or merely pass cx,dx though + # without changing them. movw $0xe801, %ax int $0x15 jc mem88 + cmpw $0x0, %cx # Kludge to handle BIOSes + jne e801usecxdx # which report their extended + cmpw $0x0, %dx # memory in AX/BX rather than + jne e801usecxdx # CX/DX. The spec I have read + movw %ax, %cx # seems to indicate AX/BX + movw %bx, %dx # are more reasonable anyway... + +e801usecxdx: andl $0xffff, %edx # clear sign extend shll $6, %edx # and go from 64k to 1k chunks movl %edx, (0x1e0) # store extended memory size diff -u --recursive --new-file v2.4.4/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.4/linux/arch/i386/config.in Fri Apr 20 18:26:15 2001 +++ linux/arch/i386/config.in Thu May 24 15:14:08 2001 @@ -27,21 +27,21 @@ mainmenu_option next_comment comment 'Processor type and features' choice 'Processor family' \ - "386 CONFIG_M386 \ - 486 CONFIG_M486 \ - 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ - Pentium-Classic CONFIG_M586TSC \ - Pentium-MMX CONFIG_M586MMX \ - Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ - Pentium-III CONFIG_MPENTIUMIII \ - Pentium-4 CONFIG_MPENTIUM4 \ - K6/K6-II/K6-III CONFIG_MK6 \ - Athlon/Duron/K7 CONFIG_MK7 \ - Crusoe CONFIG_MCRUSOE \ - Winchip-C6 CONFIG_MWINCHIPC6 \ - Winchip-2 CONFIG_MWINCHIP2 \ - Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ - CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro + "386 CONFIG_M386 \ + 486 CONFIG_M486 \ + 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ + Pentium-Classic CONFIG_M586TSC \ + Pentium-MMX CONFIG_M586MMX \ + Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ + Pentium-III/Celeron(Coppermine) CONFIG_MPENTIUMIII \ + Pentium-4 CONFIG_MPENTIUM4 \ + K6/K6-II/K6-III CONFIG_MK6 \ + Athlon/Duron/K7 CONFIG_MK7 \ + Crusoe CONFIG_MCRUSOE \ + Winchip-C6 CONFIG_MWINCHIPC6 \ + Winchip-2 CONFIG_MWINCHIP2 \ + Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ + CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # diff -u --recursive --new-file v2.4.4/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.4/linux/arch/i386/defconfig Fri Apr 27 14:41:16 2001 +++ linux/arch/i386/defconfig Tue May 22 10:53:06 2001 @@ -382,6 +382,7 @@ CONFIG_EEPRO100=y # CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set @@ -441,7 +442,6 @@ # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y -# CONFIG_PCMCIA_HERMES is not set # CONFIG_PCMCIA_NETWAVE is not set # CONFIG_PCMCIA_WAVELAN is not set # CONFIG_AIRONET4500_CS is not set @@ -573,6 +573,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET 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 @@ -676,6 +677,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -700,6 +702,7 @@ # # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set # CONFIG_USB_DSBR is not set # CONFIG_USB_DABUSB is not set diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c --- v2.4.4/linux/arch/i386/kernel/bluesmoke.c Wed Apr 11 19:02:27 2001 +++ linux/arch/i386/kernel/bluesmoke.c Mon May 21 12:34:50 2001 @@ -1,16 +1,18 @@ -/* - * Machine Check Handler For PII/PIII - */ +#include #include #include #include #include #include +/* + * Machine Check Handler For PII/PIII + */ + static int banks; -void do_machine_check(struct pt_regs * regs, long error_code) +static void intel_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; @@ -62,28 +64,101 @@ wrmsr(0x17a,mcgstl, mcgsth); } +/* + * Machine check handler for Pentium class Intel + */ + +static void pentium_machine_check(struct pt_regs * regs, long error_code) +{ + u32 loaddr, hi, lotype; + rdmsr(0x0, loaddr, hi); + rdmsr(0x1, lotype, hi); + printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype); + if(lotype&(1<<5)) + printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id()); +} /* - * This has to be run for each processor + * Machine check handler for WinChip C6 + */ + +static void winchip_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id()); +} + +/* + * Handle unconfigured int18 (should never happen) */ + +static void unexpected_machine_check(struct pt_regs * regs, long error_code) +{ + printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id()); +} + +/* + * Call the installed machine check handler for this CPU setup. + */ -void mcheck_init(struct cpuinfo_x86 *c) +static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; + +void do_machine_check(struct pt_regs * regs, long error_code) +{ + machine_check_vector(regs, error_code); +} + +/* + * Set up machine check reporting for Intel processors + */ + +void __init intel_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; static int done; - - if( c->x86_vendor != X86_VENDOR_INTEL ) - return; + /* + * Check for MCE support + */ + if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) + return; + + /* + * Pentium machine check + */ + + if(c->x86 == 5) + { + machine_check_vector = pentium_machine_check; + wmb(); + /* Read registers before enabling */ + rdmsr(0x0, l, h); + rdmsr(0x1, l, h); + if(done==0) + printk(KERN_INFO "Intel old style machine check architecture supported.\n"); + /* Enable MCE */ + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x40, %%eax\n\t" + "movl %%eax, %%cr4\n\t" : : : "eax"); + printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id()); return; - + } + + + /* + * Check for PPro style MCA + */ + if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) return; /* Ok machine check is available */ + machine_check_vector = intel_machine_check; + wmb(); + if(done==0) printk(KERN_INFO "Intel machine check architecture supported.\n"); rdmsr(0x179, l, h); @@ -98,10 +173,56 @@ { wrmsr(0x401+4*i, 0x0, 0x0); } + set_in_cr4(X86_CR4_MCE); + printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); + done=1; +} + +/* + * Set up machine check reporting on the Winchip C6 series + */ + +static void winchip_mcheck_init(struct cpuinfo_x86 *c) +{ + u32 lo, hi; + /* Not supported on C3 */ + if(c->x86 != 5) + return; + /* Winchip C6 */ + machine_check_vector = winchip_machine_check; + wmb(); + rdmsr(0x107, lo, hi); + lo|= (1<<2); /* Enable EIERRINT (int 18 MCE) */ + lo&= ~(1<<4); /* Enable MCE */ + wrmsr(0x107, lo, hi); __asm__ __volatile__ ( "movl %%cr4, %%eax\n\t" "orl $0x40, %%eax\n\t" "movl %%eax, %%cr4\n\t" : : : "eax"); - printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); - done=1; + printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id()); +} + + +/* + * This has to be run for each processor + */ + +void __init mcheck_init(struct cpuinfo_x86 *c) +{ + switch(c->x86_vendor) + { + case X86_VENDOR_AMD: + /* + * AMD K7 machine check is Intel like + */ + if(c->x86 == 6) + intel_mcheck_init(c); + break; + case X86_VENDOR_INTEL: + intel_mcheck_init(c); + break; + case X86_VENDOR_CENTAUR: + winchip_mcheck_init(c); + break; + } } diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.4.4/linux/arch/i386/kernel/i386_ksyms.c Wed Apr 25 13:31:03 2001 +++ linux/arch/i386/kernel/i386_ksyms.c Tue May 15 08:46:20 2001 @@ -112,6 +112,7 @@ #ifdef CONFIG_PCI EXPORT_SYMBOL(pcibios_penalize_isa_irq); +EXPORT_SYMBOL(pci_mem_start); #endif #ifdef CONFIG_X86_USE_3DNOW diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.4/linux/arch/i386/kernel/mtrr.c Wed Apr 11 19:02:27 2001 +++ linux/arch/i386/kernel/mtrr.c Thu May 24 15:14:08 2001 @@ -646,12 +646,32 @@ unsigned long low; } centaur_mcr[8]; +static u8 centaur_mcr_reserved; +static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + +/* + * 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; +} + 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, @@ -794,7 +814,15 @@ else { high = base << PAGE_SHIFT; - low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + if(centaur_mcr_type == 0) + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + else + { + if(type == MTRR_TYPE_UNCACHABLE) + low = -size << PAGE_SHIFT | 0x02; /* NC */ + else + low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + } } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; @@ -1104,6 +1132,28 @@ return -ENOSPC; } /* End Function generic_get_free_region */ +static int centaur_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. @@ -1164,9 +1214,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1229,9 +1279,13 @@ case MTRR_IF_CENTAUR_MCR: if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) { - if (type != MTRR_TYPE_WRCOMB) + /* + * FIXME: Winchip2 supports uncached + */ + if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { - printk (KERN_WARNING "mtrr: only write-combining is supported\n"); + printk (KERN_WARNING "mtrr: only write-combining%s supported\n", + centaur_mcr_type?" and uncacheable are":" is"); return -EINVAL; } } @@ -1348,9 +1402,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1943,27 +1997,101 @@ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); } /* End Function cyrix_arr_init */ -static void __init centaur_mcr_init(void) +/* + * 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) +{ + unsigned i; + u32 lo, hi; + + /* 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<slot_name, lat); pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + unsigned long prot; + + /* I/O space cannot be accessed via normal processor loads and + * stores on this platform. + */ + if (mmap_state == pci_mmap_io) + return -EINVAL; + + /* Leave vm_pgoff as-is, the PCI space address is the physical + * address on this platform. + */ + vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO); + + prot = pgprot_val(vma->vm_page_prot); + if (boot_cpu_data.x86 > 3) + prot |= _PAGE_PCD | _PAGE_PWT; + vma->vm_page_prot = __pgprot(prot); + + /* Write-combine setting is ignored, it is changed via the mtrr + * interfaces on this platform. + */ + if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.4.4/linux/arch/i386/kernel/pci-irq.c Fri Feb 9 11:29:44 2001 +++ linux/arch/i386/kernel/pci-irq.c Wed May 16 10:25:39 2001 @@ -105,7 +105,7 @@ * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) - printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); + printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); pcibios_last_bus = -1; } @@ -295,10 +295,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); + printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } return (x & 0x80) ? 0 : (x & 0x0f); @@ -329,10 +329,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("advanced SiS pirq mapping not yet implemented\n"); + printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } pci_write_config_byte(router, reg, x); @@ -351,7 +351,7 @@ static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } return read_config_nybble(router, 0x74, pirq-1); @@ -360,7 +360,7 @@ static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } write_config_nybble(router, 0x74, pirq-1, irq); @@ -411,6 +411,7 @@ { "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_82820FW_0, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, @@ -439,13 +440,17 @@ #ifdef CONFIG_PCI_BIOS if (!rt->signature) { - printk("PCI: Using BIOS for IRQ routing\n"); + printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); pirq_router = &pirq_bios_router; return; } #endif + + DBG("PCI: Attempting to find IRQ router for %04x:%04x\n", + rt->rtr_vendor, rt->rtr_device); + /* fall back to default router if nothing else found */ - pirq_router = pirq_routers + sizeof(pirq_routers) / sizeof(pirq_routers[0]) - 1; + pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1]; pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn); if (!pirq_router_dev) { @@ -464,7 +469,7 @@ pirq_router = r; } } - printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n", + printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", pirq_router->name, pirq_router_dev->vendor, pirq_router_dev->device, @@ -568,7 +573,7 @@ } else return 0; } - printk("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); + printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ pci_for_each_dev(dev2) { @@ -582,13 +587,13 @@ if (info->irq[pin].link == pirq) { /* We refuse to override the dev->irq information. Give a warning! */ if (dev2->irq && dev2->irq != irq) { - printk("IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); + printk(KERN_INFO "IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); continue; } dev2->irq = irq; pirq_penalty[irq]++; if (dev != dev2) - printk("PCI: The same IRQ used for device %s\n", dev2->slot_name); + printk(KERN_INFO "PCI: The same IRQ used for device %s\n", dev2->slot_name); } } return 1; @@ -667,7 +672,7 @@ } #endif if (irq >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); dev->irq = irq; } diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.4/linux/arch/i386/kernel/setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/i386/kernel/setup.c Fri May 25 17:07:09 2001 @@ -127,6 +127,9 @@ unsigned int BIOS_revision; unsigned int mca_pentium_flag; +/* For PCI or other memory-mapped resources */ +unsigned long pci_mem_start = 0x10000000; + /* * Setup options */ @@ -764,7 +767,7 @@ void __init setup_arch(char **cmdline_p) { - unsigned long bootmap_size; + unsigned long bootmap_size, low_mem_size; unsigned long start_pfn, max_pfn, max_low_pfn; int i; @@ -1009,6 +1012,11 @@ for (i = 0; i < STANDARD_IO_RESOURCES; i++) request_resource(&ioport_resource, standard_io_resources+i); + /* Tell the PCI layer not to allocate too close to the RAM area.. */ + low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff; + if (low_mem_size > pci_mem_start) + pci_mem_start = low_mem_size; + #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -1657,7 +1665,7 @@ /* Unhide possibly hidden capability flags The mp6 iDragon family don't have MSRs. - We switch on extra features with this cpuid wierdness: */ + We switch on extra features with this cpuid weirdness: */ __asm__ ( "movl $0x6363452a, %%eax\n\t" "movl $0x3231206c, %%ecx\n\t" @@ -2268,7 +2276,7 @@ /* Now the feature flags better reflect actual CPU features! */ - printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2286,7 +2294,7 @@ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.4/linux/arch/i386/kernel/traps.c Mon Mar 19 18:23:40 2001 +++ linux/arch/i386/kernel/traps.c Mon May 7 14:15:21 2001 @@ -973,7 +973,7 @@ set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); - set_trap_gate(14,&page_fault); + set_intr_gate(14,&page_fault); set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); diff -u --recursive --new-file v2.4.4/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c --- v2.4.4/linux/arch/i386/lib/mmx.c Wed Apr 11 19:02:27 2001 +++ linux/arch/i386/lib/mmx.c Tue May 22 10:23:16 2001 @@ -163,7 +163,7 @@ ".previous" : : "r" (from) ); - for(i=0; i<4096/64; i++) + for(i=0; i<(4096-320)/64; i++) { __asm__ __volatile__ ( "1: prefetch 320(%0)\n" @@ -195,6 +195,29 @@ from+=64; to+=64; } + for(i=(4096-320)/64; i<4096/64; i++) + { + __asm__ __volatile__ ( + "2: movq (%0), %%mm0\n" + " movntq %%mm0, (%1)\n" + " movq 8(%0), %%mm1\n" + " movntq %%mm1, 8(%1)\n" + " movq 16(%0), %%mm2\n" + " movntq %%mm2, 16(%1)\n" + " movq 24(%0), %%mm3\n" + " movntq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm4\n" + " movntq %%mm4, 32(%1)\n" + " movq 40(%0), %%mm5\n" + " movntq %%mm5, 40(%1)\n" + " movq 48(%0), %%mm6\n" + " movntq %%mm6, 48(%1)\n" + " movq 56(%0), %%mm7\n" + " movntq %%mm7, 56(%1)\n" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } /* since movntq is weakly-ordered, a "sfence" is needed to become * ordered again. */ @@ -213,13 +236,8 @@ static void fast_clear_page(void *page) { int i; - if (!(current->flags & PF_USEDFPU)) - clts(); - else - { - __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); - current->flags &= ~PF_USEDFPU; - } + + kernel_fpu_begin(); __asm__ __volatile__ ( " pxor %%mm0, %%mm0\n" : : @@ -247,19 +265,16 @@ : : "r" (page) : "memory"); page+=128; } - stts(); + + kernel_fpu_end(); } static void fast_copy_page(void *to, void *from) { int i; - if (!(current->flags & PF_USEDFPU)) - clts(); - else - { - __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); - current->flags &= ~PF_USEDFPU; - } + + + kernel_fpu_begin(); __asm__ __volatile__ ( "1: prefetch (%0)\n" @@ -310,7 +325,7 @@ from+=64; to+=64; } - stts(); + kernel_fpu_end(); } diff -u --recursive --new-file v2.4.4/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.4.4/linux/arch/i386/mm/fault.c Mon Mar 19 12:35:09 2001 +++ linux/arch/i386/mm/fault.c Tue May 15 00:16:51 2001 @@ -117,6 +117,10 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + /* It's safe to allow irq's after cr2 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + tsk = current; /* @@ -127,8 +131,12 @@ * be in an interrupt or a critical region, and should * only copy the information from the master page table, * nothing more. + * + * This verifies that the fault happens in kernel space + * (error_code & 4) == 0, and that the fault was not a + * protection error (error_code & 1) == 0. */ - if (address >= TASK_SIZE) + if (address >= TASK_SIZE && !(error_code & 5)) goto vmalloc_fault; mm = tsk->mm; @@ -224,7 +232,6 @@ bad_area: up_read(&mm->mmap_sem); -bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { tsk->thread.cr2 = address; @@ -322,27 +329,32 @@ /* * Synchronize this task's top level page-table * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. */ int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; + pte_t *pte_k; - pgd = tsk->active_mm->pgd + offset; + asm("movl %%cr3,%0":"=r" (pgd)); + pgd = offset + (pgd_t *)__va(pgd); pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd)) { - if (!pgd_present(*pgd_k)) - goto bad_area_nosemaphore; - set_pgd(pgd, *pgd_k); - return; - } - + if (!pgd_present(*pgd_k)) + goto no_context; + set_pgd(pgd, *pgd_k); + pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) - goto bad_area_nosemaphore; + if (!pmd_present(*pmd_k)) + goto no_context; set_pmd(pmd, *pmd_k); + + pte_k = pte_offset(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; return; } } diff -u --recursive --new-file v2.4.4/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.4.4/linux/arch/m68k/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/m68k/config.in Mon May 21 18:12:09 2001 @@ -192,7 +192,7 @@ int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + if [ "$CONFIG_CHR_DEV_ST" != "n" ]; then int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 fi dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI diff -u --recursive --new-file v2.4.4/linux/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S --- v2.4.4/linux/arch/m68k/lib/semaphore.S Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/lib/semaphore.S Sat May 19 17:43:05 2001 @@ -51,49 +51,3 @@ moveml (%sp)+,%a0/%d0/%d1 rts -ENTRY(__down_read_failed) - moveml %a0/%d0/%d1,-(%sp) - jcc 3f -1: movel %a1,-(%sp) - jbsr SYMBOL_NAME(down_read_failed_biased) - movel (%sp)+,%a1 -2: moveml (%sp)+,%a0/%d0/%d1 - rts - -3: movel %a1,-(%sp) - jbsr SYMBOL_NAME(down_read_failed) - movel (%sp)+,%a1 - subql #1,%a1@ - jpl 2b - jcc 3b - jra 1b - -ENTRY(__down_write_failed) - moveml %a0/%d0/%d1,-(%sp) - jcc 3f -1: movel %a1,-(%sp) - jbsr SYMBOL_NAME(down_write_failed_biased) - movel (%sp)+,%a1 -2: moveml (%sp)+,%a0/%d0/%d1 - rts - -3: movel %a1,-(%sp) - jbsr SYMBOL_NAME(down_write_failed) - movel (%sp)+,%a1 - subl #RW_LOCK_BIAS,%a1@ - jpl 2b - jcc 3b - jra 1b - -ENTRY(__rwsem_wake) - moveml %a0/%d0/%d1,-(%sp) - jeq 1f - movel %a1,-(%sp) - jbsr SYMBOL_NAME(rwsem_wake_readers) - jra 2f -1: movel %a1,-(%sp) - jbsr rwsem_wake_writer -2: movel (%sp)+,%a1 - moveml (%sp)+,%a0/%d0/%d1 - rts - diff -u --recursive --new-file v2.4.4/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.4.4/linux/arch/m68k/mm/memory.c Fri Feb 9 11:29:44 2001 +++ linux/arch/m68k/mm/memory.c Sat May 19 17:43:05 2001 @@ -246,6 +246,10 @@ voff -= m68k_memory[i].size; } while (++i < m68k_num_memory); + /* As a special case allow `__pa(high_memory)'. */ + if (voff == 0) + return m68k_memory[i-1].addr + m68k_memory[i-1].size; + return mm_vtop_fallback(vaddr); } #endif diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8260_io/Makefile linux/arch/ppc/8260_io/Makefile --- v2.4.4/linux/arch/ppc/8260_io/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/8260_io/Makefile Mon May 21 17:04:46 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort +# # # Makefile for the linux MPC8xx ppc-specific parts of comm processor # diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8260_io/commproc.c linux/arch/ppc/8260_io/commproc.c --- v2.4.4/linux/arch/ppc/8260_io/commproc.c Sun Sep 17 09:48:05 2000 +++ linux/arch/ppc/8260_io/commproc.c Mon May 21 17:04:46 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.commproc.c 1.5 05/17/01 18:14:19 cort + */ /* * General Purpose functions for the global management of the diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8260_io/enet.c linux/arch/ppc/8260_io/enet.c --- v2.4.4/linux/arch/ppc/8260_io/enet.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/8260_io/enet.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.enet.c 1.6 05/17/01 18:14:19 cort + */ +/* * Ethernet driver for Motorola MPC8260. * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8260_io/fcc_enet.c linux/arch/ppc/8260_io/fcc_enet.c --- v2.4.4/linux/arch/ppc/8260_io/fcc_enet.c Fri Feb 16 16:02:34 2001 +++ linux/arch/ppc/8260_io/fcc_enet.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.fcc_enet.c 1.7 05/17/01 18:14:20 cort + */ +/* * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c --- v2.4.4/linux/arch/ppc/8260_io/uart.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/8260_io/uart.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.uart.c 1.6 05/17/01 18:14:20 cort + */ +/* * UART driver for MPC8260 CPM SCC or SMC * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) * Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in --- v2.4.4/linux/arch/ppc/8xx_io/Config.in Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/Config.in Wed May 16 09:57:20 2001 @@ -18,12 +18,12 @@ fi bool 'Use Big CPM Ethernet Buffers' CONFIG_ENET_BIG_BUFFERS fi -bool 'Use SMC2 for UART' CONFIG_8xxSMC2 -if [ "$CONFIG_8xxSMC2" = "y" ]; then - bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_8xx_ALTSMC2 - bool 'Use SMC2 for Console' CONFIG_8xx_CONS_SMC2 +bool 'Use SMC2 for UART' CONFIG_SMC2_UART +if [ "$CONFIG_SMC2_UART" = "y" ]; then + bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_ALTSMC2 + bool 'Use SMC2 for Console' CONFIG_CONS_SMC2 fi -bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC +bool 'Enable SCC2 and SCC3 for UART' CONFIG_USE_SCC_IO # This doesn't really belong here, but it is convenient to ask # 8xx specific questions. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/Makefile linux/arch/ppc/8xx_io/Makefile --- v2.4.4/linux/arch/ppc/8xx_io/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/8xx_io/Makefile Mon May 21 17:04:46 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:20 cort +# # # Makefile for the linux MPC8xx ppc-specific parts of comm processor # diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c --- v2.4.4/linux/arch/ppc/8xx_io/commproc.c Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/commproc.c Mon May 21 17:04:46 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.commproc.c 1.8 05/18/01 07:54:04 patch + */ /* * General Purpose functions for the global management of the @@ -218,7 +221,7 @@ * The internal baud rate clock is the system clock divided by 16. * This assumes the baudrate is 16x oversampled by the uart. */ -#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) +#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq) #define BRG_UART_CLK (BRG_INT_CLK/16) #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h --- v2.4.4/linux/arch/ppc/8xx_io/commproc.h Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/commproc.h Mon May 21 17:04:46 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.commproc.h 1.8 05/17/01 18:14:20 cort + */ /* * MPC8xx Communication Processor Module. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c --- v2.4.4/linux/arch/ppc/8xx_io/enet.c Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/enet.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.enet.c 1.10 05/17/01 18:14:20 cort + */ +/* * Ethernet driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.4.4/linux/arch/ppc/8xx_io/fec.c Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/fec.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.fec.c 1.12 05/18/01 07:54:04 patch + */ +/* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * @@ -1686,10 +1689,7 @@ /* Set MII speed to 2.5 MHz */ fecp->fec_mii_speed = fep->phy_speed = - ( - ( ((bd->bi_intfreq * 1000000) + 500000) / 2500000 / 2 ) - & 0x3F - ) << 1; + (( (bd->bi_intfreq + 500000) / 2500000 / 2 ) & 0x3F ) << 1; #else fecp->fec_mii_speed = 0; /* turn off MDIO */ #endif /* CONFIG_USE_MDIO */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.4.4/linux/arch/ppc/8xx_io/uart.c Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/8xx_io/uart.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.uart.c 1.10 05/17/01 18:14:20 cort + */ +/* * UART driver for MPC860 CPM SCC or SMC * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * @@ -55,17 +58,17 @@ */ # ifndef CONFIG_SERIAL_CONSOLE_PORT # ifdef CONFIG_SCC3_ENET -# ifdef CONFIG_8xx_CONS_SMC2 +# ifdef CONFIG_CONS_SMC2 # define CONFIG_SERIAL_CONSOLE_PORT 0 /* Console on SMC2 is 1st port */ # else # error "Can't use SMC1 for console with Ethernet on SCC3" # endif # else /* ! CONFIG_SCC3_ENET */ -# ifdef CONFIG_8xx_CONS_SMC2 /* Console on SMC2 */ +# ifdef CONFIG_CONS_SMC2 /* Console on SMC2 */ # define CONFIG_SERIAL_CONSOLE_PORT 1 # else /* Console on SMC1 */ # define CONFIG_SERIAL_CONSOLE_PORT 0 -# endif /* CONFIG_8xx_CONS_SMC2 */ +# endif /* CONFIG_CONS_SMC2 */ # endif /* CONFIG_SCC3_ENET */ # endif /* CONFIG_SERIAL_CONSOLE_PORT */ #endif /* CONFIG_SERIAL_CONSOLE */ @@ -134,15 +137,15 @@ { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ #endif #if !defined(CONFIG_USB_MPC8xx) && !defined(CONFIG_USB_CLIENT_MPC8xx) -# ifdef CONFIG_8xxSMC2 +# ifdef CONFIG_SMC2_UART { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ # endif -# ifdef CONFIG_8xxSCC +# ifdef CONFIG_USE_SCC_IO { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) }, /* SCC2 ttyS2 */ { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ # endif #else /* CONFIG_USB_xxx */ -# ifdef CONFIG_8xxSCC +# ifdef CONFIG_USE_SCC_IO { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ # endif #endif /* CONFIG_USB_xxx */ @@ -2533,7 +2536,7 @@ /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. */ -#ifdef CONFIG_8xxSCC +#ifdef CONFIG_USE_SCC_IO #ifndef CONFIG_MBX /* The "standard" configuration through the 860. */ @@ -2747,7 +2750,7 @@ * parallel I/O. On 823/850 these are on * port A for SMC2. */ -#ifndef CONFIG_8xx_ALTSMC2 +#ifndef CONFIG_ALTSMC2 iobits = 0xc0 << (idx * 4); cp->cp_pbpar |= iobits; cp->cp_pbdir &= ~iobits; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.4.4/linux/arch/ppc/Makefile Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/Makefile Thu May 24 15:02:06 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.13 05/21/01 00:48:24 cort +# # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. Remember to do have actions # for "archclean" and "archdep" for cleaning up and making dependencies for @@ -31,7 +33,7 @@ endif ifdef CONFIG_8xx -CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io +CFLAGS := $(CFLAGS) -mcpu=860 endif ifdef CONFIG_PPC64BRIDGE @@ -65,10 +67,6 @@ endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot -MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot -MAKEMBXBOOT = $(MAKE) -C arch/$(ARCH)/mbxboot -MAKETREEBOOT = $(MAKE) -C arch/$(ARCH)/treeboot ifdef CONFIG_8xx SUBDIRS += arch/ppc/8xx_io @@ -89,108 +87,20 @@ checks: @$(MAKE) -C arch/$(ARCH)/kernel checks -BOOT_TARGETS = zImage znetboot.initrd zImage.initrd - -ifdef CONFIG_4xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKETREEBOOT) $@ -endif - -ifdef CONFIG_8xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEMBXBOOT) $@ -endif +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd -ifdef CONFIG_6xx -ifndef CONFIG_8260 $(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ -znetboot: $(CHECKS) vmlinux -ifdef CONFIG_ALL_PPC -ifdef CONFIG_SMP - cp -f vmlinux /tftpboot/vmlinux.smp -else - cp -f vmlinux /tftpboot/vmlinux -endif -endif - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ -else -# 8260 is custom 6xx -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEMBXBOOT) $@ -endif -endif - -ifdef CONFIG_PPC64BRIDGE -$(BOOT_TARGETS): $(CHECKS) vmlinux - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ - -znetboot: $(CHECKS) vmlinux - cp -f vmlinux /tftpboot/vmlinux.64 - @$(MAKECOFFBOOT) $@ - @$(MAKEBOOT) $@ - @$(MAKECHRPBOOT) $@ -endif - -.PHONY: clean_config -clean_config: +%_config: arch/ppc/configs/%_defconfig rm -f .config arch/ppc/defconfig - -pmac_config: clean_config - cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig - -prep_config: clean_config - cp -f arch/ppc/configs/prep_defconfig arch/ppc/defconfig - -chrp_config: clean_config - cp -f arch/ppc/configs/chrp_defconfig arch/ppc/defconfig - -common_config: clean_config - cp -f arch/ppc/configs/common_defconfig arch/ppc/defconfig - -mbx_config: clean_config - cp -f arch/ppc/configs/mbx_defconfig arch/ppc/defconfig - -apus_config: clean_config - cp -f arch/ppc/configs/apus_defconfig arch/ppc/defconfig - -oak_config: clean_config - cp -f arch/ppc/configs/oak_defconfig arch/ppc/defconfig - -walnut_config: clean_config - cp -f arch/ppc/configs/walnut_defconfig arch/ppc/defconfig - -rpxlite_config: clean_config - cp -f arch/ppc/configs/rpxlite_defconfig arch/ppc/defconfig - -rpxcllf_config: clean_config - cp -f arch/ppc/configs/rpxcllf_defconfig arch/ppc/defconfig - -bseip_config: clean_config - cp -f arch/ppc/configs/bseip_defconfig arch/ppc/defconfig - -est8260_config: clean_config - cp -f arch/ppc/configs/est8260_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/$(@:config=defconfig) arch/ppc/defconfig archclean: rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} - @$(MAKECOFFBOOT) clean @$(MAKEBOOT) clean - @$(MAKECHRPBOOT) clean - @$(MAKEMBXBOOT) clean - @$(MAKETREEBOOT) clean archmrproper: archdep: - $(MAKEBOOT) fastdep - $(MAKECHRPBOOT) fastdep + $(MAKEBOOT) dep diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/Makefile linux/arch/ppc/amiga/Makefile --- v2.4.4/linux/arch/ppc/amiga/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/amiga/Makefile Mon May 21 17:04:46 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.5 05/21/01 00:48:24 cort +# # # Makefile for Linux arch/m68k/amiga source directory # @@ -14,6 +16,6 @@ obj-y := config.o amiints.o cia.o time.o bootinfo.o amisound.o \ chipram.o amiga_ksyms.o -obj-$(CONFIG_AMIGA_PCMCIA) += pcmia.o +obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/amiga_ksyms.c linux/arch/ppc/amiga/amiga_ksyms.c --- v2.4.4/linux/arch/ppc/amiga/amiga_ksyms.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/amiga/amiga_ksyms.c Mon May 21 17:04:46 2001 @@ -1 +1,4 @@ +/* + * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort + */ #include "../../m68k/amiga/amiga_ksyms.c" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.4.4/linux/arch/ppc/amiga/amiints.c Fri Feb 16 16:02:34 2001 +++ linux/arch/ppc/amiga/amiints.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.amiints.c 1.8 05/21/01 00:48:24 cort + */ +/* * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code * * This file is subject to the terms and conditions of the GNU General Public @@ -255,9 +258,10 @@ return; } - if (irq >= IRQ_AMIGA_AUTO) + if (irq >= IRQ_AMIGA_AUTO) { sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); - + return; + } if (irq >= IRQ_AMIGA_CIAA) { cia_free_irq(irq, dev_id); return; @@ -295,7 +299,10 @@ return; } - if (--ami_ablecount[irq]) + ami_ablecount[irq]--; + if (ami_ablecount[irq]<0) + ami_ablecount[irq]=0; + else if (ami_ablecount[irq]) return; /* No action for auto-vector interrupts */ @@ -347,64 +354,16 @@ ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } -void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) +void amiga_do_irq_list(int irq, struct pt_regs *fp) { - irq_node_t *node, *slow_nodes; - unsigned short intena; - unsigned long flags; + irq_node_t *node; kstat.irqs[0][SYS_IRQS + irq]++; - if (server->count++) - server->reentrance = 1; - - intena = ami_intena_vals[irq]; - custom.intreq = intena; - /* serve first fast handlers - there can only be one of these */ - node = ami_irq_list[irq]; - - /* - * Timer interrupts show up like this - */ - if (!node) { - server->count--; - return; - } + custom.intreq = ami_intena_vals[irq]; - if (node && (node->flags & SA_INTERRUPT)) { - save_flags(flags); - cli(); + for (node = ami_irq_list[irq]; node; node = node->next) node->handler(irq, node->dev_id, fp); - restore_flags(flags); - - server->count--; - return; - } - - /* - * Disable the interrupt source in question and reenable all - * other interrupts. No interrupt handler should ever touch - * the intena flags directly! - */ - custom.intena = intena; - save_flags(flags); - sti(); - - slow_nodes = node; - for (;;) { - for (; node; node = node->next) - node->handler(irq, node->dev_id, fp); - - if (!server->reentrance) { - server->count--; - restore_flags(flags); - custom.intena = IF_SETCLR | intena; - return; - } - - server->reentrance = 0; - node = slow_nodes; - } } /* @@ -437,7 +396,6 @@ static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) { unsigned short ints = custom.intreqr & custom.intenar; - static struct irq_server server = {0, 0}; /* if a blitter interrupt */ if (ints & IF_BLIT) { @@ -453,7 +411,7 @@ /* if a vertical blank interrupt */ if (ints & IF_VERTB) - amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); } static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) @@ -512,7 +470,7 @@ and executes them in a loop. Having ami_badint at the end of the chain is a bad idea. */ void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { - NULL, ami_int1, NULL, NULL /* FB expects to replace ami_int3*/, + NULL, ami_int1, NULL, ami_int3, ami_int4, ami_int5, NULL, ami_int7 }; #else diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/amisound.c linux/arch/ppc/amiga/amisound.c --- v2.4.4/linux/arch/ppc/amiga/amisound.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/amiga/amisound.c Mon May 21 17:04:46 2001 @@ -1 +1,4 @@ +/* + * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort + */ #include "../../m68k/amiga/amisound.c" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/bootinfo.c linux/arch/ppc/amiga/bootinfo.c --- v2.4.4/linux/arch/ppc/amiga/bootinfo.c Thu Oct 7 10:17:08 1999 +++ linux/arch/ppc/amiga/bootinfo.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort + */ +/* * linux/arch/ppc/amiga/bootinfo.c * * Extracted from arch/m68k/kernel/setup.c. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/chipram.c linux/arch/ppc/amiga/chipram.c --- v2.4.4/linux/arch/ppc/amiga/chipram.c Tue Jul 11 11:18:53 2000 +++ linux/arch/ppc/amiga/chipram.c Mon May 21 17:04:46 2001 @@ -1,183 +1,4 @@ /* -** linux/amiga/chipram.c -** -** Modified 03-May-94 by Geert Uytterhoeven -** - 64-bit aligned allocations for full AGA compatibility -*/ - -#include -#include -#include -#include -#include -#include - -struct chip_desc { - unsigned first : 1; - unsigned last : 1; - unsigned alloced : 1; - unsigned length : 24; - long pad; /* We suppose this makes this struct 64 bits long!! */ -}; - -#define DP(ptr) ((struct chip_desc *)(ptr)) - -u_long amiga_chip_size; -static unsigned long chipavail; - -static struct resource chipram = { "Chip RAM", 0 }; - -unsigned long amiga_chip_avail( void ) -{ -#ifdef DEBUG - printk("chip_avail : %ld bytes\n",chipavail); -#endif - return chipavail; -} - - -void __init amiga_chip_init (void) -{ - struct chip_desc *dp; - - if (!AMIGAHW_PRESENT(CHIP_RAM)) - return; - -#ifndef CONFIG_APUS_FAST_EXCEPT - /* - * Remove the first 4 pages where PPC exception handlers will - * be located. - */ - amiga_chip_size -= 0x4000; -#endif - chipram.end = amiga_chip_size-1; - request_resource(&iomem_resource, &chipram); - - /* initialize start boundary */ - - dp = DP(chipaddr); - dp->first = 1; - - dp->alloced = 0; - dp->length = amiga_chip_size - 2*sizeof(*dp); - - /* initialize end boundary */ - dp = DP(chipaddr + amiga_chip_size) - 1; - dp->last = 1; - - dp->alloced = 0; - dp->length = amiga_chip_size - 2*sizeof(*dp); - chipavail = dp->length; /*MILAN*/ - -#ifdef DEBUG - printk ("chipram end boundary is %p, length is %d\n", dp, - dp->length); -#endif -} - -void *amiga_chip_alloc(long size, const char *name) -{ - /* last chunk */ - struct chip_desc *dp; - void *ptr; - - /* round off */ - size = (size + 7) & ~7; - -#ifdef DEBUG - printk("amiga_chip_alloc: allocate %ld bytes\n", size); -#endif - - /* - * get pointer to descriptor for last chunk by - * going backwards from end chunk - */ - dp = DP(chipaddr + amiga_chip_size) - 1; - dp = DP((unsigned long)dp - dp->length) - 1; - - while ((dp->alloced || dp->length < size) - && !dp->first) - dp = DP ((unsigned long)dp - dp[-1].length) - 2; - - if (dp->alloced || dp->length < size) { - printk ("no chipmem available for %ld allocation\n", size); - return NULL; - } - - if (dp->length < (size + 2*sizeof(*dp))) { - /* length too small to split; allocate the whole thing */ - dp->alloced = 1; - ptr = (void *)(dp+1); - dp = DP((unsigned long)ptr + dp->length); - dp->alloced = 1; -#ifdef DEBUG - printk ("amiga_chip_alloc: no split\n"); -#endif - } else { - /* split the extent; use the end part */ - long newsize = dp->length - (2*sizeof(*dp) + size); - -#ifdef DEBUG - printk ("amiga_chip_alloc: splitting %d to %ld\n", dp->length, - newsize); -#endif - dp->length = newsize; - dp = DP((unsigned long)(dp+1) + newsize); - dp->first = dp->last = 0; - dp->alloced = 0; - dp->length = newsize; - dp++; - dp->first = dp->last = 0; - dp->alloced = 1; - dp->length = size; - ptr = (void *)(dp+1); - dp = DP((unsigned long)ptr + size); - dp->alloced = 1; - dp->length = size; - } - -#ifdef DEBUG - printk ("amiga_chip_alloc: returning %p\n", ptr); -#endif - - if ((unsigned long)ptr & 7) - panic("amiga_chip_alloc: alignment violation\n"); - - chipavail -= size + (2*sizeof(*dp)); /*MILAN*/ - - if (!request_mem_region(ZTWO_PADDR(ptr), size, name)) - printk(KERN_WARNING "amiga_chip_alloc: region of size %ld at 0x%08lx " - "is busy\n", size, ZTWO_PADDR(ptr)); - - return ptr; -} - -void amiga_chip_free (void *ptr) -{ - struct chip_desc *sdp = DP(ptr) - 1, *dp2; - struct chip_desc *edp = DP((unsigned long)ptr + sdp->length); - - chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/ -#ifdef DEBUG - printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr); -#endif - /* deallocate the chunk */ - sdp->alloced = edp->alloced = 0; - release_mem_region(ZTWO_PADDR(ptr), sdp->length); - - /* check if we should merge with the previous chunk */ - if (!sdp->first && !sdp[-1].alloced) { - dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2; - dp2->length += sdp->length + 2*sizeof(*sdp); - edp->length = dp2->length; - sdp = dp2; - } - - /* check if we should merge with the following chunk */ - if (!edp->last && !edp[1].alloced) { - dp2 = DP((unsigned long)edp + edp[1].length) + 2; - dp2->length += edp->length + 2*sizeof(*sdp); - sdp->length = dp2->length; - edp = dp2; - } -} + * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort + */ +#include "../../m68k/amiga/chipram.c" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/cia.c linux/arch/ppc/amiga/cia.c --- v2.4.4/linux/arch/ppc/amiga/cia.c Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/amiga/cia.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.cia.c 1.7 05/21/01 00:48:24 cort + */ +/* * linux/arch/m68k/amiga/cia.c - CIA support * * Copyright (C) 1996 Roman Zippel @@ -27,18 +30,17 @@ u_short int_mask; int handler_irq, cia_irq, server_irq; char *name; - struct irq_server server; irq_handler_t irq_list[CIA_IRQS]; } ciaa_base = { &ciaa, 0, 0, IF_PORTS, IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA, IRQ_AMIGA_PORTS, - "CIAA handler", {0, 0} + "CIAA handler" }, ciab_base = { &ciab, 0, 0, IF_EXTER, IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB, IRQ_AMIGA_EXTER, - "CIAB handler", {0, 0} + "CIAB handler" }; #define CIA_SET_BASE_ADJUST_IRQ(base, irq) \ @@ -197,7 +199,7 @@ } ints >>= 1; } - amiga_do_irq_list(base->server_irq, fp, &base->server); + amiga_do_irq_list(base->server_irq, fp); } void __init cia_init_IRQ(struct ciabase *base) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c --- v2.4.4/linux/arch/ppc/amiga/config.c Mon Nov 27 17:57:34 2000 +++ linux/arch/ppc/amiga/config.c Mon May 21 17:04:46 2001 @@ -1,12 +1,8 @@ +/* + * BK Id: SCCS/s.config.c 1.7 05/21/01 00:48:24 cort + */ #define m68k_debug_device debug_device -#include - -/* machine dependent "kbd-reset" setup function */ -void (*mach_kbd_reset_setup) (char *, int) __initdata = 0; - -#include - /* * linux/arch/m68k/amiga/config.c * @@ -28,6 +24,10 @@ #include #include #include +#include +#ifdef CONFIG_ZORRO +#include +#endif #include #include @@ -36,10 +36,12 @@ #include #include #include +#include #include -#include +#include unsigned long powerup_PCI_present; +unsigned long powerup_BPPCPLUS_present; unsigned long amiga_model; unsigned long amiga_eclock; unsigned long amiga_masterclock; @@ -121,7 +123,7 @@ }; #ifdef CONFIG_MAGIC_SYSRQ -static char amiga_sysrq_xlate[128] = +char amiga_sysrq_xlate[128] = "\0001234567890-=\\\000\000" /* 0x00 - 0x0f */ "qwertyuiop[]\000123" /* 0x10 - 0x1f */ "asdfghjkl;'\000\000456" /* 0x20 - 0x2f */ @@ -139,16 +141,18 @@ * Motherboard Resources present in all Amiga models */ -static struct resource mb_res[] = { - { "Ranger Memory", 0x00c00000, 0x00c7ffff }, - { "CIA B", 0x00bfd000, 0x00bfdfff }, - { "CIA A", 0x00bfe000, 0x00bfefff }, - { "Custom I/O", 0x00dff000, 0x00dfffff }, - { "Kickstart ROM", 0x00f80000, 0x00ffffff } +static struct { + struct resource _ciab, _ciaa, _custom, _kickstart; +} mb_resources = { +// { "Ranger Memory", 0x00c00000, 0x00c7ffff }, + _ciab: { "CIA B", 0x00bfd000, 0x00bfdfff }, + _ciaa: { "CIA A", 0x00bfe000, 0x00bfefff }, + _custom: { "Custom I/O", 0x00dff000, 0x00dfffff }, + _kickstart: { "Kickstart ROM", 0x00f80000, 0x00ffffff } }; static struct resource rtc_resource = { - "A2000 RTC", 0x00dc0000, 0x00dcffff + NULL, 0x00dc0000, 0x00dcffff }; static struct resource ram_resource[NUM_MEMINFO]; @@ -194,6 +198,7 @@ break; case BI_AMIGA_AUTOCON: +#ifdef CONFIG_ZORRO if (zorro_num_autocon < ZORRO_NUM_AUTO) { const struct ConfigDev *cd = (struct ConfigDev *)data; struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; @@ -204,12 +209,21 @@ dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; } else printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); +#endif /* CONFIG_ZORRO */ break; case BI_AMIGA_SERPER: /* serial port period: ignored here */ break; + case BI_AMIGA_PUP_BRIDGE: + powerup_PCI_present = *(const unsigned short *)data; + break; + + case BI_AMIGA_BPPC_SCSI: + powerup_BPPCPLUS_present = *(const unsigned short *)data; + break; + default: unknown = 1; } @@ -392,11 +406,8 @@ /* Some APUS boxes may have PCI memory, but ... */ iomem_resource.name = "Memory"; - request_resource(&iomem_resource, &ranger_resource); - request_resource(&iomem_resource, &ciab_resource); - request_resource(&iomem_resource, &ciaa_resource); - request_resource(&iomem_resource, &custom_chips_resource); - request_resource(&iomem_resource, &kickstart_resource); + for (i = 0; i < 4; i++) + request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; @@ -415,11 +426,12 @@ mach_gettimeoffset = amiga_gettimeoffset; if (AMIGAHW_PRESENT(A3000_CLK)){ mach_gettod = a3000_gettod; - rtc_resource.name[1] = '3'; + rtc_resource.name = "A3000 RTC"; request_resource(&iomem_resource, &rtc_resource); } else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ mach_gettod = a2000_gettod; + rtc_resource.name = "A2000 RTC"; request_resource(&iomem_resource, &rtc_resource); } @@ -439,14 +451,10 @@ mach_floppy_setup = amiga_floppy_setup; #endif mach_reset = amiga_reset; +#ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; - kd_mksound = amiga_mksound; -#ifdef CONFIG_MAGIC_SYSRQ - mach_sysrq_key = 0x5f; /* HELP */ - mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */ - mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ - mach_sysrq_xlate = amiga_sysrq_xlate; #endif + kd_mksound = amiga_mksound; #ifdef CONFIG_HEARTBEAT mach_heartbeat = amiga_heartbeat; #endif @@ -500,11 +508,14 @@ static unsigned short jiffy_ticks; static void __init amiga_sched_init(void (*timer_routine)(int, void *, - struct pt_regs *)) + struct pt_regs *)) { + static struct resource sched_res = { + "timer", 0x00bfd400, 0x00bfd5ff, + }; jiffy_ticks = (amiga_eclock+HZ/2)/HZ; - if (!request_mem_region(CIAB_PHYSADDR+0x400, 0x200, "timer")) + if (request_resource(&mb_resources._ciab, &sched_res)) printk("Cannot allocate ciab.ta{lo,hi}\n"); ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; @@ -612,6 +623,8 @@ t->wday = tod->weekday; t->mon = tod->month1 * 10 + tod->month2 - 1; t->year = tod->year1 * 10 + tod->year2; + if (t->year <= 69) + t->year += 100; } else { tod->second1 = t->sec / 10; tod->second2 = t->sec % 10; @@ -625,6 +638,8 @@ tod->weekday = t->wday; tod->month1 = (t->mon + 1) / 10; tod->month2 = (t->mon + 1) % 10; + if (t->year >= 100) + t->year -= 100; tod->year1 = t->year / 10; tod->year2 = t->year % 10; } @@ -646,6 +661,8 @@ t->wday = tod->weekday; t->mon = tod->month1 * 10 + tod->month2 - 1; t->year = tod->year1 * 10 + tod->year2; + if (t->year <= 69) + t->year += 100; if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) @@ -672,6 +689,8 @@ tod->weekday = t->wday; tod->month1 = (t->mon + 1) / 10; tod->month2 = (t->mon + 1) % 10; + if (t->year >= 100) + t->year -= 100; tod->year1 = t->year / 10; tod->year2 = t->year % 10; } @@ -796,7 +815,9 @@ static void amiga_savekmsg_init(void) { - savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug"); + static struct resource debug_res = { "Debug" }; + + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); savekmsg->magic1 = SAVEKMSG_MAGIC1; savekmsg->magic2 = SAVEKMSG_MAGIC2; savekmsg->magicptr = virt_to_phys(savekmsg); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/ints.c linux/arch/ppc/amiga/ints.c --- v2.4.4/linux/arch/ppc/amiga/ints.c Fri Nov 12 04:29:47 1999 +++ linux/arch/ppc/amiga/ints.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort + */ +/* * linux/arch/ppc/amiga/ints.c * * Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/pcmcia.c linux/arch/ppc/amiga/pcmcia.c --- v2.4.4/linux/arch/ppc/amiga/pcmcia.c Thu Oct 7 10:17:08 1999 +++ linux/arch/ppc/amiga/pcmcia.c Mon May 21 17:04:46 2001 @@ -1 +1,4 @@ +/* + * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort + */ #include "../../m68k/amiga/pcmcia.c" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/amiga/time.c linux/arch/ppc/amiga/time.c --- v2.4.4/linux/arch/ppc/amiga/time.c Mon Sep 11 08:39:48 2000 +++ linux/arch/ppc/amiga/time.c Mon May 21 17:04:46 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.time.c 1.5 05/17/01 18:14:20 cort + */ #include /* CONFIG_HEARTBEAT */ #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.4.4/linux/arch/ppc/boot/Makefile Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/boot/Makefile Thu May 24 15:02:06 2001 @@ -9,127 +9,88 @@ # Adapted for PowerPC by Gary Thomas # modified by Cort (cort@cs.nmt.edu) # + .c.s: $(CC) $(CFLAGS) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -D__BOOTER__ -c -o $*.o $< + $(CC) $(CFLAGS) -c -o $*.o $< .S.s: $(CPP) $(AFLAGS) -traditional -o $*.o $< .S.o: $(CC) $(AFLAGS) -traditional -c -o $*.o $< -ZOFF = 0 -ZSZ = 0 -IOFF = 0 -ISZ = 0 +GZIP_FLAGS = -v9f -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE) -endif +CFLAGS := $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -D__BOOTER__ \ + -I$(TOPDIR)/arch/$(ARCH)/boot/include +AFLAGS += -D__BOOTER__ +OBJCOPY_ARGS = -O elf32-powerpc -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 +ifeq ($(CONFIG_SMP),y) +TFTPSIMAGE=/tftpboot/sImage.smp else -MSIZE= +TFTPSIMAGE=/tftpboot/sImage endif -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 -GZIP_FLAGS = -v9f +lib/zlib.a: + $(MAKE) -C lib -OBJECTS := head.o misc.o ../coffboot/zlib.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -OBJCOPY_ARGS = -O elf32-powerpc +images/vmlinux.gz: $(TOPDIR)/vmlinux + $(MAKE) -C images vmlinux.gz -OBJECTS += vreset.o kbd.o of1275.o -ifeq ($(CONFIG_SERIAL_CONSOLE),y) -OBJECTS += ns16550.o -endif - -all: zImage - -zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ - -D__BOOTER__ \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ - rm zvmlinux.initrd.tmp +# Since gemini doesn't need/have it's own directory, we do znetboot* here +ifdef CONFIG_GEMINI +BOOT_TARGETS = zImage zImage.initrd +else +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd +endif -zImage: zvmlinux mkprep +# We go into the utils dir by hand to ensure HOSTCC builds +$(BOOT_TARGETS): sImage vmapus lib/zlib.a images/vmlinux.gz +ifneq ("xx$(CONFIG_8260)$(CONFIG_8xx)","xx") + $(MAKE) -C mbx $@ +endif ifdef CONFIG_ALL_PPC - ./mkprep -pbp zvmlinux zImage + $(MAKE) -C utils addnote piggyback mknote hack-coff mkprep + $(MAKE) -C chrp $@ + $(MAKE) -C pmac $@ + $(MAKE) -C prep $@ endif -ifdef CONFIG_APUS - $(STRIP) ../../../vmlinux -o vmapus - gzip $(GZIP_FLAGS) vmapus +ifdef CONFIG_4xx + $(MAKE) -C tree $@ endif -zImage.initrd: zvmlinux.initrd mkprep -ifdef CONFIG_ALL_PPC - ./mkprep -pbp zvmlinux.initrd zImage.initrd +sImage: $(TOPDIR)/vmlinux +ifdef CONFIG_GEMINI + $(OBJCOPY) -I elf32-powerpc -O binary $(TOPDIR)/vmlinux images/sImage endif -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ - -D__BOOTER__ \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp - -floppy: $(TOPDIR)/vmlinux zImage - dd if=zImage of=/dev/fd0H1440 bs=64b - -mkprep : mkprep.c - $(HOSTCC) -o mkprep mkprep.c +vmapus: $(TOPDIR)/vmlinux +ifdef CONFIG_APUS + $(STRIP) $(TOPDIR)/vmlinux -o images/vmapus + gzip $(GZIP_FLAGS) images/vmapus +endif +ifdef CONFIG_GEMINI znetboot : zImage -ifdef CONFIG_ALL_PPC - cp zImage $(TFTPIMAGE) + cp images/sImage $(TFTPSIMAGE) endif -znetboot.initrd : zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - +# Do the dirs clean: - rm -f vmlinux* zvmlinux* mkprep zImage* - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend + $(MAKE) -C images clean + $(MAKE) -C tree clean + $(MAKE) -C utils clean dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - -# just here to match coffboot/Makefile -vmlinux.coff: + $(MAKE) -C mbx fastdep + $(MAKE) -C chrp fastdep + $(MAKE) -C common fastdep + $(MAKE) -C pmac fastdep + $(MAKE) -C prep fastdep + $(MAKE) -C common fastdep -vmlinux.coff.initrd: +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/chrp/Makefile linux/arch/ppc/boot/chrp/Makefile --- v2.4.4/linux/arch/ppc/boot/chrp/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/chrp/Makefile Thu May 24 15:02:06 2001 @@ -0,0 +1,73 @@ +# BK Id: SCCS/s.Makefile 1.8 05/18/01 06:20:29 patch +# +# Makefile for making ELF bootable images for booting on CHRP +# using Open Firmware. +# +# Geert Uytterhoeven September 1997 +# +# Based on coffboot by Paul Mackerras + +ifeq ($(CONFIG_PPC64BRIDGE),y) +MSIZE=.64 +AFLAGS += -Wa,-mppc64bridge +else +MSIZE= +endif + +.c.o: + $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +LD_ARGS = -Ttext 0x00400000 + +OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o +LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a +ADDNOTE = ../utils/addnote +PIGGYBACK = ../utils/piggyback + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE) +else +TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE) +endif + +all: zImage + +znetboot: zImage +ifdef CONFIG_SMP + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.smp +else + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux +endif +ifdef CONFIG_PPC64BRIDGE + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.64 +endif + cp ../images/zImage.chrp $(TFTPIMAGE) + +znetboot.initrd: zImage.initrd + cp ../images/zImage.initrd.chrp $(TFTPIMAGE) + +floppy: zImage + mcopy zImage a:zImage + +image.o: $(PIGGYBACK) ../images/vmlinux.gz + $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ + +sysmap.o: $(PIGGYBACK) $(TOPDIR)/System.map + $(PIGGYBACK) sysmap < $(TOPDIR)/System.map | $(AS) -o $@ + +initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) + $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ + +zImage: $(OBJS) $(LIBS) ../common/no_initrd.o $(ADDNOTE) ../images/vmlinux.gz + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) ../common/no_initrd.o $(LIBS) + cp ../images/$@.chrp ../images/$@.chrp-rs6k + $(ADDNOTE) ../images/$@.chrp-rs6k + +zImage.initrd: $(OBJS) $(LIBS) initrd.o $(ADDNOTE) ../images/vmlinux.gz + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) initrd.o $(LIBS) + cp ../images/$@.chrp ../images/$@.chrp-rs6k + $(ADDNOTE) ../images/$@.chrp-rs6k + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/chrp/main.c linux/arch/ppc/boot/chrp/main.c --- v2.4.4/linux/arch/ppc/boot/chrp/main.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/chrp/main.c Thu May 24 15:02:06 2001 @@ -0,0 +1,198 @@ +/* + * BK Id: SCCS/s.main.c 1.7 05/18/01 06:20:29 patch + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include "nonstdio.h" +#include "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +void gunzip(void *, int, unsigned char *, int *); + +#define RAM_START 0x00000000 +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) + +#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) +#define PROG_START 0x00010000 + +char *avail_ram; +char *end_avail; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; +extern char sysmap_data[]; +extern int sysmap_len; + +static char scratch[1024<<10]; /* 1MB of scratch space for gunzip */ + +chrpboot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + extern char _start; + + printf("chrpboot starting: loaded at 0x%x\n\r", &_start); + + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + + im = image_data; + len = image_len; + /* claim 4MB starting at PROG_START */ + claim(PROG_START, (4<<20) - PROG_START, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + avail_ram = scratch; + end_avail = scratch + sizeof(scratch); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, 0x400000, im, &len); + printf("done %u bytes\n\r", len); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n\r", sa); + + { + struct bi_record *rec; + + rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "chrpboot"); + rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_chrp; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#if 0 + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)sysmap_data; + rec->data[1] = sysmap_len; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n\r"); + + pause(); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n\r"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + nb = (nb + 7) & -8; + if (addr == (avail_ram - nb)) { + avail_ram -= nb; + } +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/chrp/misc.S linux/arch/ppc/boot/chrp/misc.S --- v2.4.4/linux/arch/ppc/boot/chrp/misc.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/chrp/misc.S Thu May 24 15:02:06 2001 @@ -0,0 +1,53 @@ +/* + * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + +/* + * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000. + */ + .globl setup_bats +setup_bats: + mfpvr 3 + rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,3,1 + lis 4,0x9000 + bne 4f + ori 4,4,4 /* set up BAT registers for 601 */ + li 5,0x7f + b 5f +4: ori 4,4,0xff /* set up BAT registers for 604 */ + li 5,2 + mtdbatu 3,4 + mtdbatl 3,5 +5: mtibatu 3,4 + mtibatl 3,5 + isync + blr + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/chrp/start.c linux/arch/ppc/boot/chrp/start.c --- v2.4.4/linux/arch/ppc/boot/chrp/start.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/chrp/start.c Thu May 24 15:02:06 2001 @@ -0,0 +1,308 @@ +/* + * BK Id: SCCS/s.start.c 1.6 05/18/01 15:16:59 cort + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include + +int (*prom)(); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + +void exit(void); +void *finddevice(const char *name); +int getprop(void *phandle, const char *name, void *buf, int buflen); + +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + prom = (int (*)()) promptr; + chosen_handle = finddevice("/chosen"); + if (chosen_handle == (void *) -1) + exit(); + if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) + exit(); + stderr = stdout; + if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) + exit(); + + chrpboot(a1, a2, promptr); + for (;;) + exit(); +} + +int +write(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +int +read(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +void +exit() +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom)(&args); + } +} + +void +pause() +{ + struct prom_args { + char *service; + } args; + + args.service = "enter"; + (*prom)(&args); +} + +void * +finddevice(const char *name) +{ + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + void *phandle; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.phandle = (void *) -1; + (*prom)(&args); + return args.phandle; +} + +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +int +getprop(void *phandle, const char *name, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *phandle; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.phandle = phandle; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*prom)(&args); + return args.size; +} + +int +putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + putc('\r', f); + return write(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return write(f, str, n) == n? 0: -1; +} + +int +readchar() +{ + char ch; + + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\r\n"); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int +getchar() +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +extern int vsprintf(char *buf, const char *fmt, va_list args); +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); + return n; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/Makefile linux/arch/ppc/boot/common/Makefile --- v2.4.4/linux/arch/ppc/boot/common/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/Makefile Thu May 24 15:02:06 2001 @@ -0,0 +1,27 @@ +# +# arch/ppc/boot/common/Makefile +# +# 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. +# +# Tom Rini January 2001 +# + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +OBJCOPY_ARGS = -O elf32-powerpc + +coffcrt0.o: + $(CC) $(AFLAGS) -DXCOFF -traditional -c -o coffcrt0.o crt0.S + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/crt0.S linux/arch/ppc/boot/common/crt0.S --- v2.4.4/linux/arch/ppc/boot/common/crt0.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/crt0.S Thu May 24 15:02:06 2001 @@ -0,0 +1,84 @@ +/* + * BK Id: SCCS/s.crt0.S 1.10 05/21/01 00:49:49 cort + */ +/* Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for IBM PowerPC 400-class processor evaluation + * boards. + * + * Module name: crt0.S + * + * Description: + * Boot loader execution entry point. Clears out .bss section as per + * ANSI C requirements. Invalidates and flushes the caches over the + * range covered by the boot loader's .text section. Sets up a stack + * below the .text section entry point. + * + * 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. + */ + +#include +#include "../../kernel/ppc_asm.tmpl" + + .text + + .globl _start +_start: +#ifdef XCOFF + .long __start,0,0 + + .globl __start +__start: +#endif +#ifdef CONFIG_4xx + ## Clear out the BSS as per ANSI C requirements + + lis r7,_end@ha + addi r7,r7,_end@l # r7 = &_end + lis r8,__bss_start@ha # + addi r8,r8,__bss_start@l # r8 = &_bss_start + + ## Determine how large an area, in number of words, to clear + + subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 + addi r7,r7,3 # r7 += 3 + srwi. r7,r7,2 # r7 = size in words. + beq 2f # If the size is zero, do not bother + addi r8,r8,-4 # r8 -= 4 + mtctr r7 # SPRN_CTR = number of words to clear + li r0,0 # r0 = 0 +1: stwu r0,4(r8) # Clear out a word + bdnz 1b # If we are not done yet, keep clearing +#endif + + ## Flush and invalidate the caches for the range in memory covering + ## the .text section of the boot loader + +2: lis r9,_start@h # r9 = &_start + lis r8,_etext@ha # + addi r8,r8,_etext@l # r8 = &_etext +3: dcbf r0,r9 # Flush the data cache + icbi r0,r9 # Invalidate the instruction cache + addi r9,r9,0x10 # Increment by one cache line + cmplw cr0,r9,r8 # Are we at the end yet? + blt 3b # No, keep flushing and invalidating + sync # sync ; isync after flushing the icache + isync + +#ifdef CONFIG_4xx + ## Set up the stack + + lis r9,_start@h # r9 = &_start (text section entry) + addi r9,r9,_start@l + subi r1,r9,64 # Start the stack 64 bytes below _start + clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. + li r0,0 + stwu r0,-16(r1) + mtlr r9 +#endif + + b start # All done, start the real work. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/misc-common.c linux/arch/ppc/boot/common/misc-common.c --- v2.4.4/linux/arch/ppc/boot/common/misc-common.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/misc-common.c Thu May 24 15:02:06 2001 @@ -0,0 +1,539 @@ +/* + * arch/ppc/boot/common/misc-common.c + * + * Misc. bootloader code (almost) all platforms can use + * + * Author: Johnnie Peters + * Editor: Tom Rini + * + * Derived from arch/ppc/boot/prep/misc.c + * + * Copyright 2000-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 "zlib.h" +#include + +/* If we're on a ALL_PPC, assume we have a keyboard controller + * Also note, if we're not ALL_PPC, we assume you are a serial + * console - Tom */ +#ifdef CONFIG_ALL_PPC +extern void cursor(int x, int y); +extern void scroll(void); +extern char *vidmem; +extern int lines, cols; +extern int orig_x, orig_y; +extern int keyb_present; +extern int CRT_tstc(void); +extern int CRT_getc(void); +#else +int cursor(int x, int y) {return 0;} +void scroll(void) {} +char vidmem[1]; +#define lines 0 +#define cols 0 +int orig_x = 0; +int orig_y = 0; +#define keyb_present 0 +int CRT_tstc(void) {return 0;} +int CRT_getc(void) {return 0;} +#endif + +extern char *avail_ram; +extern char *end_avail; +extern char _end[]; + +void puts(const char *); +void putc(const char c); +void puthex(unsigned long val); +void _bcopy(char *src, char *dst, int len); +void gunzip(void *, int, unsigned char *, int *); +static int _cvt(unsigned long val, char *buf, long radix, char *digits); + +void _vprintk(void(*)(const char), const char *, va_list); + +#if defined(CONFIG_SERIAL_CONSOLE) +struct NS16550 *com_port; + +int serial_tstc(volatile struct NS16550 *); +unsigned char serial_getc(volatile struct NS16550 *); +void serial_putc(volatile struct NS16550 *, unsigned char); +#endif + +void pause(void) +{ + puts("pause\n"); +} + +void exit(void) +{ + puts("exit\n"); + while(1); +} + +int tstc(void) +{ +#if defined(CONFIG_SERIAL_CONSOLE) + if(keyb_present) + return (CRT_tstc() || serial_tstc(com_port)); + else + return (serial_tstc(com_port)); +#else + return CRT_tstc(); +#endif +} + +int getc(void) +{ + while (1) { +#if defined(CONFIG_SERIAL_CONSOLE) + if (serial_tstc(com_port)) + return (serial_getc(com_port)); +#endif /* CONFIG_SERIAL_CONSOLE */ + if (keyb_present) + if(CRT_tstc()) + return (CRT_getc()); + } +} + +void +putc(const char c) +{ + int x,y; + +#if defined(CONFIG_SERIAL_CONSOLE) + serial_putc(com_port, c); + if ( c == '\n' ) + serial_putc(com_port, '\r'); +#endif /* CONFIG_SERIAL_CONSOLE */ + + x = orig_x; + y = orig_y; + + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else if (c == '\r') { + x = 0; + } else if (c == '\b') { + if (x > 0) { + x--; + } + } else { + vidmem [ ( x + cols * y ) * 2 ] = c; + if ( ++x >= cols ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } + } + + cursor(x, y); + + orig_x = x; + orig_y = y; +} + +void puts(const char *s) +{ + int x,y; + char c; + + x = orig_x; + y = orig_y; + + while ( ( c = *s++ ) != '\0' ) { +#if defined(CONFIG_SERIAL_CONSOLE) + serial_putc(com_port, c); + if ( c == '\n' ) serial_putc(com_port, '\r'); +#endif /* CONFIG_SERIAL_CONSOLE */ + + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else if (c == '\b') { + if (x > 0) { + x--; + } + } else { + vidmem [ ( x + cols * y ) * 2 ] = c; + if ( ++x >= cols ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } + } + } + + cursor(x, y); + + orig_x = x; + orig_y = y; +} + +void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + puts("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + puts("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + puts("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + puts("inflateInit2 returned %d\n"); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + puts("inflate returned %d\n"); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} + +void +puthex(unsigned long val) +{ + + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + puts(buf); +} + +#define FALSE 0 +#define TRUE 1 +#include + +void +_printk(char const *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _vprintk(putc, fmt, ap); + va_end(ap); + return; +} + +#define is_digit(c) ((c >= '0') && (c <= '9')) + +void +_vprintk(void(*putc)(const char), const char *fmt0, va_list ap) +{ + char c, sign, *cp = 0; + int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right; + char buf[32]; + long val; + while ((c = *fmt0++)) + { + if (c == '%') + { + c = *fmt0++; + left_prec = right_prec = pad_on_right = 0; + if (c == '-') + { + c = *fmt0++; + pad_on_right++; + } + if (c == '0') + { + zero_fill = TRUE; + c = *fmt0++; + } else + { + zero_fill = FALSE; + } + while (is_digit(c)) + { + left_prec = (left_prec * 10) + (c - '0'); + c = *fmt0++; + } + if (c == '.') + { + c = *fmt0++; + zero_fill++; + while (is_digit(c)) + { + right_prec = (right_prec * 10) + (c - '0'); + c = *fmt0++; + } + } else + { + right_prec = left_prec; + } + sign = '\0'; + switch (c) + { + case 'd': + case 'x': + case 'X': + val = va_arg(ap, long); + switch (c) + { + case 'd': + if (val < 0) + { + sign = '-'; + val = -val; + } + length = _cvt(val, buf, 10, "0123456789"); + break; + case 'x': + length = _cvt(val, buf, 16, "0123456789abcdef"); + break; + case 'X': + length = _cvt(val, buf, 16, "0123456789ABCDEF"); + break; + } + cp = buf; + break; + case 's': + cp = va_arg(ap, char *); + length = strlen(cp); + break; + case 'c': + c = va_arg(ap, long /*char*/); + (*putc)(c); + continue; + default: + (*putc)('?'); + } + pad = left_prec - length; + if (sign != '\0') + { + pad--; + } + if (zero_fill) + { + c = '0'; + if (sign != '\0') + { + (*putc)(sign); + sign = '\0'; + } + } else + { + c = ' '; + } + if (!pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + if (sign != '\0') + { + (*putc)(sign); + } + while (length-- > 0) + { + (*putc)(c = *cp++); + if (c == '\n') + { + (*putc)('\r'); + } + } + if (pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + } else + { + (*putc)(c); + if (c == '\n') + { + (*putc)('\r'); + } + } + } +} + +int +_cvt(unsigned long val, char *buf, long radix, char *digits) +{ + char temp[80]; + char *cp = temp; + int length = 0; + if (val == 0) + { /* Special case */ + *cp++ = '0'; + } else + while (val) + { + *cp++ = digits[val % radix]; + val /= radix; + } + while (cp != temp) + { + *buf++ = *--cp; + length++; + } + *buf = '\0'; + return (length); +} + +void +_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) +{ + int i, c; + if ((unsigned int)s > (unsigned int)p) + { + s = (unsigned int)s - (unsigned int)p; + } + while (s > 0) + { + if (base) + { + _printk("%06X: ", (int)p - (int)base); + } else + { + _printk("%06X: ", p); + } + for (i = 0; i < 16; i++) + { + if (i < s) + { + _printk("%02X", p[i] & 0xFF); + } else + { + _printk(" "); + } + if ((i % 2) == 1) _printk(" "); + if ((i % 8) == 7) _printk(" "); + } + _printk(" |"); + for (i = 0; i < 16; i++) + { + if (i < s) + { + c = p[i] & 0xFF; + if ((c < 0x20) || (c >= 0x7F)) c = '.'; + } else + { + c = ' '; + } + _printk("%c", c); + } + _printk("|\n"); + s -= 16; + p += 16; + } +} + +void +_dump_buf(unsigned char *p, int s) +{ + _printk("\n"); + _dump_buf_with_offset(p, s, 0); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/misc-simple.c linux/arch/ppc/boot/common/misc-simple.c --- v2.4.4/linux/arch/ppc/boot/common/misc-simple.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/misc-simple.c Thu May 24 15:02:06 2001 @@ -0,0 +1,182 @@ +/* + * arch/ppc/common/misc-simple.c + * + * Misc. bootloader code for many machines. This assumes you have are using + * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory + * below 8MB is free. Finally, it assumes you have a NS16550-style uart for + * your serial console. If a machine meets these requirements, it can quite + * likely use this code during boot. + * + * Author: Matt Porter + * Derived from arch/ppc/boot/prep/misc.c + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include "zlib.h" + +unsigned long com_port; + +char *avail_ram; +char *end_avail; +extern char _end[]; + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +extern void puts(const char *); +extern void putc(const char c); +extern void puthex(unsigned long val); +extern void *memcpy(void * __dest, __const void * __src, + __kernel_size_t __n); +extern void gunzip(void *, int, unsigned char *, int *); +extern void udelay(long delay); +extern int tstc(void); +extern int getc(void); +extern volatile unsigned long serial_init(int chan); + +void +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) +{ + + int timer = 0; + extern unsigned long start; + char *cp, ch; + + com_port = serial_init(0); + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* + * Reveal where we were loaded at and where we + * were relocated to. + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including + the size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; + + /* + * Find a place to stick the zimage and initrd and + * relocate them if we have to. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + if ( (unsigned long)zimage_start <= 0x00800000 ) + { + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + avail_ram = (char *)PAGE_ALIGN( + (unsigned long)zimage_size+(unsigned long)zimage_start); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); + initrd_start = (unsigned long)avail_ram; + initrd_end = initrd_start + INITRD_SIZE; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + } else if ( initrd_start ) { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + /* Display standard Linux/PPC boot prompt for kernel args */ + puts("\nLinux/PPC load: "); + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + /* Test for backspace/delete */ + if (ch == '\b' || ch == '\177') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + /* Test for ^x/^u (and wipe the line) */ + } else if (ch == '\030' || ch == '\025') { + while (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); + + /* mappings on early boot can only handle 16M */ + if ( (int)(cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + + puts("Now booting the kernel\n"); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/no_initrd.c linux/arch/ppc/boot/common/no_initrd.c --- v2.4.4/linux/arch/ppc/boot/common/no_initrd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/no_initrd.c Thu May 24 15:02:06 2001 @@ -0,0 +1,5 @@ +/* + * BK Id: SCCS/s.no_initrd.c 1.7 05/18/01 15:17:23 cort + */ +char initrd_data[1]; +int initrd_len = 0; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/ns16550.c linux/arch/ppc/boot/common/ns16550.c --- v2.4.4/linux/arch/ppc/boot/common/ns16550.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/ns16550.c Thu May 24 15:02:06 2001 @@ -0,0 +1,80 @@ +/* + * BK Id: SCCS/s.ns16550.c 1.7 05/18/01 06:20:29 patch + */ +/* + * COM1 NS16550 support + */ + +#include +#include +#include +#include + +/* Some machines, such as ones with a PReP memory map, initally have + * their serial port at an offset of 0x80000000 from where they are + * in . This tries to take that into account. */ +#ifndef IOOFFSET +#define IOOFFSET 0 +#endif + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in */ +}; + +static int shift; + +volatile unsigned long serial_init(int chan) { + unsigned long com_port; + + /* Get the base, and add any offset we need to deal with. */ + com_port = rs_table[chan].port + IOOFFSET; + + /* How far apart the registers are. */ + shift = rs_table[chan].iomem_reg_shift; + + /* See if port is present */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x00; + *((unsigned char *)com_port + (UART_IER << shift)) = 0x00; + /* Access baud rate */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x00; +#ifdef CONFIG_SERIAL_CONSOLE_NONSTD + /* Input clock. */ + *((unsigned char *)com_port + (UART_DLL << shift)) = + (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD); + *((unsigned char *)com_port + (UART_DLM << shift)) = + (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8; +#endif + /* 8 data, 1 stop, no parity */ + *((unsigned char *)com_port + (UART_LCR << shift)) = 0x03; + /* RTS/DTR */ + *((unsigned char *)com_port + (UART_MCR << shift)) = 0x03; + /* Clear & enable FIFOs */ + *((unsigned char *)com_port + (UART_FCR << shift)) = 0x07; + + return (com_port); +} + +void +serial_putc(volatile unsigned long com_port, unsigned char c) +{ + while ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) & + UART_LSR_THRE) == 0) + ; + *(volatile unsigned char *)com_port = c; +} + +unsigned char +serial_getc(volatile unsigned long com_port) +{ + while ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) + & UART_LSR_DR) == 0) + ; + return (*(volatile unsigned char *)com_port); +} + +int +serial_tstc(volatile unsigned long com_port) +{ + return ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) + & UART_LSR_DR) != 0); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/common/string.S linux/arch/ppc/boot/common/string.S --- v2.4.4/linux/arch/ppc/boot/common/string.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/common/string.S Thu May 24 15:02:06 2001 @@ -0,0 +1,153 @@ +/* + * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch + */ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * 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. + */ +#define r0 0 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 + + .globl strlen +strlen: + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + + .globl memset +memset: + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + rlwinm r0,r5,32-2,2,31 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + + .globl memmove +memmove: + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + + .globl memcpy +memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl backwards_memcpy +backwards_memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl memcmp +memcmp: + cmpwi 0,r5,0 + blelr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S --- v2.4.4/linux/arch/ppc/boot/head.S Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/boot/head.S Wed Dec 31 16:00:00 1969 @@ -1,238 +0,0 @@ -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ - * - * Boot loader philosophy: - * ROM loads us to some arbitrary location - * Move the boot code to the link address (8M) - * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 8M - * Decompress the kernel to 0 - * Jump to the kernel entry - * -- Cort - */ - .globl start -start: - bl start_ -start_: - mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* round up */ - sub r5,r5,r4 - srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* - * no matter where we're loaded, move ourselves to -Ttext address - */ -relocate: - mflr r3 /* Compute code bias */ - subi r3,r3,4 - mr r8,r3 - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr -start_ldr: -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 -/* Run loader */ - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ - li r9,0x4 - mtlr r9 - lis r10,0xdeadc0de@h - ori r10,r10,0xdeadc0de@l - li r9,0 - stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 -00: li r0,86 /* Instructions / microsecond? */ - mtctr r0 -10: addi r0,r0,0 /* NOP */ - bdnz 10b - subic. r3,r3,1 - bne 00b - blr - -.udelay_not_601: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr - .comm .stack,4096*2,4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/images/Makefile linux/arch/ppc/boot/images/Makefile --- v2.4.4/linux/arch/ppc/boot/images/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/images/Makefile Thu May 24 15:02:06 2001 @@ -0,0 +1,12 @@ +# +# This dir holds all of the images for PPC machines. +# Tom Rini January 2001 + +include $(TOPDIR)/Rules.make + +vmlinux.gz: $(TOPDIR)/vmlinux + $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + gzip -vf9 vmlinux + +clean: + rm -f sImage vmapus vmlinux.* miboot.image* zImage* zvmlinux.* diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/include/nonstdio.h linux/arch/ppc/boot/include/nonstdio.h --- v2.4.4/linux/arch/ppc/boot/include/nonstdio.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/include/nonstdio.h Thu May 24 15:02:06 2001 @@ -0,0 +1,21 @@ +/* + * BK Id: SCCS/s.nonstdio.h 1.7 05/18/01 15:17:23 cort + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +typedef int FILE; +extern FILE *stdin, *stdout; +#define NULL ((void *)0) +#define EOF (-1) +#define fopen(n, m) NULL +#define fflush(f) 0 +#define fclose(f) 0 +extern char *fgets(); + +#define perror(s) printf("%s: no files!\n", (s)) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/include/rs6000.h linux/arch/ppc/boot/include/rs6000.h --- v2.4.4/linux/arch/ppc/boot/include/rs6000.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/include/rs6000.h Thu May 24 15:02:06 2001 @@ -0,0 +1,246 @@ +/* + * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort + */ +/* IBM RS/6000 "XCOFF" file definitions for BFD. + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM + and John Gilmore of Cygnus Support. */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + /* IBM RS/6000 */ +#define U802WRMAGIC 0730 /* writeable text segments **chh** */ +#define U802ROMAGIC 0735 /* readonly sharable text segments */ +#define U802TOCMAGIC 0737 /* readonly text segments and TOC */ + +#define BADMAG(x) \ + ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \ + (x).f_magic != U802TOCMAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ 20 + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + unsigned char magic[2]; /* type of file */ + unsigned char vstamp[2]; /* version stamp */ + unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */ + unsigned char dsize[4]; /* initialized data " " */ + unsigned char bsize[4]; /* uninitialized data " " */ + unsigned char entry[4]; /* entry pt. */ + unsigned char text_start[4]; /* base of text used for this file */ + unsigned char data_start[4]; /* base of data used for this file */ + unsigned char o_toc[4]; /* address of TOC */ + unsigned char o_snentry[2]; /* section number of entry point */ + unsigned char o_sntext[2]; /* section number of .text section */ + unsigned char o_sndata[2]; /* section number of .data section */ + unsigned char o_sntoc[2]; /* section number of TOC */ + unsigned char o_snloader[2]; /* section number of .loader section */ + unsigned char o_snbss[2]; /* section number of .bss section */ + unsigned char o_algntext[2]; /* .text alignment */ + unsigned char o_algndata[2]; /* .data alignment */ + unsigned char o_modtype[2]; /* module type (??) */ + unsigned char o_cputype[2]; /* cpu type */ + unsigned char o_maxstack[4]; /* max stack size (??) */ + unsigned char o_maxdata[4]; /* max data size (??) */ + unsigned char o_resv2[12]; /* reserved */ +} +AOUTHDR; + +#define AOUTSZ 72 +#define SMALL_AOUTSZ (28) +#define AOUTHDRSZ 72 + +#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */ +#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */ +#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */ + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _PAD ".pad" +#define _LOADER ".loader" + +#define SCNHDR struct external_scnhdr +#define SCNHSZ 40 + +/* XCOFF uses a special .loader section with type STYP_LOADER. */ +#define STYP_LOADER 0x1000 + +/* XCOFF uses a special .debug section with type STYP_DEBUG. */ +#define STYP_DEBUG 0x2000 + +/* XCOFF handles line number or relocation overflow by creating + another section header with STYP_OVRFLO set. */ +#define STYP_OVRFLO 0x8000 + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 6 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + struct { + unsigned char x_scnlen[4]; + unsigned char x_parmhash[4]; + unsigned char x_snhash[2]; + unsigned char x_smtyp[1]; + unsigned char x_smclas[1]; + unsigned char x_stab[4]; + unsigned char x_snstab[2]; + } x_csect; + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 +#define DBXMASK 0x80 /* for dbx storage mask */ +#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK) + + + +/********************** RELOCATION DIRECTIVES **********************/ + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_size[1]; + char r_type[1]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 10 + +#define DEFAULT_DATA_SECTION_ALIGNMENT 4 +#define DEFAULT_BSS_SECTION_ALIGNMENT 4 +#define DEFAULT_TEXT_SECTION_ALIGNMENT 4 +/* For new sections we havn't heard of before */ +#define DEFAULT_SECTION_ALIGNMENT 4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/include/zlib.h linux/arch/ppc/boot/include/zlib.h --- v2.4.4/linux/arch/ppc/boot/include/zlib.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/include/zlib.h Thu May 24 15:02:06 2001 @@ -0,0 +1,433 @@ +/* + * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort + */ +/* + * This file is derived from zlib.h and zconf.h from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. + */ + +/* + * ==FILEVERSION 960122== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 0.95, Aug 16th, 1995. + + Copyright (C) 1995 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + */ + +#ifndef _ZLIB_H +#define _ZLIB_H + +/* #include "zconf.h" */ /* included directly here */ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ + +/* + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. + */ + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints + * at addresses which are not a multiple of their size. + * Under DOS, -DFAR=far or -DFAR=__far may be needed. + */ + +#ifndef STDC +# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) +# define STDC +# endif +#endif + +#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ +# include +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +#ifndef FAR +# define FAR +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef Byte FAR Bytef; +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +/* end of original zconf.h */ + +#define ZLIB_VERSION "0.95P" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidp opaque; /* private data object passed to zalloc and zfree */ + + Byte data_type; /* best guess about the data type: ascii or binary */ + +} z_stream; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_FULL_FLUSH 2 +#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ +#define Z_FINISH 4 +#define Z_PACKET_FLUSH 5 +/* See deflate() below for the usage of these constants */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +/* error codes for the compression/decompression functions */ + +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Used to set the data_type field */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +extern char *zlib_version; +/* The application can compare zlib_version and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + */ + + /* basic functions */ + +extern int inflateInit OF((z_stream *strm)); +/* + Initializes the internal stream state for decompression. The fields + zalloc and zfree must be initialized before by the caller. If zalloc and + zfree are set to Z_NULL, inflateInit updates them to use default allocation + functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory. msg is set to null if there is no error message. + inflateInit does not perform any decompression: this will be done by + inflate(). +*/ + + +extern int inflate OF((z_stream *strm, int flush)); +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() always provides as much output as possible + (until there is no more input data or no more space in the output buffer). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). + + If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, + inflate flushes as much output as possible to the output buffer. The + flushing behavior of inflate is not specified for values of the flush + parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the + current implementation actually flushes as much output as possible + anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data + has been consumed, it is expecting to see the length field of a stored + block; if not, it returns Z_DATA_ERROR. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if + the stream structure was inconsistent (for example if next_in or next_out + was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no + progress is possible or if there was not enough room in the output buffer + when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then + call inflateSync to look for a good compression block. */ + + +extern int inflateEnd OF((z_stream *strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* advanced functions */ + +extern int inflateInit2 OF((z_stream *strm, + int windowBits)); +/* + This is another version of inflateInit with more compression options. The + fields next_out, zalloc and zfree must be initialized before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1< - -#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ - - -unsigned char shfts, ctls, alts, caps; - -#define KBDATAP 0x60 /* kbd data port */ -#define KBSTATUSPORT 0x61 /* kbd status */ -#define KBSTATP 0x64 /* kbd status port */ -#define KBINRDY 0x01 -#define KBOUTRDY 0x02 - - -static int kbd(int noblock) -{ - unsigned char dt, brk, val; - unsigned code; -loop: - if (noblock) { - if ((inb(KBSTATP) & KBINRDY) == 0) - return (-1); - } else while((inb(KBSTATP) & KBINRDY) == 0) ; - - dt = inb(KBDATAP); - - brk = dt & 0x80; /* brk == 1 on key release */ - dt = dt & 0x7f; /* keycode */ - - if (shfts) - code = shift_map[dt]; - else if (ctls) - code = ctrl_map[dt]; - else - code = plain_map[dt]; - - val = KVAL(code); - switch (KTYP(code) & 0x0f) { - case KT_LATIN: - if (brk) - break; - if (alts) - val |= 0x80; - if (val == 0x7f) /* map delete to backspace */ - val = '\b'; - return val; - - case KT_LETTER: - if (brk) - break; - if (caps) - val -= 'a'-'A'; - return val; - - case KT_SPEC: - if (brk) - break; - if (val == KVAL(K_CAPS)) - caps = !caps; - else if (val == KVAL(K_ENTER)) { -enter: /* Wait for key up */ - while (1) { - while((inb(KBSTATP) & KBINRDY) == 0) ; - dt = inb(KBDATAP); - if (dt & 0x80) /* key up */ break; - } - return 10; - } - break; - - case KT_PAD: - if (brk) - break; - if (val < 10) - return val; - if (val == KVAL(K_PENTER)) - goto enter; - break; - - case KT_SHIFT: - switch (val) { - case KG_SHIFT: - case KG_SHIFTL: - case KG_SHIFTR: - shfts = brk ? 0 : 1; - break; - case KG_ALT: - case KG_ALTGR: - alts = brk ? 0 : 1; - break; - case KG_CTRL: - case KG_CTRLL: - case KG_CTRLR: - ctls = brk ? 0 : 1; - break; - } - break; - - case KT_LOCK: - switch (val) { - case KG_SHIFT: - case KG_SHIFTL: - case KG_SHIFTR: - if (brk) - shfts = !shfts; - break; - case KG_ALT: - case KG_ALTGR: - if (brk) - alts = !alts; - break; - case KG_CTRL: - case KG_CTRLL: - case KG_CTRLR: - if (brk) - ctls = !ctls; - break; - } - break; - } - if (brk) return (-1); /* Ignore initial 'key up' codes */ - goto loop; -} - -static void kbdreset(void) -{ - unsigned char c; - int i; - - /* flush input queue */ - while ((inb(KBSTATP) & KBINRDY)) - { - (void)inb(KBDATAP); - } - /* Send self-test */ - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0xAA); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ - if ((c = inb(KBDATAP)) != 0x55) - { - puts("Keyboard self test failed - result:"); - puthex(c); - puts("\n"); - } - /* Enable interrupts and keyboard controller */ - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0x60); - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBDATAP,0x45); - for (i = 0; i < 10000; i++) udelay(1); - - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0x20); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ - if (! (inb(KBDATAP) & 0x40)) { - /* - * 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." (KBINRDY and KBOUTRDY) - */ - - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; - outb(KBDATAP,0xF0); - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; - outb(KBDATAP,0x01); - } - - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0xAE); -} - -/* We have to actually read the keyboard when CRT_tstc is called, - * since the pending data might be a key release code, and therefore - * not valid data. In this case, kbd() will return -1, even though there's - * data to be read. Of course, we might actually read a valid key press, - * in which case it gets queued into key_pending for use by CRT_getc. - */ - -static int kbd_reset = 0; - -static int key_pending = -1; - -int CRT_getc(void) -{ - int c; - if (!kbd_reset) {kbdreset(); kbd_reset++; } - - if (key_pending != -1) { - c = key_pending; - key_pending = -1; - return c; - } else { - while ((c = kbd(0)) == 0) ; - return c; - } -} - -int CRT_tstc(void) -{ - if (!kbd_reset) {kbdreset(); kbd_reset++; } - - while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { - key_pending = kbd(1); - } - - return (key_pending != -1); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/lib/Makefile linux/arch/ppc/boot/lib/Makefile --- v2.4.4/linux/arch/ppc/boot/lib/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/lib/Makefile Thu May 24 15:02:06 2001 @@ -0,0 +1,9 @@ +# +# Makefile for some libs needed by zImage. +# + +L_TARGET := zlib.a + +obj-y := zlib.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/lib/zlib.c linux/arch/ppc/boot/lib/zlib.c --- v2.4.4/linux/arch/ppc/boot/lib/zlib.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/lib/zlib.c Thu May 24 15:02:06 2001 @@ -0,0 +1,2150 @@ +/* + * BK Id: SCCS/s.zlib.c 1.8 05/18/01 15:17:24 cort + */ +/* + * This file is derived from various .h and .c files from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - changed functions not used outside this file to "local" + * - added minCompression parameter to deflateInit2 + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp + * + */ + +/*+++++*/ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ + +#define _Z_UTIL_H + +#include "zlib.h" + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define FAR + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern char *z_errmsg[]; /* indexed by 1-zlib_error */ + +#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) +/* To be used only when the state is known to be valid */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + + /* common constants */ + +#define DEFLATED 8 + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + + /* functions */ + +#include +#define zmemcpy memcpy +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); + +/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ +/* void zcfree OF((voidpf opaque, voidpf ptr)); */ + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr, size) \ + (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) +#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} + +/* deflate.h -- internal compression state + * Copyright (C) 1995 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/*+++++*/ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +local inflate_blocks_statef * inflate_blocks_new OF(( + z_stream *z, + check_func c, /* check function */ + uInt w)); /* window size */ + +local int inflate_blocks OF(( + inflate_blocks_statef *, + z_stream *, + int)); /* initial return code */ + +local void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_addhistory OF(( + inflate_blocks_statef *, + z_stream *)); + +local int inflate_packet_flush OF(( + inflate_blocks_statef *)); + +/*+++++*/ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt Nalloc; /* number of these allocated here */ + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + local uInt inflate_hufts; +#endif + +local int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +local int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_stream *)); /* for zfree function */ + + +/*+++++*/ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +local inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_stream *)); + +local int inflate_codes OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +local void inflate_codes_free OF(( + inflate_codes_statef *, + z_stream *)); + + +/*+++++*/ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state, sizeof(struct internal_state)); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2(z, w) +z_stream *z; +int w; +{ + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; +/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ +/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit(z) +z_stream *z; +{ + return inflateInit2(z, DEF_WBITS); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z, f) +z_stream *z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) + { + z->state->mode = BAD; + z->msg = "unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = "invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + if ((b = NEXTBYTE) & 0x20) + { + z->state->mode = BAD; + z->msg = "invalid reserved bit"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = "incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + z->state->mode = BLOCKS; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = "incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z) +z_stream *z; +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z) +z_stream *z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE + +/*+++++*/ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ + mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + int nblens; /* # elements allocated at blens */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl, *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* + * The IBM 150 firmware munges the data right after _etext[]. This + * protects it. -- Cort + */ +local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; +/* And'ing with mask[n] masks the lower n bits */ +local uInt inflate_mask[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +/*+++++*/ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_stream *)); + + +/*+++++*/ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* Table for deflate from PKZIP's appnote.txt. */ +local uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +local void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +local inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_stream *z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +local int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = "invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if (((~b) >> 16) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : TYPE; + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.trees.nblens = t; + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + s->mode = BADB; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + s->mode = BADB; + z->msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BADB; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window, s->end - s->window); + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +local int inflate_addhistory(s, z) +inflate_blocks_statef *s; +z_stream *z; +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WRAP */ /* expand WRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +local int inflate_packet_flush(s) + inflate_blocks_statef *s; +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} + + +/*+++++*/ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + uIntf *, /* list of base values for non-simple codes */ + uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_stream *)); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +local void ffree OF(( + voidpf q, /* opaque pointer (not used) */ + voidpf p, /* what to free (not used) */ + uInt n)); /* number of bytes (not used) */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* actually lengths - 2; also see note #13 above about 258 */ +local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ +local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local uInt cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +uIntf *d; /* list of base values for non-simple codes */ +uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_stream *zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (all zero length codes or an + over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } + q->word.Nalloc = z + 1; +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +local int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tb, z); + z->msg = "incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_lock = 0; +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local uInt fixed_left = FIXEDH; +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer (not used) */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= fixed_left, + "inflate_trees falloc overflow"); + if (q) s++; /* to make some compilers happy */ + fixed_left -= n; + return (voidpf)(fixed_mem + fixed_left); +} + + +local void ffree(q, p, n) +voidpf q; +voidpf p; +uInt n; +{ + Assert(0, "inflate_trees ffree called!"); + if (q) q = p; /* to make some compilers happy */ +} + + +local int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not built already--lock out other instances */ + while (++fixed_lock > 1) + fixed_lock--; + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = ffree; + z.opaque = Z_NULL; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + fixed_built = 1; + } + fixed_lock--; + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +local int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_stream *z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); + p = q; + } + return Z_OK; +} + +/*+++++*/ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl, *td; +z_stream *z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +local int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_stream *z; +{ + ZFREE(z, c, sizeof(struct inflate_codes_state)); + Tracev((stderr, "inflate: codes free\n")); +} + +/*+++++*/ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt n; + Bytef *p, *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + + +/*+++++*/ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +local int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl, *td; +inflate_blocks_statef *s; +z_stream *z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = "invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = "invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + + +/*+++++*/ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ + +char *zlib_version = ZLIB_VERSION; + +char *z_errmsg[] = { +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +""}; + + +/*+++++*/ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf) {s1 += *buf++; s2 += s1;} +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); +#define DO16(buf) DO8(buf); DO8(buf); + +/* ========================================================================= */ +uLong adler32(adler, buf, len) + uLong adler; + Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + k -= 16; + } + if (k != 0) do { + DO1(buf); + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/Makefile linux/arch/ppc/boot/mbx/Makefile --- v2.4.4/linux/arch/ppc/boot/mbx/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/Makefile Thu May 24 15:02:06 2001 @@ -0,0 +1,127 @@ +# BK Id: SCCS/s.Makefile 1.5 05/18/01 06:20:29 patch +# +# +# arch/ppc/mbxboot/Makefile +# +# 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) 1994 by Linus Torvalds +# Adapted for PowerPC by Gary Thomas +# modified by Cort (cort@cs.nmt.edu) +# +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +TFTPIMAGE := /tftpboot/zImage.embedded + +OFFSET := ../utils/offset +SIZE := ../utils/size + +LIBS := ../lib/zlib.a +OBJCOPY_ARGS := -O elf32-powerpc + +ifdef CONFIG_8xx +ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00180000 +OBJECTS := head.o m8xx_tty.o +CFLAGS += -DCONFIG_8xx +endif + +ifdef CONFIG_8260 +ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00400000 +OBJECTS := head_8260.o m8260_tty.o embed_config.o +CFLAGS += -DCONFIG_8260 +endif + +OBJECTS += ../common/misc-common.o misc.o ../common/string.o +OBJCOPY_ARGS = -O elf32-powerpc + +ifeq ($(CONFIG_MBX),y) +OBJECTS += iic.o embed_config.o pci.o qspan_pci.o +CFLAGS += -DCONFIG_MBX +endif +ifeq ($(CONFIG_RPXLITE),y) +CFLAGS += -DCONFIG_RPXLITE +OBJECTS += iic.o embed_config.o +endif +ifeq ($(CONFIG_RPXCLASSIC),y) +CFLAGS += -DCONFIG_RPXCLASSIC +OBJECTS += iic.o embed_config.o pci.o qspan_pci.o +endif +ifeq ($(CONFIG_BSEIP),y) +CFLAGS += -DCONFIG_BSEIP +OBJECTS += iic.o embed_config.o +endif +ifeq ($(CONFIG_FADS),y) +CFLAGS += -DCONFIG_FADS +OBJECTS += embed_config.o +endif + +all: zImage + +misc.o: misc.c + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp ../images/$@.mbx + +zImage: zvmlinux + ln -sf zvmlinux.mbx ../images/zImage.mbx + +zImage.initrd: zvmlinux.initrd + ln -sf zvmlinux.initrd.mbx ../images/zImage.initrd.mbx + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp ../images/$@.mbx +# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.mbx + rm -f $@.tmp $@ + +znetboot : zImage + cp ../images/zImage.mbx $(TFTPIMAGE) + +znetboot.initrd : zImage.initrd + cp ../images/zImage.initrd.mbx $(TFTPIMAGE) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/embed_config.c linux/arch/ppc/boot/mbx/embed_config.c --- v2.4.4/linux/arch/ppc/boot/mbx/embed_config.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/embed_config.c Thu May 24 15:02:06 2001 @@ -0,0 +1,593 @@ +/* + * BK Id: SCCS/s.embed_config.c 1.7 05/18/01 07:54:04 patch + */ + +/* Board specific functions for those embedded 8xx boards that do + * not have boot monitor support for board information. + */ +#include +#include +#ifdef CONFIG_8xx +#include +#endif +#ifdef CONFIG_8260 +#include +#include +#endif + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); +static u_char aschex_to_byte(u_char *cp); + +/* Supply a default Ethernet address for those eval boards that don't + * ship with one. This is an address from the MBX board I have, so + * it is unlikely you will find it on your network. + */ +static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; + +#if defined(CONFIG_MBX) + +/* The MBX hands us a pretty much ready to go board descriptor. This + * is where the idea started in the first place. + */ +void +embed_config(bd_t *bd) +{ + u_char *mp; + u_char eebuf[128]; + int i; + + /* Read the first 128 bytes of the EEPROM. There is more, + * but this is all we need. + */ + iic_read(0xa4, eebuf, 0, 128); + + /* All we are looking for is the Ethernet MAC address. The + * first 8 bytes are 'MOTOROLA', so check for part of that. + * If it's there, assume we have a valid MAC address. If not, + * grab our default one. + */ + if ((*(uint *)eebuf) == 0x4d4f544f) + mp = &eebuf[0x4c]; + else + mp = (u_char *)def_enet_addr; + + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *mp++; + } + + /* The boot rom passes these to us in MHz. Linux now expects + * them to be in Hz. + */ + bd->bi_intfreq *= 1000000; + bd->bi_busfreq *= 1000000; + + /* Stuff a baud rate here as well. + */ + bd->bi_baudrate = 9600; +} +#endif /* CONFIG_MBX */ + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPX6) + +/* Helper functions for Embedded Planet boards. +*/ +static void +rpx_eth(bd_t *bd, u_char *cp) +{ + int i; + + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = aschex_to_byte(cp); + cp += 2; + } +} + +static uint +rpx_baseten(u_char *cp) +{ + uint retval; + + retval = 0; + + while (*cp != '\n') { + retval *= 10; + retval += (*cp) - '0'; + cp++; + } + return(retval); +} + +static void +rpx_brate(bd_t *bd, u_char *cp) +{ + uint rate; + + rate = 0; + + while (*cp != '\n') { + rate *= 10; + rate += (*cp) - '0'; + cp++; + } + + bd->bi_baudrate = rate * 100; +} + +static void +rpx_memsize(bd_t *bd, u_char *cp) +{ + uint size; + + size = 0; + + while (*cp != '\n') { + size *= 10; + size += (*cp) - '0'; + cp++; + } + + bd->bi_memsize = size * 1024 * 1024; +} + +static void +rpx_cpuspeed(bd_t *bd, u_char *cp) +{ + uint num, den; + + num = den = 0; + + while (*cp != '\n') { + num *= 10; + num += (*cp) - '0'; + cp++; + if (*cp == '/') { + cp++; + den = (*cp) - '0'; + break; + } + } + + /* I don't know why the RPX just can't state the actual + * CPU speed..... + */ + if (den) { + num /= den; + num *= den; + } + bd->bi_intfreq = bd->bi_busfreq = num * 1000000; + + /* The 8xx can only run a maximum 50 MHz bus speed (until + * Motorola changes this :-). Greater than 50 MHz parts + * run internal/2 for bus speed. + */ + if (num > 50) + bd->bi_busfreq /= 2; +} + +/* Because I didn't find anything that would do this....... +*/ +u_char +aschex_to_byte(u_char *cp) +{ + u_char byte, c; + + c = *cp++; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte = c * 16; + + c = *cp; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte += c; + + return(byte); +} +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + +/* Read the EEPROM on the RPX-Lite board. +*/ +void +embed_config(bd_t *bd) +{ + u_char eebuf[256], *cp; + + /* Read the first 256 bytes of the EEPROM. I think this + * is really all there is, and I hope if it gets bigger the + * info we want is still up front. + */ +#if 1 + iic_read(0xa8, eebuf, 0, 128); + iic_read(0xa8, &eebuf[128], 128, 128); + + /* We look for two things, the Ethernet address and the + * serial baud rate. The records are separated by + * newlines. + */ + cp = eebuf; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + rpx_brate(bd, cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + rpx_memsize(bd, cp); + } + } + if (*cp == 'H') { + cp++; + if (*cp == 'Z') { + cp += 2; + rpx_cpuspeed(bd, cp); + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; +#else + /* For boards without initialized EEPROM. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (8 * 1024 * 1024); + bd->bi_intfreq = 48000000; + bd->bi_busfreq = 48000000; + bd->bi_baudrate = 9600; +#endif +} +#endif /* RPXLITE || RPXCLASSIC */ + +#ifdef CONFIG_BSEIP +/* Build a board information structure for the BSE ip-Engine. + * There is more to come since we will add some environment + * variables and a function to read them. + */ +void +embed_config(bd_t *bd) +{ + u_char *cp; + int i; + + /* Baud rate and processor speed will eventually come + * from the environment variables. + */ + bd->bi_baudrate = 9600; + + /* Get the Ethernet station address from the Flash ROM. + */ + cp = (u_char *)0xfe003ffa; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + /* The rest of this should come from the environment as well. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (16 * 1024 * 1024); + bd->bi_intfreq = 48000000; + bd->bi_busfreq = 48000000; +} +#endif /* BSEIP */ + +#ifdef CONFIG_FADS +/* Build a board information structure for the FADS. + */ +void +embed_config(bd_t *bd) +{ + u_char *cp; + int i; + + /* Just fill in some known values. + */ + bd->bi_baudrate = 9600; + + /* Use default enet. + */ + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + bd->bi_memstart = 0; + bd->bi_memsize = (8 * 1024 * 1024); + bd->bi_intfreq = 40000000; + bd->bi_busfreq = 40000000; +} +#endif /* FADS */ + +#ifdef CONFIG_8260 +/* Compute 8260 clock values if the rom doesn't provide them. + * We can't compute the internal core frequency (I don't know how to + * do that). + */ +static void +clk_8260(bd_t *bd) +{ + uint scmr, vco_out, clkin; + uint plldf, pllmf, busdf, brgdf, cpmdf; + volatile immap_t *ip; + + ip = (immap_t *)IMAP_ADDR; + scmr = ip->im_clkrst.car_scmr; + + /* The clkin is always bus frequency. + */ + clkin = bd->bi_busfreq; + + /* Collect the bits from the scmr. + */ + plldf = (scmr >> 12) & 1; + pllmf = scmr & 0xfff; + cpmdf = (scmr >> 16) & 0x0f; + busdf = (scmr >> 20) & 0x0f; + + /* This is arithmetic from the 8260 manual. + */ + vco_out = clkin / (plldf + 1); + vco_out *= 2 * (pllmf + 1); + bd->bi_vco = vco_out; /* Save for later */ + + bd->bi_cpmfreq = vco_out / 2; /* CPM Freq, in MHz */ + + /* Set Baud rate divisor. The power up default is divide by 16, + * but we set it again here in case it was changed. + */ + ip->im_clkrst.car_sccr = 1; /* DIV 16 BRG */ + bd->bi_brgfreq = vco_out / 16; +} +#endif + +#ifdef CONFIG_EST8260 +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + bd = *bdp; +#if 0 + /* This is actually provided by my boot rom. I have it + * here for those people that may load the kernel with + * a JTAG/COP tool and not the rom monitor. + */ + bd->bi_baudrate = 115200; + bd->bi_intfreq = 200000000; + bd->bi_busfreq = 66666666; + bd->bi_cpmfreq = 66666666; + bd->bi_brgfreq = 33333333; + bd->bi_memsize = 16 * 1024 * 1024; +#else + /* The boot rom passes these to us in MHz. Linux now expects + * them to be in Hz. + */ + bd->bi_intfreq *= 1000000; + bd->bi_busfreq *= 1000000; + bd->bi_cpmfreq *= 1000000; + bd->bi_brgfreq *= 1000000; +#endif + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* EST8260 */ + +#ifdef CONFIG_SBS8260 +/* We have to fill in everything. +*/ +static bd_t bdinfo; + +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + /* This should provided by the boot rom. + */ + bd = &bdinfo; + *bdp = bd; + bd->bi_baudrate = 9600; + bd->bi_memsize = 64 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. The development board had 66 MHz. + */ + bd->bi_busfreq = 66666666; + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 133000000; + + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* SBS8260 */ + +#ifdef CONFIG_RPX6 +/* The pointer we are given is for the string of key values. + */ +static bd_t bdinfo; + +void +embed_config(bd_t **bdp) +{ + u_char *cp, *keyvals; + int i; + bd_t *bd; + + keyvals = (u_char *)*bdp; + + bd = &bdinfo; + *bdp = bd; + + /* This is almost identical to the RPX-Lite/Classic functions + * on the 8xx boards. It would be nice to have a key lookup + * function in a string, but the format of all of the fields + * is slightly different. + */ + cp = keyvals; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + bd->bi_baudrate = rpx_baseten(cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + bd->bi_memsize = rpx_baseten(cp) * 1024 * 1024; + } + } + if (*cp == 'X') { + cp++; + if (*cp == 'T') { + cp += 2; + bd->bi_busfreq = rpx_baseten(cp); + } + } + if (*cp == 'N') { + cp++; + if (*cp == 'V') { + cp += 2; + bd->bi_nvsize = rpx_baseten(cp) * 1024 * 1024; + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; + + /* The memory size includes both the 60x and local bus DRAM. + * I don't want to use the local bus DRAM for real memory, + * so subtract it out. It would be nice if they were separate + * keys. + */ + bd->bi_memsize -= 32 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. + */ + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 200000000; +} +#endif /* RPX6 for testing */ + +#ifdef CONFIG_ADS8260 +/* We have to fill in everything. +*/ +static bd_t bdinfo; + +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + /* This should provided by the boot rom. + */ + bd = &bdinfo; + *bdp = bd; + bd->bi_baudrate = 9600; + bd->bi_memsize = 16 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. The development board had 66 MHz. + */ + bd->bi_busfreq = 66666666; + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 200000000; + + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* ADS8260 */ + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/gzimage.c linux/arch/ppc/boot/mbx/gzimage.c --- v2.4.4/linux/arch/ppc/boot/mbx/gzimage.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/gzimage.c Thu May 24 15:02:06 2001 @@ -0,0 +1,11 @@ +/* + * BK Id: SCCS/s.gzimage.c 1.6 05/18/01 15:17:06 cort + */ +/* + * gzimage.c + * + * Dummy file to allow a compressed zImage to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_gzimage; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/head.S linux/arch/ppc/boot/mbx/head.S --- v2.4.4/linux/arch/ppc/boot/mbx/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/head.S Thu May 24 15:02:06 2001 @@ -0,0 +1,243 @@ +/* + * BK Id: SCCS/s.head.S 1.9 05/18/01 07:54:04 patch + */ +#include +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * This code is loaded by the ROM loader at some arbitrary location. + * Move it to high memory so that it can load the kernel at 0x0000. + * + * This is a three step process that will also work when booting from + * a Flash PROM normally located in high memory. + * + * First, the entire image is loaded into some high memory address. + * This is usually at or above 0x02000000. This is done by a network + * boot function supported by the board or a debugger over BDM port. + * + * Second, the start up function here will relocate the decompress + * function to run at the link address of 0x01000000. + * + * Last, the decompression function will reloate the initrd, zImage, and + * the residual data to locations under 8 Meg. This is necessary because + * the embedded kernel start up uses 8 Meg translations to access physical + * space before the MMU is enabled. Finally, the zImage is uncompressed + * to location 0 and we jump to it. + * + * On the MBX, + * R1 - Stack pointer at a high memory address. + * R3 - Pointer to Board Information Block. + * R4 - Pointer to argument string. + * Interrupts masked, cache and MMU disabled. + * + * ...and the first and second functions listed above are + * done for us (it knows ELF images). + * + * For other embedded boards we build the Board Information Block. + */ + + .globl start +start: + bl start_ +start_: +#ifndef CONFIG_MBX + lis r11, local_bd_info@h + ori r11, r11, local_bd_info@l +#else + mr r11, r3 +#endif + + mfmsr r3 /* Turn off interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r3,r3,r4 + mtmsr r3 + + li r4,0 /* Zero DER to prevent FRZ */ + mtspr SPRN_DER,r4 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 +#if 0 + cmp 0,r3,r4 + beq start_ldr /* Branch if loaded OK */ +#endif + +/* + * no matter where we're loaded, move ourselves to -Ttext address + * This computes the sizes we need to determine other things. + */ + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr + +start_ldr: +/* Most 8xx boards don't boot up with the I-cache enabled. Do that + * now because the decompress runs much faster that way. + */ + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr IC_CST, r3 + +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b + + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + + /* Perform configuration of the various boards. This is done + * by reading some configuration data from EEPROM and building + * the board information structure. + */ + mr r3, r11 + mr r21, r11 + mr r22, r8 + mr r23, r7 + mr r24, r6 + + bl embed_config + mr r3, r21 + bl serial_init /* Init MBX serial port */ + + mr r11, r21 + mr r8, r22 + mr r7, r23 + mr r6, r24 + +#ifdef CONFIG_MBX + /* On the MBX (or anything that will TFTP load an ELF image), + * we have to find the intermediate address. The ELF loader + * only moves the Linux boostrap/decompress, not the zImage. + */ +#define ILAP_ADDRESS 0xfa000020 + lis r8, ILAP_ADDRESS@h + lwz r8, ILAP_ADDRESS@l(r8) + addis r8, r8, 1 /* Add 64K */ +#endif + + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + cmpi 0,r2,0 + bne 00b + + /* r4,r5 have initrd_start, size */ + lis r2,initrd_start@h + ori r2,r2,initrd_start@l + lwz r4,0(r2) + lis r2,initrd_end@h + ori r2,r2,initrd_end@l + lwz r5,0(r2) + + /* The world starts from the beginning. + */ + li r9,0x0 + mtlr r9 + + /* Invalidate the instruction cache because we just copied a + * bunch of kernel instructions. + */ + lis r9, IDC_INVALL@h + mtspr IC_CST, r9 + + blr +hang: + b hang + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + mulli r4,r3,1000 /* nanoseconds */ + addi r4,r4,59 + li r5,60 + divw r4,r4,r5 /* BUS ticks */ +1: mftbu r5 + mftb r6 + mftbu r7 + cmp 0,r5,r7 + bne 1b /* Get [synced] base time */ + addc r9,r6,r4 /* Compute end time */ + addze r8,r5 +2: mftbu r5 + cmp 0,r5,r8 + blt 2b + bgt 3f + mftb r6 + cmp 0,r6,r9 + blt 2b +3: blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + + .comm .stack,4096*2,4 +#ifndef CONFIG_MBX +local_bd_info: + .long 0 + .long 0x01000000 + .long 64 + .long 64 + .long 0 + .long 0 + .long 0 +#endif diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/head_8260.S linux/arch/ppc/boot/mbx/head_8260.S --- v2.4.4/linux/arch/ppc/boot/mbx/head_8260.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/head_8260.S Thu May 24 15:02:06 2001 @@ -0,0 +1,259 @@ +/* + * BK Id: SCCS/s.head_8260.S 1.8 05/18/01 07:54:04 patch + */ +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * Boot loader philosophy: + * + * ROM loads us to some arbitrary location + * ROM loads these registers: + * + * R3 = Pointer to the board configuration data + * R5 = Pointer to Open Firmware data + * + * ROM jumps to start/start_ + * Move the boot code to the link address (4 MB) + * Call decompress_kernel() + * Relocate the initrd, zimage and residual data to 4 MB + * Decompress the kernel to 0 + * Jump to the kernel entry + * -- Cort + */ + .globl start +start: + bl start_ +start_: + mr r11,r3 /* Save pointer to residual/board data */ + mr r25,r5 /* Save OFW pointer */ + li r3,MSR_IP /* Establish default MSR value */ + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + + /* Speed us up a little. + */ + bl flush_instruction_cache + +/* Run loader */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + mr r7,r25 /* OFW interfaces */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + cmpi 0,r2,0 + bne 00b + + /* r4,r5 have initrd_start, size */ + lis r2,initrd_start@h + ori r2,r2,initrd_start@l + lwz r4,0(r2) + lis r2,initrd_end@h + ori r2,r2,initrd_end@l + lwz r5,0(r2) + + /* tell kernel we're prep */ + /* + * get start address of kernel code which is stored as a coff + * entry. see boot/head.S -- Cort + */ + li r9,0x4 + mtlr r9 + lis r10,0xdeadc0de@h + ori r10,r10,0xdeadc0de@l + li r9,0 + stw r10,0(r9) +/* + * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 + * so disable BATs before setting this to avoid a clash + */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT1U,r8 + mtspr DBAT2U,r8 + mtspr DBAT3U,r8 + mtspr IBAT0U,r8 + mtspr IBAT1U,r8 + mtspr IBAT2U,r8 + mtspr IBAT3U,r8 + + blr +hang: + b hang + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,1 /* 601 ? */ + bne .udelay_not_601 +00: li r0,86 /* Instructions / microsecond? */ + mtctr r0 +10: addi r0,r0,0 /* NOP */ + bdnz 10b + subic. r3,r3,1 + bne 00b + blr + +.udelay_not_601: + mulli r4,r3,1000 /* nanoseconds */ + addi r4,r4,59 + li r5,60 + divw r4,r4,r5 /* BUS ticks */ +1: mftbu r5 + mftb r6 + mftbu r7 + cmp 0,r5,r7 + bne 1b /* Get [synced] base time */ + addc r9,r6,r4 /* Compute end time */ + addze r8,r5 +2: mftbu r5 + cmp 0,r5,r8 + blt 2b + bgt 3f + mftb r6 + cmp 0,r6,r9 + blt 2b +3: blr + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/iic.c linux/arch/ppc/boot/mbx/iic.c --- v2.4.4/linux/arch/ppc/boot/mbx/iic.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/iic.c Thu May 24 15:02:06 2001 @@ -0,0 +1,218 @@ +/* + * BK Id: SCCS/s.iic.c 1.8 05/18/01 07:54:04 patch + */ + +/* Minimal support functions to read configuration from IIC EEPROMS + * on MPC8xx boards. Originally written for RPGC RPX-Lite. + * Dan Malek (dmalek@jlc.net). + */ +#include +#include +#include +#include "../../8xx_io/commproc.h" + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +void iic_read(uint devaddr, u_char *buf, uint offset, uint count); + +static int iic_init_done; + +static void +iic_init() +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + uint dpaddr; + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + /* Reset the CPM. This is necessary on the 860 processors + * that may have started the SCC1 ethernet without relocating + * the IIC. + * This also stops the Ethernet in case we were loaded by a + * BOOTP rom monitor. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); + + /* Remove any microcode patches. We will install our own + * later. + */ + cp->cp_cpmcr1 = 0; + cp->cp_cpmcr2 = 0; + cp->cp_cpmcr3 = 0; + cp->cp_cpmcr4 = 0; + cp->cp_rccr = 0; + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Initialize the parameter ram. + */ + + /* Allocate space for a two transmit and one receive buffer + * descriptor in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0840; + + /* Set up the IIC parameters in the parameter ram. + */ + iip->iic_tbase = dpaddr; + iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + /* This should really be done by the reader/writer. + */ + iip->iic_mrblr = 128; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0x34; + + /* Make clock run maximum slow. + */ + i2c->i2c_i2brg = 7; + + /* Disable interrupts. + */ + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + /* Enable SDMA. + */ + immap->im_siu_conf.sc_sdcr = 1; + + iic_init_done = 1; +} + +/* Read from IIC. + * Caller provides device address, memory buffer, and byte count. + */ +static u_char iitemp[32]; + +void +iic_read(uint devaddr, u_char *buf, uint offset, uint count) +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + u_char *tb; + uint temp; + + /* If the interface has not been initialized, do that now. + */ + if (!iic_init_done) + iic_init(); + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + /* Send a "dummy write" operation. This is a write request with + * only the offset sent, followed by another start condition. + * This will ensure we start reading from the first location + * of the EEPROM. + */ + tb = iitemp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr & 0xfe; /* Device address */ + *(tb+1) = offset; /* Offset */ + tbdf->cbd_datlen = 2; /* Length */ + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 3) == 0); + + if (tbdf->cbd_sc & BD_SC_READY) + printf("IIC ra complete but tbuf ready\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#if 0 + /* We can't do this...there is no serial port yet! + */ + if (temp == 0) { + printf("Timeout reading EEPROM\n"); + return; + } +#endif +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; + + /* To read, we need an empty buffer of the proper length. + * All that is used is the first byte for address, the remainder + * is just used for timing (and doesn't really have to exist). + */ + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr | 1; /* Device address */ + rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ + tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ + tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + + /* Chip bug, set enable here. + */ + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 1) == 0); + + if (rbdf->cbd_sc & BD_SC_EMPTY) + printf("IIC read complete but rbuf empty\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/m8260_tty.c linux/arch/ppc/boot/mbx/m8260_tty.c --- v2.4.4/linux/arch/ppc/boot/mbx/m8260_tty.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/m8260_tty.c Thu May 24 15:02:06 2001 @@ -0,0 +1,312 @@ +/* + * BK Id: SCCS/s.m8260_tty.c 1.7 05/18/01 07:54:04 patch + */ + + +/* Minimal serial functions needed to send messages out the serial + * port on SMC1. + */ +#include +#include +#include + +uint no_print; +extern char *params[]; +extern int nparams; +static u_char cons_hold[128], *sgptr; +static int cons_hold_cnt; + +/* If defined, enables serial console. The value (1 through 4) + * should designate which SCC is used, but this isn't complete. Only + * SCC1 is known to work at this time. + */ +#ifdef CONFIG_SCC_CONSOLE +#define SCC_CONSOLE 1 +#endif + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile scc_t *sccp; + volatile scc_uart_t *sup; + volatile cbd_t *tbdf, *rbdf; + volatile immap_t *ip; + volatile iop8260_t *io; + volatile cpm8260_t *cp; + uint dpaddr, memaddr; + + ip = (immap_t *)IMAP_ADDR; + cp = &ip->im_cpm; + io = &ip->im_ioport; + + /* Perform a reset. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & CPM_CR_FLG); + +#ifdef CONFIG_ADS8260 + /* Enable the RS-232 transceivers. + */ + *(volatile uint *)(BCSR_ADDR + 4) &= + ~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2); +#endif + +#ifdef SCC_CONSOLE + sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]); + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Use Port D for SCC1 instead of other functions. + */ + io->iop_ppard |= 0x00000003; + io->iop_psord &= ~0x00000001; /* Rx */ + io->iop_psord |= 0x00000002; /* Tx */ + io->iop_pdird &= ~0x00000001; /* Rx */ + io->iop_pdird |= 0x00000002; /* Tx */ + +#else + sp = (smc_t*)&(ip->im_smc[0]); + *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; + up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* Use Port D for SMC1 instead of other functions. + */ + io->iop_ppard |= 0x00c00000; + io->iop_pdird |= 0x00400000; + io->iop_pdird &= ~0x00800000; + io->iop_psord &= ~0x00c00000; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. + */ + memaddr = (bd->bi_memsize - 256) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+128; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ +#ifdef SCC_CONSOLE + sup->scc_genscc.scc_rbase = dpaddr; + sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t); + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + sup->scc_genscc.scc_mrblr = 128; + sup->scc_maxidl = 8; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sccp->scc_gsmrh = 0; + sccp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + sccp->scc_sccm = 0; + sccp->scc_scce = 0xffff; + sccp->scc_dsr = 0x7e7e; + sccp->scc_pmsr = 0x3000; + + /* Wire BRG1 to SCC1. The console driver will take care of + * others. + */ + ip->im_cpmux.cmx_scr = 0; +#else + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; + up->smc_brklen = 0; + up->smc_brkec = 0; + up->smc_brkcr = 0; + up->smc_mrblr = 128; + up->smc_maxidl = 8; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + */ + ip->im_cpmux.cmx_smr = 0; +#endif + + /* The baud rate divisor needs to be coordinated with clk_8260(). + */ + ip->im_brgc1 = + (((bd->bi_brgfreq/16) / bd->bi_baudrate) << 1) | + CPM_BRG_EN; + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Initialize Tx/Rx parameters. + */ +#ifdef SCC_CONSOLE + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#else + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +#endif +} + +void +serial_putc(void *ignored, const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + extern bd_t *board_info; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; +#endif + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc(void *ignored) +{ + char c; + + if (cons_hold_cnt <= 0) { + cons_hold_cnt = serial_readbuf(cons_hold); + sgptr = cons_hold; + } + c = *sgptr++; + cons_hold_cnt--; + + return(c); +} + +int +serial_readbuf(u_char *cbuf) +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + int i, nc; + + ip = (immap_t *)IMAP_ADDR; + +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + nc = rbdf->cbd_datlen; + for (i=0; icbd_sc |= BD_SC_EMPTY; + + return(nc); +} + +int +serial_tstc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/m8xx_tty.c linux/arch/ppc/boot/mbx/m8xx_tty.c --- v2.4.4/linux/arch/ppc/boot/mbx/m8xx_tty.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/m8xx_tty.c Thu May 24 15:02:06 2001 @@ -0,0 +1,288 @@ +/* + * BK Id: SCCS/s.m8xx_tty.c 1.8 05/18/01 07:54:04 patch + */ + + +/* Minimal serial functions needed to send messages out the serial + * port on the MBX console. + * + * The MBX uxes SMC1 for the serial port. We reset the port and use + * only the first BD that EPPC-Bug set up as a character FIFO. + * + * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug + * use COM1 instead of SMC1 as the console port. This kinda sucks + * for the rest of the kernel, so here we force the use of SMC1 again. + */ +#include +#include +#include +#include +#include "../../8xx_io/commproc.h" + +#ifdef CONFIG_MBX +#define MBX_CSR1 ((volatile u_char *)0xfa100000) +#define CSR1_COMEN (u_char)0x02 +#endif + +#ifdef TQM_SMC2_CONSOLE +#define PROFF_CONS PROFF_SMC2 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 +#define SMC_INDEX 1 +static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); +#else +#define PROFF_CONS PROFF_SMC1 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 +#define SMC_INDEX 0 +#endif + +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + uint dpaddr, memaddr, ui; + + cp = cpmp; + sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); + up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +#ifdef CONFIG_FADS + /* Enable SMC1/2 transceivers. + */ + *((volatile uint *)BCSR1) &= ~(BCSR1_RS232EN_1|BCSR1_RS232EN_2); +#endif + +#ifndef CONFIG_MBX + { + /* Initialize SMCx and use it for the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + +#ifdef TQM_SMC2_CONSOLE + /* Use Port A for SMC2 instead of other functions. + */ + iopp->iop_papar |= 0x00c0; + iopp->iop_padir &= ~0x00c0; + iopp->iop_paodr &= ~0x00c0; +#else + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory for SMC FIFOs. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * This wires BRG1 to SMC1 and BRG2 to SMC2; + */ + cp->cp_simode = 0x10000000; + ui = bd->bi_intfreq / 16 / bd->bi_baudrate; +#ifdef TQM_SMC2_CONSOLE + cp->cp_brgc2 = +#else + cp->cp_brgc1 = +#endif + ((ui - 1) < 4096) + ? (((ui - 1) << 1) | CPM_BRG_EN) + : ((((ui / 16) - 1) << 1) | CPM_BRG_EN | CPM_BRG_DIV16); + +#else /* CONFIG_MBX */ + if (*MBX_CSR1 & CSR1_COMEN) { + /* COM1 is enabled. Initialize SMC1 and use it for + * the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + (((bd->bi_intfreq/16) / 9600) << 1) | CPM_BRG_EN; + + /* Enable SMC1 for console output. + */ + *MBX_CSR1 &= ~CSR1_COMEN; + } + else { +#endif /* ndef CONFIG_MBX */ + /* SMCx is used as console port. + */ + tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; + + /* Issue a stop transmit, and wait for it. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Single character receive. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +void +serial_putc(void *ignored, const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/misc.c linux/arch/ppc/boot/mbx/misc.c --- v2.4.4/linux/arch/ppc/boot/mbx/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/misc.c Thu May 24 15:02:06 2001 @@ -0,0 +1,296 @@ +/* + * BK Id: SCCS/s.misc.c 1.9 05/18/01 07:54:04 patch + */ +/* + * Adapted for PowerPC by Gary Thomas + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort + */ + +#include +#include +#include "zlib.h" +#include +#include +#include +#include +#include +#ifdef CONFIG_8xx +#include +#endif +#ifdef CONFIG_8260 +#include +#endif + +/* + * The following references are needed to cause the linker to pull in the + * gzimage.o and rdimage.o files. These object files are special, + * since they get placed into the .gzimage and .rdimage ELF sections + * of the zvmlinux and zvmlinux.initrd files. + */ +extern char dummy_for_gzimage; +extern char dummy_for_rdimage; + +/* + * Please send me load/board info and such data for hardware not + * listed here so I can keep track since things are getting tricky + * with the different load addrs with different firmware. This will + * help to avoid breaking the load/boot process. + * -- Cort + */ +char *avail_ram; +char *end_avail; + +/* See comment below..... +*/ +unsigned int initrd_offset, initrd_size; + +/* Because of the limited amount of memory on embedded, it presents + * loading problems. The biggest is that we load this boot program + * into a relatively low memory address, and the Linux kernel Bss often + * extends into this space when it get loaded. When the kernel starts + * and zeros the BSS space, it also writes over the information we + * save here and pass to the kernel (command line and board info). + * On these boards, we grab some known memory holes to hold this information. + */ +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +/* This is the default cmdline that will be given to the user at boot time.. + * If none was specified at compile time, we'll give it one that should work. + * -- Tom */ +#ifdef CONFIG_CMDLINE_BOOL +char compiled_string[] = CONFIG_CMDLINE; +#endif +char ramroot_string[] = "root=/dev/ram"; +char netroot_string[] = "root=/dev/nfs rw"; + +bd_t hold_resid_buf; +bd_t *hold_residual = &hold_resid_buf; +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +extern void puts(const char *); +extern void putc(const char c); +extern void udelay(long x); +extern void puthex(unsigned long val); +extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n); +extern void gunzip(void *, int, unsigned char *, int *); +extern int tstc(void); +extern int getc(void); + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) +{ + int timer; + extern unsigned long start; + char *cp, ch; + +#ifdef CONFIG_8260 + /* I don't know why I didn't do it this way on the 8xx....... + */ + embed_config(&bp); + serial_init(bp); +#endif + + /* These values must be variables. If not, the compiler optimizer + * will remove some code, causing the size of the code to vary + * when these values are zero. This is bad because we first + * compile with these zero to determine the size and offsets + * in an image, than compile again with these set to the proper + * discovered value.....Ya know, we used to read these from the + * header a long time ago..... + */ + initrd_offset = INITRD_OFFSET; + initrd_size = INITRD_SIZE; + + /* Grab some space for the command line and board info. Since + * we no longer use the ELF header, but it was loaded, grab + * that space. + */ +#ifdef CONFIG_MBX + cmd_line = (char *)(load_addr - 0x10000); + + /* To be like everyone else, we need one too, although this + * board information is passed from the boot rom. + */ + bp->bi_baudrate = 9600; +#else + cmd_line = (char *)(0x200000); +#endif + hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); + /* copy board data */ + if (bp) + memcpy(hold_residual,bp,sizeof(bd_t)); + + /* Set end of memory available to us. It is always the highest + * memory address provided by the board information. + */ + end_avail = (char *)(bp->bi_memsize); + + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( bp ) + { + puts("board data at: "); puthex((unsigned long)bp); + puts(" "); + puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); + puts("\n"); + puts("relocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including the + size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( initrd_offset ) + initrd_start = load_addr - 0x10000 + initrd_offset; + else + initrd_start = 0; + initrd_end = initrd_size + initrd_start; + + /* + * setup avail_ram - this is the first part of ram usable + * by the uncompress code. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); + if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)(load_addr+(num_words*4)); + if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)((unsigned long)&start+(num_words*4)); + + /* relocate zimage */ + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + /* + * There is no reason (yet) to relocate zImage for embedded boards. + * To support boot from flash rom on 8xx embedded boards, I + * assume if zimage start is over 16M we are booting from flash. + * In this case, avilable ram will start just above the space we + * have allocated for the command buffer and board information. + */ + if ((unsigned long)zimage_start > 0x01000000) + avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + + /* We only have to relocate initrd if we find it is in Flash + * rom. This is because the kernel thinks it can toss the + * pages into the free memory pool after it is done. Use + * the same 16M test. + */ + if ((unsigned long)initrd_start > 0x01000000) { + memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), + (void *)initrd_start, + initrd_size ); + initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); + initrd_end = initrd_start + initrd_size; + end_avail = (char *)initrd_start; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + else { + avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); + } + } + + + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + /* This is where we try and pick the right command line for booting. + * If we were given one at compile time, use it. It Is Right. + * If we weren't, see if we have a ramdisk. If so, thats root. + * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom */ +#ifdef CONFIG_CMDLINE_BOOL + memcpy (cmd_line, compiled_string, sizeof(compiled_string)); +#else + if (initrd_start) + memcpy (cmd_line, ramroot_string, sizeof(ramroot_string)); + else + memcpy (cmd_line, netroot_string, sizeof(netroot_string)); +#endif + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b' || ch == '\177') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else if (ch == '\030' /* ^x */ + || ch == '\025') { /* ^u */ + while (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\nUncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + puts("Now booting the kernel\n"); + return (unsigned long)hold_residual; +} + +/* + * PCI/ISA I/O support + */ + +volatile unsigned char *ISA_io = (unsigned char *)0x80000000; +volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; + +void +outb(int port, char val) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + ISA_io[port] = val; +} + +unsigned char +inb(int port) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return (ISA_io[port]); +} + +unsigned long +local_to_PCI(unsigned long addr) +{ + return ((addr & 0x7FFFFFFF) | 0x80000000); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/pci.c linux/arch/ppc/boot/mbx/pci.c --- v2.4.4/linux/arch/ppc/boot/mbx/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/pci.c Thu May 24 15:02:06 2001 @@ -0,0 +1,255 @@ +/* + * BK Id: SCCS/s.pci.c 1.6 05/18/01 15:17:06 cort + */ +/* Stand alone funtions for QSpan Tundra support. + */ +#include +#include +#include +#include + +/* To map PCI devices, you first write 0xffffffff into the device + * base address registers. When the register is read back, the + * number of most significant '1' bits describes the amount of address + * space needed for mapping. If the most significant bit is not set, + * either the device does not use that address register, or it has + * a fixed address that we can't change. After the address is assigned, + * the command register has to be written to enable the card. + */ +typedef struct { + u_char pci_bus; + u_char pci_devfn; + ushort pci_command; + uint pci_addrs[6]; +} pci_map_t; + +/* We should probably dynamically allocate these structures. +*/ +#define MAX_PCI_DEVS 32 +int pci_dev_cnt; +pci_map_t pci_map[MAX_PCI_DEVS]; + +void pci_conf_write(int bus, int device, int func, int reg, uint writeval); +void pci_conf_read(int bus, int device, int func, int reg, void *readval); +void probe_addresses(int bus, int devfn); +void map_pci_addrs(void); + +/* This is a really stripped version of PCI bus scan. All we are + * looking for are devices that exist. + */ +pci_scanner(int addr_probe) +{ + unsigned int devfn, l, max, class, bus_number; + unsigned char cmd, irq, tmp, hdr_type, is_multi; + int reg; + + is_multi = 0; + bus_number = 0; + for (devfn = 0; devfn < 0xff; ++devfn) { + /* The device numbers are comprised of upper 5 bits of + * device number and lower 3 bits of multi-function number. + */ + if ((devfn & 7) && !is_multi) { + /* Don't scan multifunction addresses if this is + * not a multifunction device. + */ + continue; + } + + /* Read the header to determine card type. + */ + qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, + &hdr_type); + + /* If this is a base device number, check the header to + * determine if it is mulifunction. + */ + if ((devfn & 7) == 0) + is_multi = hdr_type & 0x80; + + /* Check to see if the board is really in the slot. + */ + qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); + /* some broken boards return 0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || + l == 0xffff0000) { + /* Nothing there. + */ + is_multi = 0; + continue; + } + + /* If we are not performing an address probe, + * just simply print out some information. + */ + if (!addr_probe) { + qs_pci_read_config_dword(bus_number, devfn, + PCI_CLASS_REVISION, &class); + + class >>= 8; /* upper 3 bytes */ + +#if 0 + printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", + (devfn >> 3), (devfn & 7), + (l & 0xffff), (l >> 16) & 0xffff, class); +#else + puts("Found ("); puthex(devfn >> 3); + puts(":"); puthex(devfn & 7); + puts("): vendor "); puthex(l & 0xffff); + puts(", device "); puthex((l >> 16) & 0xffff); + puts(", class "); puthex(class); puts("\n"); +#endif + } + else { + /* If this is a "normal" device, build address list. + */ + if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) + probe_addresses(bus_number, devfn); + } + } + + /* Now map the boards. + */ + if (addr_probe) + map_pci_addrs(); +} + +/* Probe addresses for the specified device. This is a destructive + * operation because it writes the registers. + */ +void +probe_addresses(bus, devfn) +{ + int i; + uint pciaddr; + ushort pcicmd; + pci_map_t *pm; + + if (pci_dev_cnt >= MAX_PCI_DEVS) { + puts("Too many PCI devices\n"); + return; + } + + pm = &pci_map[pci_dev_cnt++]; + + pm->pci_bus = bus; + pm->pci_devfn = devfn; + + for (i=0; i<6; i++) { + qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); + qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), + &pciaddr); + pm->pci_addrs[i] = pciaddr; + qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); + pm->pci_command = pcicmd; + } +} + +/* Map the cards into the PCI space. The PCI has separate memory + * and I/O spaces. In addition, some memory devices require mapping + * below 1M. The least significant 4 bits of the address register + * provide information. If this is an I/O device, only the LS bit + * is used to indicate that, so I/O devices can be mapped to a two byte + * boundard. Memory addresses can be mapped to a 32 byte boundary. + * The QSpan implementations usually have a 1Gbyte space for each + * memory and I/O spaces. + * + * This isn't a terribly fancy algorithm. I just map the spaces from + * the top starting with the largest address space. When finished, + * the registers are written and the card enabled. + * + * While the Tundra can map a large address space on most boards, we + * need to be careful because it may overlap other devices (like IMMR). + */ +#define MEMORY_SPACE_SIZE 0x20000000 +#define IO_SPACE_SIZE 0x20000000 + +void +map_pci_addrs() +{ + uint pci_mem_top, pci_mem_low; + uint pci_io_top; + uint addr_mask, reg_addr, space; + int i, j; + pci_map_t *pm; + + pci_mem_top = MEMORY_SPACE_SIZE; + pci_io_top = IO_SPACE_SIZE; + pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ + + /* We can't map anything more than the maximum space, but test + * for it anyway to catch devices out of range. + */ + addr_mask = 0x80000000; + + do { + space = (~addr_mask) + 1; /* Size of the space */ + for (i=0; ipci_addrs[j]; + if ((reg_addr & 0x80000000) == 0) + continue; + if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { + if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) + continue; + if (pci_io_top < space) { + puts("Out of PCI I/O space\n"); + } + else { + pci_io_top -= space; + pm->pci_addrs[j] = pci_io_top; + pm->pci_command |= PCI_COMMAND_IO; + } + } + else { + if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) + continue; + + /* Memory space. Test if below 1M. + */ + if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { + if (pci_mem_low < space) { + puts("Out of PCI 1M space\n"); + } + else { + pci_mem_low -= space; + pm->pci_addrs[j] = pci_mem_low; + } + } + else { + if (pci_mem_top < space) { + puts("Out of PCI Mem space\n"); + } + else { + pci_mem_top -= space; + pm->pci_addrs[j] = pci_mem_top; + } + } + pm->pci_command |= PCI_COMMAND_MEMORY; + } + } + } + addr_mask >>= 1; + addr_mask |= 0x80000000; + } while (addr_mask != 0xfffffffe); + + /* Now, run the list one more time and map everything. + */ + for (i=0; ipci_bus, pm->pci_devfn, + PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); + } + + /* Enable memory or address mapping. + */ + qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, + pm->pci_command); + } +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/qspan_pci.c linux/arch/ppc/boot/mbx/qspan_pci.c --- v2.4.4/linux/arch/ppc/boot/mbx/qspan_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/qspan_pci.c Thu May 24 15:02:06 2001 @@ -0,0 +1,271 @@ +/* + * BK Id: SCCS/s.qspan_pci.c 1.6 05/18/01 15:17:06 cort + */ +/* + * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) + * + * QSpan Motorola bus to PCI bridge. The config address register + * is located 0x500 from the base of the bridge control/status registers. + * The data register is located at 0x504. + * This is a two step operation. First, the address register is written, + * then the data register is read/written as required. + * I don't know what to do about interrupts (yet). + */ + +#include +#include +#include +#include + +/* + * When reading the configuration space, if something does not respond + * the bus times out and we get a machine check interrupt. So, the + * good ol' exception tables come to mind to trap it and return some + * value. + * + * On an error we just return a -1, since that is what the caller wants + * returned if nothing is present. I copied this from __get_user_asm, + * with the only difference of returning -1 instead of EFAULT. + * There is an associated hack in the machine check trap code. + * + * The QSPAN is also a big endian device, that is it makes the PCI + * look big endian to us. This presents a problem for the Linux PCI + * functions, which assume little endian. For example, we see the + * first 32-bit word like this: + * ------------------------ + * | Device ID | Vendor ID | + * ------------------------ + * If we read/write as a double word, that's OK. But in our world, + * when read as a word, device ID is at location 0, not location 2 as + * the little endian PCI would believe. We have to switch bits in + * the PCI addresses given to us to get the data to/from the correct + * byte lanes. + * + * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. + * It always forces the MS bit to zero. Therefore, dev_fn values + * greater than 128 are returned as "no device found" errors. + * + * The QSPAN can only perform long word (32-bit) configuration cycles. + * The "offset" must have the two LS bits set to zero. Read operations + * require we read the entire word and then sort out what should be + * returned. Write operations other than long word require that we + * read the long word, update the proper word or byte, then write the + * entire long word back. + * + * PCI Bridge hack. We assume (correctly) that bus 0 is the primary + * PCI bus from the QSPAN. If we are called with a bus number other + * than zero, we create a Type 1 configuration access that a downstream + * PCI bridge will interpret. + */ + +#define __get_pci_config(x, addr, op) \ + __asm__ __volatile__( \ + "1: "op" %0,0(%1)\n" \ + " eieio\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".text" \ + : "=r"(x) : "r"(addr)) + +#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) +#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) + +#define mk_config_addr(bus, dev, offset) \ + (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) + +#define mk_config_type1(bus, dev, offset) \ + mk_config_addr(bus, dev, offset) | 1; + +/* Initialize the QSpan device registers after power up. +*/ +qspan_init() +{ + uint *qptr; + + + + qptr = (uint *)PCI_CSR_ADDR; + + /* PCI Configuration/status. Upper bits written to clear + * pending interrupt or status. Lower bits enable QSPAN as + * PCI master, enable memory and I/O cycles, and enable PCI + * parity error checking. + * IMPORTANT: The last two bits of this word enable PCI + * master cycles into the QBus. The QSpan is broken and can't + * meet the timing specs of the PQ bus for this to work. Therefore, + * if you don't have external bus arbitration, you can't use + * this function. + */ +#ifdef EXTERNAL_PQ_ARB + qptr[1] = 0xf9000147; +#else + qptr[1] = 0xf9000144; +#endif + + /* PCI Misc configuration. Set PCI latency timer resolution + * of 8 cycles, set cache size to 4 x 32. + */ + qptr[3] = 0; + + /* Set up PCI Target address mapping. Enable, Posted writes, + * 2Gbyte space (processor memory controller determines actual size). + */ + qptr[64] = 0x8f000080; + + /* Map processor 0x80000000 to PCI 0x00000000. + * Processor address bit 1 determines I/O type access (0x80000000) + * or memory type access (0xc0000000). + */ + qptr[65] = 0x80000000; + + /* Enable error logging and clear any pending error status. + */ + qptr[80] = 0x90000000; + + qptr[512] = 0x000c0003; + + /* Set up Qbus slave image. + */ + qptr[960] = 0x01000000; + qptr[961] = 0x000000d1; + qptr[964] = 0x00000000; + qptr[965] = 0x000000d1; + +} + +/* Functions to support PCI bios-like features to read/write configuration + * space. If the function fails for any reason, a -1 (0xffffffff) value + * must be returned. + */ +#define DEVICE_NOT_FOUND (-1) +#define SUCCESSFUL 0 + +int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *val = *cp; + return SUCCESSFUL; +} + +int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + offset ^= 0x02; + + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *val = *sp; + return SUCCESSFUL; +} + +int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffffffff; + return DEVICE_NOT_FOUND; + } + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); + return SUCCESSFUL; +} + +int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *cp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x02; + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *sp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *(unsigned int *)QS_CONFIG_DATA = val; + + return SUCCESSFUL; +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mbx/rdimage.c linux/arch/ppc/boot/mbx/rdimage.c --- v2.4.4/linux/arch/ppc/boot/mbx/rdimage.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/mbx/rdimage.c Thu May 24 15:02:06 2001 @@ -0,0 +1,11 @@ +/* + * BK Id: SCCS/s.rdimage.c 1.6 05/18/01 15:17:06 cort + */ +/* + * rdimage.c + * + * Dummy file to allow a compressed initrd to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_rdimage; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c --- v2.4.4/linux/arch/ppc/boot/misc.c Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/boot/misc.c Wed Dec 31 16:00:00 1969 @@ -1,845 +0,0 @@ -/* - * misc.c - * - * $Id: misc.c,v 1.68 1999/10/20 22:08:08 cort Exp $ - * - * Adapted for PowerPC by Gary Thomas - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) - * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort - */ - -#include -#include "../coffboot/zlib.h" -#include "asm/residual.h" -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SERIAL_CONSOLE) -#include "ns16550.h" -struct NS16550 *com_port; -#endif /* CONFIG_SERIAL_CONSOLE */ - -/* - * Please send me load/board info and such data for hardware not - * listed here so I can keep track since things are getting tricky - * with the different load addrs with different firmware. This will - * help to avoid breaking the load/boot process. - * -- Cort - */ -char *avail_ram; -char *end_avail; -extern char _end[]; - -#ifdef CONFIG_CMDLINE -#define CMDLINE CONFIG_CMDLINE -#else -#define CMDLINE ""; -#endif -char cmd_preset[] = CMDLINE; -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -int keyb_present = 1; /* keyboard controller is present by default */ -RESIDUAL hold_resid_buf; -RESIDUAL *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; -char *zimage_start; -int zimage_size; - -char *vidmem = (char *)0xC00B8000; -int lines, cols; -int orig_x, orig_y; - -void puts(const char *); -void putc(const char c); -void puthex(unsigned long val); -void _bcopy(char *src, char *dst, int len); -void * memcpy(void * __dest, __const void * __src, - int __n); -void gunzip(void *, int, unsigned char *, int *); -static int _cvt(unsigned long val, char *buf, long radix, char *digits); -unsigned char inb(int); - -void pause() -{ - puts("pause\n"); -} - -void exit() -{ - puts("exit\n"); - while(1); -} - -static void clear_screen() -{ - int i, j; - for (i = 0; i < lines; i++) { - for (j = 0; j < cols; j++) { - vidmem[((i*cols)+j)*2] = ' '; - vidmem[((i*cols)+j)*2+1] = 0x07; - } - } -} - -static void scroll() -{ - int i; - - memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); - for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) - vidmem[i] = ' '; -} - -tstc(void) -{ -#if defined(CONFIG_SERIAL_CONSOLE) - if (keyb_present) - return (CRT_tstc() || NS16550_tstc(com_port)); - else - NS16550_tstc(com_port); -#else - return (CRT_tstc() ); -#endif /* CONFIG_SERIAL_CONSOLE */ -} - -getc(void) -{ - while (1) { -#if defined(CONFIG_SERIAL_CONSOLE) - if (NS16550_tstc(com_port)) return (NS16550_getc(com_port)); -#endif /* CONFIG_SERIAL_CONSOLE */ - if (keyb_present) - if (CRT_tstc()) return (CRT_getc()); - } -} - -void -putc(const char c) -{ - int x,y; - -#if defined(CONFIG_SERIAL_CONSOLE) - NS16550_putc(com_port, c); - if ( c == '\n' ) NS16550_putc(com_port, '\r'); -#endif /* CONFIG_SERIAL_CONSOLE */ - - x = orig_x; - y = orig_y; - - if ( c == '\n' ) { - x = 0; - if ( ++y >= lines ) { - scroll(); - y--; - } - } else if (c == '\r') { - x = 0; - } else if (c == '\b') { - if (x > 0) { - x--; - } - } else { - vidmem [ ( x + cols * y ) * 2 ] = c; - if ( ++x >= cols ) { - x = 0; - if ( ++y >= lines ) { - scroll(); - y--; - } - } - } - - cursor(x, y); - - orig_x = x; - orig_y = y; -} - -void puts(const char *s) -{ - int x,y; - char c; - - x = orig_x; - y = orig_y; - - while ( ( c = *s++ ) != '\0' ) { -#if defined(CONFIG_SERIAL_CONSOLE) - NS16550_putc(com_port, c); - if ( c == '\n' ) NS16550_putc(com_port, '\r'); -#endif /* CONFIG_SERIAL_CONSOLE */ - - if ( c == '\n' ) { - x = 0; - if ( ++y >= lines ) { - scroll(); - y--; - } - } else if (c == '\b') { - if (x > 0) { - x--; - } - } else { - vidmem [ ( x + cols * y ) * 2 ] = c; - if ( ++x >= cols ) { - x = 0; - if ( ++y >= lines ) { - scroll(); - y--; - } - } - } - } - - cursor(x, y); - - orig_x = x; - orig_y = y; -} - -void * memcpy(void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++) d[i] = s[i]; -} - -int memcmp(__const void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++, d++, s++) - { - if (*d != *s) - { - return (*s - *d); - } - } - return (0); -} - -void error(char *x) -{ - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); - - while(1); /* Halt */ -} - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p = avail_ram; - - size *= items; - size = (size + 7) & -8; - avail_ram += size; - if (avail_ram > end_avail) { - puts("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - puts("bad gzipped data\n"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - puts("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - puts("inflateInit2 returned %d\n"); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - puts("inflate returned %d\n"); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} - -unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, - RESIDUAL *residual, void *OFW_interface) -{ - int timer; - extern unsigned long start; - char *cp, ch; - unsigned long i; - BATU *u; - BATL *l; - unsigned long TotalMemory; - unsigned long orig_MSR; - int dev_handle; - int mem_info[2]; - int res, size; - unsigned char board_type; - unsigned char base_mod; - - lines = 25; - cols = 80; - orig_x = 0; - orig_y = 24; - - /* - * IBM's have the MMU on, so we have to disable it or - * things get really unhappy in the kernel when - * trying to setup the BATs with the MMU on - * -- Cort - */ - flush_instruction_cache(); - _put_HID0(_get_HID0() & ~0x0000C000); - _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); - -#if defined(CONFIG_SERIAL_CONSOLE) - com_port = (struct NS16550 *)NS16550_init(0); -#endif /* CONFIG_SERIAL_CONSOLE */ - vga_init(0xC0000000); - - if (residual) - { - /* Is this Motorola PPCBug? */ - if ((1 & residual->VitalProductData.FirmwareSupports) && - (1 == residual->VitalProductData.FirmwareSupplier)) { - board_type = inb(0x800) & 0xF0; - - /* If this is genesis 2 board then check for no - * keyboard controller and more than one processor. - */ - if (board_type == 0xe0) { - base_mod = inb(0x803); - /* if a MVME2300/2400 or a Sitka then no keyboard */ - if((base_mod == 0xFA) || (base_mod == 0xF9) || - (base_mod == 0xE1)) { - keyb_present = 0; /* no keyboard */ - } - } - } - memcpy(hold_residual,residual,sizeof(RESIDUAL)); - } else { - /* Assume 32M in the absence of more info... */ - TotalMemory = 0x02000000; - /* - * This is a 'best guess' check. We want to make sure - * we don't try this on a PReP box without OF - * -- Cort - */ - while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) - { - /* The MMU needs to be on when we call OFW */ - _put_MSR(orig_MSR); - of_init(OFW_interface); - - /* get handle to memory description */ - res = of_finddevice("/memory@0", - &dev_handle); - // puthex(res); puts("\n"); - if (res) break; - - /* get the info */ - // puts("get info = "); - res = of_getprop(dev_handle, - "reg", - mem_info, - sizeof(mem_info), - &size); - // puthex(res); puts(", info = "); puthex(mem_info[0]); - // puts(" "); puthex(mem_info[1]); puts("\n"); - if (res) break; - - TotalMemory = mem_info[1]; - break; - } - hold_residual->TotalMemory = TotalMemory; - residual = hold_residual; - /* Turn MMU back off */ - _put_MSR(orig_MSR & ~0x0030); - } - - /* assume the chunk below 8M is free */ - end_avail = (char *)0x00800000; - - /* tell the user where we were loaded at and where we - * were relocated to for debugging this process - */ - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( residual ) - { - puts("board data at: "); puthex((unsigned long)residual); - puts(" "); - puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); - puts("\n"); - } - - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; - else - initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; - - /* - * Find a place to stick the zimage and initrd and - * relocate them if we have to. -- Cort - */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); - puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - if ( (unsigned long)zimage_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); - zimage_start = (char *)avail_ram; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); - avail_ram += zimage_size; - } - - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - if ( (unsigned long)initrd_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, - (void *)initrd_start, initrd_end-initrd_start ); - puts("relocated to: "); - initrd_end = (unsigned long) avail_ram + (initrd_end-initrd_start); - initrd_start = (unsigned long)avail_ram; - puthex((unsigned long)initrd_start); - puts(" "); - puthex((unsigned long)initrd_end); - puts("\n"); - } - avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); - } - - avail_ram = (char *)0x00400000; - end_avail = (char *)0x00800000; - puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); - puthex((unsigned long)end_avail); puts("\n"); - - if (keyb_present) - CRT_tstc(); /* Forces keyboard to be initialized */ - - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); - while ( *cp ) putc(*cp++); - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - puts("\n"); - - puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); - puts("done.\n"); - - { - struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN(zimage_size); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - memcpy( (void *)rec->data, "prepboot", 9); - rec->size = sizeof(struct bi_record) + 8 + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_prep; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_CMD_LINE; - memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); - rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; - rec = (struct bi_record *)((ulong)rec + rec->size); - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - } - puts("Now booting the kernel\n"); - return (unsigned long)hold_residual; -} - -void puthex(unsigned long val) -{ - unsigned char buf[10]; - int i; - for (i = 7; i >= 0; i--) - { - buf[i] = "0123456789ABCDEF"[val & 0x0F]; - val >>= 4; - } - buf[8] = '\0'; - puts(buf); -} - -/* - * PCI/ISA I/O support - */ - -volatile unsigned char *ISA_io = (unsigned char *)0x80000000; -volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; - -void -outb(int port, char val) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - ISA_io[port] = val; -} - -unsigned char -inb(int port) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - return (ISA_io[port]); -} - -unsigned long -local_to_PCI(unsigned long addr) -{ - return ((addr & 0x7FFFFFFF) | 0x80000000); -} - -void -_bcopy(char *src, char *dst, int len) -{ - while (len--) *dst++ = *src++; -} - - -#define FALSE 0 -#define TRUE 1 -#include - -int -strlen(char *s) -{ - int len = 0; - while (*s++) len++; - return len; -} - -_printk(char const *fmt, ...) -{ - int ret; - va_list ap; - - va_start(ap, fmt); - ret = _vprintk(putc, fmt, ap); - va_end(ap); - return (ret); -} - -#define is_digit(c) ((c >= '0') && (c <= '9')) - -int -_vprintk(putc, fmt0, ap) -int (*putc)(); -const char *fmt0; -va_list ap; -{ - char c, sign, *cp; - int left_prec, right_prec, zero_fill, length, pad, pad_on_right; - char buf[32]; - long val; - while (c = *fmt0++) - { - if (c == '%') - { - c = *fmt0++; - left_prec = right_prec = pad_on_right = 0; - if (c == '-') - { - c = *fmt0++; - pad_on_right++; - } - if (c == '0') - { - zero_fill = TRUE; - c = *fmt0++; - } else - { - zero_fill = FALSE; - } - while (is_digit(c)) - { - left_prec = (left_prec * 10) + (c - '0'); - c = *fmt0++; - } - if (c == '.') - { - c = *fmt0++; - zero_fill++; - while (is_digit(c)) - { - right_prec = (right_prec * 10) + (c - '0'); - c = *fmt0++; - } - } else - { - right_prec = left_prec; - } - sign = '\0'; - switch (c) - { - case 'd': - case 'x': - case 'X': - val = va_arg(ap, long); - switch (c) - { - case 'd': - if (val < 0) - { - sign = '-'; - val = -val; - } - length = _cvt(val, buf, 10, "0123456789"); - break; - case 'x': - length = _cvt(val, buf, 16, "0123456789abcdef"); - break; - case 'X': - length = _cvt(val, buf, 16, "0123456789ABCDEF"); - break; - } - cp = buf; - break; - case 's': - cp = va_arg(ap, char *); - length = strlen(cp); - break; - case 'c': - c = va_arg(ap, long /*char*/); - (*putc)(c); - continue; - default: - (*putc)('?'); - } - pad = left_prec - length; - if (sign != '\0') - { - pad--; - } - if (zero_fill) - { - c = '0'; - if (sign != '\0') - { - (*putc)(sign); - sign = '\0'; - } - } else - { - c = ' '; - } - if (!pad_on_right) - { - while (pad-- > 0) - { - (*putc)(c); - } - } - if (sign != '\0') - { - (*putc)(sign); - } - while (length-- > 0) - { - (*putc)(c = *cp++); - if (c == '\n') - { - (*putc)('\r'); - } - } - if (pad_on_right) - { - while (pad-- > 0) - { - (*putc)(c); - } - } - } else - { - (*putc)(c); - if (c == '\n') - { - (*putc)('\r'); - } - } - } -} - -int _cvt(unsigned long val, char *buf, long radix, char *digits) -{ - char temp[80]; - char *cp = temp; - int length = 0; - if (val == 0) - { /* Special case */ - *cp++ = '0'; - } else - while (val) - { - *cp++ = digits[val % radix]; - val /= radix; - } - while (cp != temp) - { - *buf++ = *--cp; - length++; - } - *buf = '\0'; - return (length); -} - -_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) -{ - int i, c; - if ((unsigned int)s > (unsigned int)p) - { - s = (unsigned int)s - (unsigned int)p; - } - while (s > 0) - { - if (base) - { - _printk("%06X: ", (int)p - (int)base); - } else - { - _printk("%06X: ", p); - } - for (i = 0; i < 16; i++) - { - if (i < s) - { - _printk("%02X", p[i] & 0xFF); - } else - { - _printk(" "); - } - if ((i % 2) == 1) _printk(" "); - if ((i % 8) == 7) _printk(" "); - } - _printk(" |"); - for (i = 0; i < 16; i++) - { - if (i < s) - { - c = p[i] & 0xFF; - if ((c < 0x20) || (c >= 0x7F)) c = '.'; - } else - { - c = ' '; - } - _printk("%c", c); - } - _printk("|\n"); - s -= 16; - p += 16; - } -} - -_dump_buf(unsigned char *p, int s) -{ - _printk("\n"); - _dump_buf_with_offset(p, s, 0); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c --- v2.4.4/linux/arch/ppc/boot/mkprep.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/boot/mkprep.c Wed Dec 31 16:00:00 1969 @@ -1,287 +0,0 @@ -/* - * Makes a prep bootable image which can be dd'd onto - * a disk device to make a bootdisk. Will take - * as input a elf executable, strip off the header - * and write out a boot image as: - * 1) default - strips elf header - * suitable as a network boot image - * 2) -pbp - strips elf header and writes out prep boot partition image - * cat or dd onto disk for booting - * 3) -asm - strips elf header and writes out as asm data - * useful for generating data for a compressed image - * -- Cort - * - * Modified for x86 hosted builds by Matt Porter - */ - -#include -#include -#include -#include - -#define cpu_to_le32(x) le32_to_cpu((x)) -unsigned long le32_to_cpu(unsigned long x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - - -#define cpu_to_le16(x) le16_to_cpu((x)) -unsigned short le16_to_cpu(unsigned short x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) - -/* size of read buffer */ -#define SIZE 0x1000 - - -typedef unsigned long dword_t; -typedef unsigned short word_t; -typedef unsigned char byte_t; -typedef byte_t block_t[512]; -typedef byte_t page_t[4096]; - - -/* - * Partition table entry - * - from the PReP spec - */ -typedef struct partition_entry { - byte_t boot_indicator; - byte_t starting_head; - byte_t starting_sector; - byte_t starting_cylinder; - - byte_t system_indicator; - byte_t ending_head; - byte_t ending_sector; - byte_t ending_cylinder; - - dword_t beginning_sector; - dword_t number_of_sectors; -} partition_entry_t; - -#define BootActive 0x80 -#define SystemPrep 0x41 - -void copy_image(int , int); -void write_prep_partition(int , int ); -void write_asm_data( int in, int out ); - -unsigned int elfhdr_size = 65536; - -int main(int argc, char *argv[]) -{ - int in_fd, out_fd; - int argptr = 1; - unsigned int prep = 0; - unsigned int asmoutput = 0; - - if ( (argc < 3) || (argc > 4) ) - { - fprintf(stderr, "usage: %s [-pbp] [-asm] \n",argv[0]); - exit(-1); - } - - /* needs to handle args more elegantly -- but this is a small/simple program */ - - /* check for -pbp */ - if ( !strcmp( argv[argptr], "-pbp" ) ) - { - prep = 1; - argptr++; - } - - /* check for -asm */ - if ( !strcmp( argv[argptr], "-asm" ) ) - { - asmoutput = 1; - argptr++; - } - - /* input file */ - if ( !strcmp( argv[argptr], "-" ) ) - in_fd = 0; /* stdin */ - else - if ((in_fd = open( argv[argptr] , 0)) < 0) - exit(-1); - argptr++; - - /* output file */ - if ( !strcmp( argv[argptr], "-" ) ) - out_fd = 1; /* stdout */ - else - if ((out_fd = creat( argv[argptr] , 0755)) < 0) - exit(-1); - argptr++; - - /* skip elf header in input file */ - /*if ( !prep )*/ - lseek(in_fd, elfhdr_size, SEEK_SET); - - /* write prep partition if necessary */ - if ( prep ) - write_prep_partition( in_fd, out_fd ); - - /* write input image to bootimage */ - if ( asmoutput ) - write_asm_data( in_fd, out_fd ); - else - copy_image(in_fd, out_fd); - - return 0; -} - -void write_prep_partition(int in, int out) -{ - unsigned char block[512]; - partition_entry_t *pe = (partition_entry_t *)&block[0x1BE]; - dword_t *entry = (dword_t *)&block[0]; - dword_t *length = (dword_t *)&block[sizeof(long)]; - struct stat info; - - if (fstat(in, &info) < 0) - { - fprintf(stderr,"info failed\n"); - exit(-1); - } - - bzero( block, sizeof block ); - - /* set entry point and boot image size skipping over elf header */ -#ifdef __i386__ - *entry = 0x400/*+65536*/; - *length = info.st_size-elfhdr_size+0x400; -#else - *entry = cpu_to_le32(0x400/*+65536*/); - *length = cpu_to_le32(info.st_size-elfhdr_size+0x400); -#endif /* __i386__ */ - - /* sets magic number for msdos partition (used by linux) */ - block[510] = 0x55; - block[511] = 0xAA; - - /* - * Build a "PReP" partition table entry in the boot record - * - "PReP" may only look at the system_indicator - */ - pe->boot_indicator = BootActive; - pe->system_indicator = SystemPrep; - /* - * The first block of the diskette is used by this "boot record" which - * actually contains the partition table. (The first block of the - * partition contains the boot image, but I digress...) We'll set up - * one partition on the diskette and it shall contain the rest of the - * diskette. - */ - pe->starting_head = 0; /* zero-based */ - pe->starting_sector = 2; /* one-based */ - pe->starting_cylinder = 0; /* zero-based */ - pe->ending_head = 1; /* assumes two heads */ - pe->ending_sector = 18; /* assumes 18 sectors/track */ - pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */ - - /* - * The "PReP" software ignores the above fields and just looks at - * the next two. - * - size of the diskette is (assumed to be) - * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette) - * - unlike the above sector numbers, the beginning sector is zero-based! - */ -#if 0 - pe->beginning_sector = cpu_to_le32(1); -#else - /* This has to be 0 on the PowerStack? */ -#ifdef __i386__ - pe->beginning_sector = 0; -#else - pe->beginning_sector = cpu_to_le32(0); -#endif /* __i386__ */ -#endif - -#ifdef __i386__ - pe->number_of_sectors = 2*18*80-1; -#else - pe->number_of_sectors = cpu_to_le32(2*18*80-1); -#endif /* __i386__ */ - - write( out, block, sizeof(block) ); - write( out, entry, sizeof(*entry) ); - write( out, length, sizeof(*length) ); - /* set file position to 2nd sector where image will be written */ - lseek( out, 0x400, SEEK_SET ); -} - - - -void -copy_image(int in, int out) -{ - char buf[SIZE]; - int n; - - while ( (n = read(in, buf, SIZE)) > 0 ) - write(out, buf, n); -} - - -void -write_asm_data( int in, int out ) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[SIZE]; - unsigned char str[256]; - - write( out, "\t.data\n\t.globl input_data\ninput_data:\n", - strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) ); - pos = 0; - cksum = 0; - while ((len = read(in, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - write( out, "\t.long\t", strlen( "\t.long\t" ) ); - } - sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - write( out, str, strlen(str) ); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - sprintf( str, " # %x \n", pos+i-12); - write( out, str, strlen(str) ); - } else - { - write( out, ",", 1 ); - } - } - if (cnt) - { - write( out, "0\n", 2 ); - } - pos += len; - } - sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos); - write( out, str, strlen(str) ); - - fprintf(stderr, "cksum = %x\n", cksum); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/ns16550.c linux/arch/ppc/boot/ns16550.c --- v2.4.4/linux/arch/ppc/boot/ns16550.c Thu Jan 7 12:06:57 1999 +++ linux/arch/ppc/boot/ns16550.c Wed Dec 31 16:00:00 1969 @@ -1,56 +0,0 @@ -/* - * COM1 NS16550 support - */ - -#include "ns16550.h" -typedef struct NS16550 *NS16550_t; - -const NS16550_t COM_PORTS[] = { (NS16550_t) COM1, - (NS16550_t) COM2, - (NS16550_t) COM3, - (NS16550_t) COM4 }; - -volatile struct NS16550 * -NS16550_init(int chan) -{ - volatile struct NS16550 *com_port; - volatile unsigned char xx; - com_port = (struct NS16550 *) COM_PORTS[chan]; - /* See if port is present */ - com_port->lcr = 0x00; - com_port->ier = 0xFF; -#if 0 - if (com_port->ier != 0x0F) return ((struct NS16550 *)0); -#endif - com_port->ier = 0x00; - com_port->lcr = 0x80; /* Access baud rate */ - com_port->dll = 0xc; /* 9600 baud */ - com_port->dlm = 0xc >> 8; - com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */ - com_port->mcr = 0x03; /* RTS/DTR */ - com_port->fcr = 0x07; /* Clear & enable FIFOs */ - return (com_port); -} - - -NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) -{ - volatile int i; - while ((com_port->lsr & LSR_THRE) == 0) ; - com_port->thr = c; -} - -unsigned char -NS16550_getc(volatile struct NS16550 *com_port) -{ - while ((com_port->lsr & LSR_DR) == 0) ; - return (com_port->rbr); -} - -NS16550_tstc(volatile struct NS16550 *com_port) -{ - return ((com_port->lsr & LSR_DR) != 0); -} - - - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/ns16550.h linux/arch/ppc/boot/ns16550.h --- v2.4.4/linux/arch/ppc/boot/ns16550.h Thu Jan 7 12:06:57 1999 +++ linux/arch/ppc/boot/ns16550.h Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ -/* - * NS16550 Serial Port - */ - -struct NS16550 - { - unsigned char rbr; /* 0 */ - unsigned char ier; /* 1 */ - unsigned char fcr; /* 2 */ - unsigned char lcr; /* 3 */ - unsigned char mcr; /* 4 */ - unsigned char lsr; /* 5 */ - unsigned char msr; /* 6 */ - unsigned char scr; /* 7 */ - }; - -#define thr rbr -#define iir fcr -#define dll rbr -#define dlm ier - -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit holding register empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -#define COM1 0x800003F8 -#define COM2 0x800002F8 -#define COM3 0x800003F8 -#define COM4 0x80000388 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/of1275.c linux/arch/ppc/boot/of1275.c --- v2.4.4/linux/arch/ppc/boot/of1275.c Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/boot/of1275.c Wed Dec 31 16:00:00 1969 @@ -1,427 +0,0 @@ -/* Open Firmware Client Interface */ - - -#include "of1275.h" - - -static int (*of_server)(void *) = (int(*)(void*))-1; - -void -of_init(void *handler) -{ - of_server = (int(*)(void*))handler; -} - - -/* 6.3.2.1 Client interface */ - - -int -of_test(const char *name, int *missing) -{ - int result; - static of_test_service s; - s.service = "test"; - s.n_args = 1; - s.n_returns = 1; - s.name = name; - result = of_server(&s); - *missing = s.missing; - return result; -} - - -/* 6.3.2.2 Device tree */ - - -int -of_peer(int phandle, int *sibling_phandle) -{ - int result; - static of_peer_service s; - s.service = "peer"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *sibling_phandle = s.sibling_phandle; - return result; -} - -int -of_child(int phandle, int *child_phandle) -{ - int result; - static of_child_service s; - s.service = "child"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *child_phandle = s.child_phandle; - return result; -} - -int -of_parent(int phandle, int *parent_phandle) -{ - int result; - static of_parent_service s; - s.service = "parent"; - s.n_args = 1; - s.n_returns = 1; - s.phandle = phandle; - result = of_server(&s); - *parent_phandle = s.parent_phandle; - return result; -} - -int -of_instance_to_package(int ihandle, int *phandle) -{ - int result; - static of_instance_to_package_service s; - s.service = "instance-to-package"; - s.n_args = 1; - s.n_returns = 1; - s.ihandle = ihandle; - result = of_server(&s); - *phandle = s.phandle; - return result; -} - -int -of_getproplen(int phandle, const char *name, int *proplen) -{ - int result; - static of_getproplen_service s; - s.service = "getproplen"; - s.n_args = 2; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - result = of_server(&s); - *proplen = s.proplen; - return result; -} - -int -of_getprop(int phandle, const char *name, void *buf, int buflen, int *size) -{ - int result; - static of_getprop_service s; - s.service = "getprop"; - s.n_args = 4; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *size = s.size; - return result; -} - -int -of_nextprop(int phandle, const char *previous, void *buf, int *flag) -{ - int result; - static of_nextprop_service s; - s.service = "nextprop"; - s.n_args = 3; - s.n_returns = 1; - s.phandle = phandle; - s.previous = previous; - s.buf = buf; - result = of_server(&s); - *flag = s.flag; - return result; -} - -int -of_setprop(int phandle, const char *name, void *buf, int len, int *size) -{ - int result; - static of_setprop_service s; - s.service = "setprop"; - s.n_args = 4; - s.n_returns = 1; - s.phandle = phandle; - s.name = name; - s.buf = buf; - s.len = len; - result = of_server(&s); - *size = s.size; - return result; -} - -int -of_canon(const char *device_specifier, void *buf, int buflen, int *length) -{ - int result; - static of_canon_service s; - s.service = "canon"; - s.n_args = 3; - s.n_returns = 1; - s.device_specifier = device_specifier; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -int -of_finddevice(const char *device_specifier, int *phandle) -{ - int result; - static of_finddevice_service s; - s.service = "finddevice"; - s.n_args = 1; - s.n_returns = 1; - s.device_specifier = device_specifier; - result = of_server(&s); - *phandle = s.phandle; - return result; -} - -int -of_instance_to_path(int ihandle, void *buf, int buflen, int *length) -{ - int result; - static of_instance_to_path_service s; - s.service = "instance-to-path"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -int -of_package_to_path(int phandle, void *buf, int buflen, int *length) -{ - int result; - static of_package_to_path_service s; - s.service = "package-to-path"; - s.n_args = 3; - s.n_returns = 1; - s.phandle = phandle; - s.buf = buf; - s.buflen = buflen; - result = of_server(&s); - *length = s.length; - return result; -} - -/* int of_call_method(const char *method, int ihandle, ...); */ - - -/* 6.3.2.3 Device I/O */ - - -int -of_open(const char *device_specifier, int *ihandle) -{ - int result; - static of_open_service s; - s.service = "open"; - s.n_args = 1; - s.n_returns = 1; - s.device_specifier = device_specifier; - result = of_server(&s); - *ihandle = s.ihandle; - return result; -} - -int -of_close(int ihandle) -{ - int result; - static of_close_service s; - s.service = "close"; - s.n_args = 1; - s.n_returns = 0; - s.ihandle = ihandle; - result = of_server(&s); - return result; -} - -int -of_read(int ihandle, void *addr, int len, int *actual) -{ - int result; - static of_read_service s; - s.service = "read"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.addr = addr; - s.len = len; - result = of_server(&s); - *actual = s.actual; - return result; -} - -int -of_write(int ihandle, void *addr, int len, int *actual) -{ - int result; - static of_write_service s; - s.service = "write"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.addr = addr; - s.len = len; - result = of_server(&s); - *actual = s.actual; - return result; -} - -int -of_seek(int ihandle, int pos_hi, int pos_lo, int *status) -{ - int result; - static of_seek_service s; - s.service = "seek"; - s.n_args = 3; - s.n_returns = 1; - s.ihandle = ihandle; - s.pos_hi = pos_hi; - s.pos_lo = pos_lo; - result = of_server(&s); - *status = s.status; - return result; -} - - -/* 6.3.2.4 Memory */ - - -int -of_claim(void *virt, int size, int align, void **baseaddr) -{ - int result; - static of_claim_service s; - s.service = "claim"; - s.n_args = 3; - s.n_returns = 1; - s.virt = virt; - s.size = size; - s.align = align; - result = of_server(&s); - *baseaddr = s.baseaddr; - return result; -} - -int -of_release(void *virt, int size) -{ - int result; - static of_release_service s; - s.service = "release"; - s.n_args = 2; - s.n_returns = 0; - s.virt = virt; - s.size = size; - result = of_server(&s); - return result; -} - - -/* 6.3.2.5 Control transfer */ - - -int -of_boot(const char *bootspec) -{ - int result; - static of_boot_service s; - s.service = "boot"; - s.n_args = 1; - s.n_returns = 0; - s.bootspec = bootspec; - result = of_server(&s); - return result; -} - -int -of_enter(void) -{ - int result; - static of_enter_service s; - s.service = "enter"; - s.n_args = 0; - s.n_returns = 0; - result = of_server(&s); - return result; -} - -int -of_exit(void) -{ - int result; - static of_exit_service s; - s.service = "exit"; - s.n_args = 0; - s.n_returns = 0; - result = of_server(&s); - return result; -} - -/* int of_chain(void *virt, int size, void *entry, void *args, int len); */ - - -/* 6.3.2.6 User interface */ - - -/* int of_interpret(const char *arg, ...); */ - -int -of_set_callback(void *newfunc, void **oldfunc) -{ - int result; - static of_set_callback_service s; - s.service = "set-callback"; - s.n_args = 1; - s.n_returns = 1; - s.newfunc = newfunc; - result = of_server(&s); - *oldfunc = s.oldfunc; - return result; -} - -int -of_set_symbol_lookup(void *sym_to_value, void *value_to_sym) -{ - int result; - static of_set_symbol_lookup_service s; - s.service = "set-symbol-lookup"; - s.n_args = 2; - s.n_returns = 0; - s.sym_to_value = sym_to_value; - s.value_to_sym = s.value_to_sym; - result = of_server(&s); - return result; -} - - -/* 6.3.2.7 Time */ - - -int -of_milliseconds(int *ms) -{ - int result; - static of_milliseconds_service s; - s.service = "milliseconds"; - s.n_args = 0; - s.n_returns = 1; - result = of_server(&s); - *ms = s.ms; - return result; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/of1275.h linux/arch/ppc/boot/of1275.h --- v2.4.4/linux/arch/ppc/boot/of1275.h Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/boot/of1275.h Wed Dec 31 16:00:00 1969 @@ -1,421 +0,0 @@ -/* 6.3.2.1 Client interface */ - - -typedef struct _of_test_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *name; - /*out*/ - int missing; -} of_test_service; - -int of_test(const char *name, int *missing); - - -/* 6.3.2.2 Device tree */ - - -typedef struct _of_peer_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int sibling_phandle; -} of_peer_service; - -int of_peer(int phandle, int *sibling_phandle); - - -typedef struct _of_child_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int child_phandle; -} of_child_service; - -int of_child(int phandle, int *child_phandle); - - -typedef struct _of_parent_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - /*out*/ - int parent_phandle; -} of_parent_service; - -int of_child(int phandle, int *parent_phandle); - - -typedef struct _of_instance_to_package_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - /*out*/ - int phandle; -} of_instance_to_package_service; - -int of_instance_to_package(int ihandle, int *phandle); - - -typedef struct _of_getproplen_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - /*out*/ - int proplen; -} of_getproplen_service; - -int of_getproplen(int phandle, const char *name, int *proplen); - - -typedef struct _of_getprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - void *buf; - int buflen; - /*out*/ - int size; -} of_getprop_service; - -int of_getprop(int phandle, const char *name, void *buf, int buflen, - int *size); - - -typedef struct _of_nextprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *previous; - void *buf; - /*out*/ - int flag; -} of_nextprop_service; - -int of_nextprop(int phandle, const char *previous, void *buf, int *flag); - - -typedef struct _of_setprop_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - const char *name; - void *buf; - int len; - /*out*/ - int size; -} of_setprop_service; - -int of_setprop(int phandle, const char *name, void *buf, int len, int *size); - - -typedef struct _of_canon_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - void *buf; - int buflen; - /*out*/ - int length; -} of_canon_service; - -int of_canon(const char *device_specifier, void *buf, int buflen, int *length); - - -typedef struct _of_finddevice_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - /*out*/ - int phandle; -} of_finddevice_service; - -int of_finddevice(const char *device_specifier, int *phandle); - - -typedef struct _of_instance_to_path_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *buf; - int buflen; - /*out*/ - int length; -} of_instance_to_path_service; - -int of_instance_to_path(int ihandle, void *buf, int buflen, int *length); - - -typedef struct _of_package_to_path_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int phandle; - void *buf; - int buflen; - /*out*/ - int length; -} of_package_to_path_service; - -int of_package_to_path(int phandle, void *buf, int buflen, int *length); - - -typedef struct _of_call_method_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *method; - int ihandle; - /*...*/ - int args[0]; -} of_call_method_service; - -int of_call_method(const char *method, int ihandle, ...); - - -/* 6.3.2.3 Device I/O */ - - -typedef struct _of_open_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *device_specifier; - /*out*/ - int ihandle; -} of_open_service; - -int of_open(const char *device_specifier, - int *ihandle); - - -typedef struct _of_close_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - /*out*/ -} of_close_service; - -int of_close(int ihandle); - - -typedef struct _of_read_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *addr; - int len; - /*out*/ - int actual; -} of_read_service; - -int of_read(int ihandle, void *addr, int len, int *actual); - - -typedef struct _of_write_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - void *addr; - int len; - /*out*/ - int actual; -} of_write_service; - -int of_write(int ihandle, void *addr, int len, int *actual); - - -typedef struct _of_seek_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - int ihandle; - int pos_hi; - int pos_lo; - /*out*/ - int status; -} of_seek_service; - -int of_seek(int ihandle, int pos_hi, int pos_lo, int *status); - - -/* 6.3.2.4 Memory */ - - -typedef struct _of_claim_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - int align; - /*out*/ - void *baseaddr; -} of_claim_service; - -int of_claim(void *virt, int size, int align, void **baseaddr); - - -typedef struct _of_release_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - int align; - /*out*/ -} of_release_service; - -int of_release(void *virt, int size); - - -/* 6.3.2.5 Control transfer */ - - -typedef struct _of_boot_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *bootspec; - /*out*/ -} of_boot_service; - -int of_boot(const char *bootspec); - - -typedef struct _of_enter_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ -} of_enter_service; - -int of_enter(void); - - -typedef struct _of_exit_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ -} of_exit_service; - -int of_exit(void); - - -typedef struct _of_chain_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *virt; - int size; - void *entry; - void *args; - int len; - /*out*/ -} of_chain_service; - -int of_chain(void *virt, int size, void *entry, void *args, int len); - - -/* 6.3.2.6 User interface */ - - -typedef struct _of_interpret_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - const char *cmd; - int args[0]; - /*...*/ - /*out*/ - /*...*/ -} of_interpret_service; - -int of_interpret(const char *arg, ...); - - -typedef struct _of_set_callback_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *newfunc; - /*out*/ - void *oldfunc; -} of_set_callback_service; - -int of_set_callback(void *newfunc, void **oldfunc); - - -typedef struct _of_set_symbol_lookup_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - void *sym_to_value; - void *value_to_sym; - /*out*/ -} of_set_symbol_lookup_service; - -int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym); - - -/* 6.3.2.7 Time */ - - -typedef struct _of_milliseconds_service { - const char *service; - int n_args; - int n_returns; - /*in*/ - /*out*/ - int ms; -} of_milliseconds_service; - -int of_milliseconds(int *ms); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/offset linux/arch/ppc/boot/offset --- v2.4.4/linux/arch/ppc/boot/offset Wed Sep 30 10:14:16 1998 +++ linux/arch/ppc/boot/offset Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` -echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/Makefile linux/arch/ppc/boot/pmac/Makefile --- v2.4.4/linux/arch/ppc/boot/pmac/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/Makefile Thu May 24 15:02:07 2001 @@ -0,0 +1,115 @@ +# BK Id: SCCS/s.Makefile 1.8 05/21/01 09:10:38 trini +# +# Makefile for making XCOFF bootable images for booting on PowerMacs +# using Open Firmware. +# +# Paul Mackerras January 1997 +# +# Cleaned up, moved into arch/ppc/boot/pmac +# Tom Rini January 2001 + +OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment +COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic +CHRP_LD_ARGS = -Ttext 0x01000000 + +COMMONOBJS = start.o misc.o ../common/string.o image.o +COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o +CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o +LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a + +MKNOTE := ../utils/mknote +SIZE := ../utils/size +OFFSET := ../utils/offset +PIGGYBACK := ../utils/piggyback +HACKCOFF := ../utils/hack-coff + +ifeq ($(CONFIG_PPC64BRIDGE),y) +MSIZE=.64 +else +MSIZE= +endif + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) +else +TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) +endif + +../common/crt0.o: + $(MAKE) -C ../common crt0.o + +../common/coffcrt0.o: + $(MAKE) -C ../common coffcrt0.o + +chrpmain.o: chrpmain.c + $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c + +znetboot: vmlinux.coff vmlinux.elf-pmac zImage + cp ../images/vmlinux.coff $(TFTPIMAGE) + cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).elf + +znetboot.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac + cp ../images/vmlinux.coff.initrd $(TFTPIMAGE) + cp ../images/vmlinux.elf-pmac.initrd $(TFTPIMAGE).elf + +#floppy: zImage +# mount -t hfs /dev/fd0 /mnt +# cp vmlinux.coff /mnt +# umount /mnt + +miboot.image: dummy.o ../images/vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ + dummy.o ../images/$@ + +miboot.image.initrd: miboot.image ../images/ramdisk.image.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \ + ../images/miboot.image ../images/$@ + +coffboot: $(COFFOBJS) $(LIBS) ../common/no_initrd.o ld.script ../images/vmlinux.gz + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) ../common/no_initrd.o $(LIBS) + +coffboot.initrd: $(COFFOBJS) $(LIBS) initrd.o ld.script ../images/vmlinux.gz + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) + +image.o: $(PIGGYBACK) ../images/vmlinux.gz + $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ + +initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) + $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ + +vmlinux.coff: coffboot $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot + ln -sf vmlinux.coff ../images/zImage.pmac + +vmlinux.coff.initrd: coffboot.initrd $(HACKCOFF) + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ + $(HACKCOFF) ../images/$@ + rm -f coffboot.initrd + ln -sf vmlinux.coff.initrd ../images/zImage.initrd.pmac + +vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) ../common/no_initrd.o $(MKNOTE) ../images/vmlinux.gz + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) + $(MKNOTE) > note + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ + --add-section=sysmap=$(TOPDIR)/System.map -R .comment + $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ + -DSYSMAP_OFFSET=`sh $(OFFSET) $(OBJDUMP) ../images/$@ sysmap` \ + -DSYSMAP_SIZE=`sh $(SIZE) $(OBJDUMP) ../images/$@ sysmap` + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ + --add-section=sysmap=$(TOPDIR)/System.map -R .comment + rm -f note + +vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) initrd.o $(MKNOTE) ../images/vmlinux.gz + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) initrd.o $(LIBS) + $(MKNOTE) > note + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note -R .comment + rm -f note + +zImage: vmlinux.coff vmlinux.elf-pmac miboot.image + +zImage.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac miboot.image.initrd + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/chrpmain.c linux/arch/ppc/boot/pmac/chrpmain.c --- v2.4.4/linux/arch/ppc/boot/pmac/chrpmain.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/chrpmain.c Thu May 24 15:02:07 2001 @@ -0,0 +1,312 @@ +/* + * BK Id: SCCS/s.chrpmain.c 1.9 05/18/01 06:20:29 patch + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include "nonstdio.h" +#include "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern void *claim(unsigned int, unsigned int, unsigned int); +extern void release(void *ptr, unsigned int len); +void make_bi_recs(unsigned long); +void gunzip(void *, int, unsigned char *, int *); +void stop_imac_ethernet(void); +void stop_imac_usb(void); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_END (16 << 20) + +#define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + extern char _start; + + printf("chrpboot starting: loaded at 0x%x\n", &_start); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start, + initrd_data,initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + make_bi_recs((unsigned long) dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + +#ifdef SYSMAP_OFFSET + rec->tag = BI_SYSMAP; + rec->data[0] = SYSMAP_OFFSET; + rec->data[1] = SYSMAP_SIZE; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif /* SYSMAP_OFFSET */ + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +#if 0 +#define eieio() asm volatile("eieio"); + +void stop_imac_ethernet(void) +{ + void *macio, *enet; + unsigned int macio_addr[5], enet_reg[6]; + int len; + volatile unsigned int *dbdma; + + macio = finddevice("/pci/mac-io"); + enet = finddevice("/pci/mac-io/ethernet"); + if (macio == NULL || enet == NULL) + return; + len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr)); + if (len != sizeof(macio_addr)) + return; + len = getprop(enet, "reg", enet_reg, sizeof(enet_reg)); + if (len != sizeof(enet_reg)) + return; + printf("macio base %x, dma at %x & %x\n", + macio_addr[2], enet_reg[2], enet_reg[4]); + + /* hope this is mapped... */ + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); +} + +void stop_imac_usb(void) +{ + void *usb; + unsigned int usb_addr[5]; + int len; + volatile unsigned int *usb_ctrl; + + usb = finddevice("/pci/usb"); + if (usb == NULL) + return; + len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr)); + if (len != sizeof(usb_addr)) + return; + printf("usb base %x\n", usb_addr[2]); + + usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8); + *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ + eieio(); +} +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/coffmain.c linux/arch/ppc/boot/pmac/coffmain.c --- v2.4.4/linux/arch/ppc/boot/pmac/coffmain.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/coffmain.c Thu May 24 15:02:07 2001 @@ -0,0 +1,249 @@ +/* + * BK Id: SCCS/s.coffmain.c 1.9 05/18/01 06:20:29 patch + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include "nonstdio.h" +#include "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern char *claim(unsigned, unsigned, unsigned); +void make_bi_recs(unsigned long); +void gunzip(void *, int, unsigned char *, int *); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_START 0xc0000000 +#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ + +#define PROG_START RAM_START +#define PROG_SIZE 0x00400000 + +#define SCRATCH_SIZE (128 << 10) + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; + +extern char _start[], _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + +char heap[SCRATCH_SIZE]; + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("coffboot starting: loaded at 0x%x\n", _start); + setup_bats(RAM_START); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at 0 */ + claim(0, PROG_SIZE, 0); + dst = (void *) RAM_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + begin_avail = avail_high = avail_ram = heap; + end_avail = heap + sizeof(heap); + printf("heap at 0x%x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + make_bi_recs((unsigned long)dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); +#if 0 + if (addr >= PROG_START + PROG_SIZE) + claim(addr, 0x1000, 0); +#endif + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/dummy.c linux/arch/ppc/boot/pmac/dummy.c --- v2.4.4/linux/arch/ppc/boot/pmac/dummy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/dummy.c Thu May 24 15:02:07 2001 @@ -0,0 +1,7 @@ +/* + * BK Id: SCCS/s.dummy.c 1.6 05/18/01 15:17:15 cort + */ +int main(void) +{ + return 0; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/ld.script linux/arch/ppc/boot/pmac/ld.script --- v2.4.4/linux/arch/ppc/boot/pmac/ld.script Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/ld.script Thu May 24 15:02:07 2001 @@ -0,0 +1,68 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.rodata) + *(.rodata1) + *(.got1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _etext = .; + PROVIDE (etext = .); + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/misc.S linux/arch/ppc/boot/pmac/misc.S --- v2.4.4/linux/arch/ppc/boot/pmac/misc.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/misc.S Thu May 24 15:02:07 2001 @@ -0,0 +1,60 @@ +/* + * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + +/* + * Use the BAT3 registers to map the 1st 8MB of RAM to + * the address given as the 1st argument. + */ + .globl setup_bats +setup_bats: + mfpvr 5 + rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,5,1 + li 0,0 + bne 4f + mtibatl 3,0 /* invalidate BAT first */ + ori 3,3,4 /* set up BAT registers for 601 */ + li 4,0x7f + mtibatu 3,3 + mtibatl 3,4 + b 5f +4: mtdbatu 3,0 /* invalidate BATs first */ + mtibatu 3,0 + ori 3,3,0xff /* set up BAT registers for 604 */ + li 4,2 + mtdbatl 3,4 + mtdbatu 3,3 + mtibatl 3,4 + mtibatu 3,3 +5: sync + isync + blr + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/pmac/start.c linux/arch/ppc/boot/pmac/start.c --- v2.4.4/linux/arch/ppc/boot/pmac/start.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/pmac/start.c Thu May 24 15:02:07 2001 @@ -0,0 +1,343 @@ +/* + * BK Id: SCCS/s.start.c 1.8 05/18/01 15:17:15 cort + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include + +int (*prom)(); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + +void exit(void); +void *finddevice(const char *name); +int getprop(void *phandle, const char *name, void *buf, int buflen); +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + prom = (int (*)()) promptr; + chosen_handle = finddevice("/chosen"); + if (chosen_handle == (void *) -1) + exit(); + if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) + exit(); + stderr = stdout; + if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) + exit(); + + boot(a1, a2, promptr); + for (;;) + exit(); +} + +int +write(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +int writestring(void *f, char *ptr, int nb) +{ + int w = 0, i; + char *ret = "\r"; + + for (i = 0; i < nb; ++i) { + if (ptr[i] == '\n') { + if (i > w) { + write(f, ptr + w, i - w); + w = i; + } + write(f, ret, 1); + } + } + if (w < nb) + write(f, ptr + w, nb - w); + return nb; +} + +int +read(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +void +exit() +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom)(&args); + } +} + +void +pause() +{ + struct prom_args { + char *service; + } args; + + args.service = "enter"; + (*prom)(&args); +} + +void * +finddevice(const char *name) +{ + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + void *phandle; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.phandle = (void *) -1; + (*prom)(&args); + return args.phandle; +} + +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +void +release(void *virt, unsigned int size) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *virt; + unsigned int size; + } args; + + args.service = "release"; + args.nargs = 2; + args.nret = 0; + args.virt = virt; + args.size = size; + (*prom)(&args); +} + +int +getprop(void *phandle, const char *name, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *phandle; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.phandle = phandle; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*prom)(&args); + return args.size; +} + +int +putc(int c, void *f) +{ + char ch = c; + + return writestring(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return writestring(f, str, n) == n? 0: -1; +} + +int +readchar() +{ + char ch; + + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\n"); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int +getchar() +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +extern int vsprintf(char *buf, const char *fmt, va_list args); +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); + return n; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/Makefile linux/arch/ppc/boot/prep/Makefile --- v2.4.4/linux/arch/ppc/boot/prep/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/Makefile Thu May 24 15:02:07 2001 @@ -0,0 +1,114 @@ +# BK Id: SCCS/s.Makefile 1.15 05/21/01 11:51:32 trini +# +# arch/ppc/boot/Makefile +# +# 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. +# +# Tom Rini January 2001 +# +# Originally: +# arch/ppc/boot/Makefile +# Copyright (C) 1994 by Linus Torvalds +# Adapted for PowerPC by Gary Thomas +# modified by Cort (cort@cs.nmt.edu) +# + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.S.s: + $(CPP) $(AFLAGS) -traditional -o $*.o $< +.S.o: + $(CC) $(AFLAGS) -traditional -c -o $*.o $< + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.prep.smp +else +TFTPIMAGE=/tftpboot/zImage.prep +endif + +ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 +OBJECTS := head.o misc.o vreset.o kbd.o ../common/misc-common.o \ + ../common/string.o of1275.o +OBJCOPY_ARGS = -O elf32-powerpc +LIBS = ../lib/zlib.a + +ifeq ($(CONFIG_SERIAL_CONSOLE),y) +OBJECTS += ns16550.o +endif + +# Tools +MKPREP := ../utils/mkprep +SIZE := ../utils/size +OFFSET := ../utils/offset + +all: zImage + +misc.o: misc.c + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ + -DZIMAGE_SIZE=0 -c -o $@ $*.c + +ns16550.o: ../common/ns16550.c + $(CC) $(CFLAGS) -DIOOFFSET=0x80000000 -c -o $@ ../common/$*.c + +zvmlinux.initrd: zvmlinux ../images/vmlinux.gz + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ + -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=../images/ramdisk.image.gz \ + --add-section=image=../images/vmlinux.gz \ + $@.tmp $@ + rm -f $@.tmp zvmlinux + +zImage: zvmlinux $(MKPREP) + $(MKPREP) -pbp zvmlinux ../images/$@.prep + rm -f zvmlinux + +zImage.initrd: zvmlinux.initrd $(MKPREP) + $(MKPREP) -pbp zvmlinux.initrd ../images/$@.prep + rm -f zvmlinux.initrd + +zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz zvmlinux.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) zvmlinux image` \ + -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) zvmlinux image` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=image=../images/vmlinux.gz $@.tmp $@ + rm $@.tmp + +floppy: zImage + dd if=../images/zImage.prep of=/dev/fd0H1440 bs=64b + +znetboot : zImage + cp ../images/zImage.prep $(TFTPIMAGE) + +znetboot.initrd : zImage.initrd + cp ../images/zImage.initrd.prep $(TFTPIMAGE) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/head.S linux/arch/ppc/boot/prep/head.S --- v2.4.4/linux/arch/ppc/boot/prep/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/head.S Thu May 24 15:02:07 2001 @@ -0,0 +1,248 @@ +/* + * BK Id: SCCS/s.head.S 1.8 05/18/01 06:20:29 patch + */ +#include "../../kernel/ppc_defs.h" +#include "../../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * Boot loader philosophy: + * ROM loads us to some arbitrary location + * Move the boot code to the link address (8M) + * Call decompress_kernel() + * Relocate the initrd, zimage and residual data to 8M + * Decompress the kernel to 0 + * Jump to the kernel entry + * -- Cort + */ + .globl start +start: + bl start_ +start_: + mr r11,r3 /* Save pointer to residual/board data */ + mr r25,r5 /* Save OFW pointer */ + li r3,MSR_IP /* Establish default MSR value */ + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + bne 1010f +/* compute size of whole image in words. this should be moved to + * start_ldr() -- Cort + */ + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* round up */ + sub r5,r5,r4 + srwi r5,r5,2 + mr r7,r5 + b start_ldr +1010: +/* + * no matter where we're loaded, move ourselves to -Ttext address + */ +relocate: + mflr r3 /* Compute code bias */ + subi r3,r3,4 + mr r8,r3 + lis r4,start@h + ori r4,r4,start@l + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr +start_ldr: +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 +/* Run loader */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + mr r7,r25 /* OFW interfaces */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + cmpi 0,r2,0 + bne 00b + + /* r4,r5 have initrd_start, size */ + lis r2,initrd_start@h + ori r2,r2,initrd_start@l + lwz r4,0(r2) + lis r2,initrd_end@h + ori r2,r2,initrd_end@l + lwz r5,0(r2) + + + /* tell kernel we're prep */ + /* + * get start address of kernel code which is stored as a coff + * entry. see boot/head.S -- Cort + */ + li r9,0x4 + mtlr r9 + lis r10,0xdeadc0de@h + ori r10,r10,0xdeadc0de@l + li r9,0 + stw r10,0(r9) +/* + * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 + * so disable BATs before setting this to avoid a clash + */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT1U,r8 + mtspr DBAT2U,r8 + mtspr DBAT3U,r8 + mtspr IBAT0U,r8 + mtspr IBAT1U,r8 + mtspr IBAT2U,r8 + mtspr IBAT3U,r8 + + blr +hang: + b hang + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,1 /* 601 ? */ + bne .udelay_not_601 +00: li r0,86 /* Instructions / microsecond? */ + mtctr r0 +10: addi r0,r0,0 /* NOP */ + bdnz 10b + subic. r3,r3,1 + bne 00b + blr + +.udelay_not_601: + mulli r4,r3,1000 /* nanoseconds */ + addi r4,r4,59 + li r5,60 + divw r4,r4,r5 /* BUS ticks */ +1: mftbu r5 + mftb r6 + mftbu r7 + cmp 0,r5,r7 + bne 1b /* Get [synced] base time */ + addc r9,r6,r4 /* Compute end time */ + addze r8,r5 +2: mftbu r5 + cmp 0,r5,r8 + blt 2b + bgt 3f + mftb r6 + cmp 0,r6,r9 + blt 2b +3: blr + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mfspr r3,HID0 /* Caches are controlled by this register */ + li r4,0 + ori r4,r4,(HID0_ICE|HID0_ICFI) + or r3,r3,r4 /* Need to enable+invalidate to clear */ + mtspr HID0,r3 + andc r3,r3,r4 + ori r3,r3,HID0_ICE /* Enable cache */ + mtspr HID0,r3 + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/iso_font.h linux/arch/ppc/boot/prep/iso_font.h --- v2.4.4/linux/arch/ppc/boot/prep/iso_font.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/iso_font.h Thu May 24 15:02:07 2001 @@ -0,0 +1,260 @@ +/* + * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort + */ +static const unsigned char font[] = { +/* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, +/* 0x02 */ 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00, +/* 0x03 */ 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00, +/* 0x04 */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* 0x05 */ 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x06 */ 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x08 */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0x09 */ 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00, +/* 0x0A */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0x0B */ 0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, +/* 0x0C */ 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x0D */ 0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00, +/* 0x0E */ 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00, +/* 0x0F */ 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x10 */ 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, +/* 0x11 */ 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, +/* 0x12 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0x13 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0x14 */ 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00, +/* 0x15 */ 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00, +/* 0x16 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00, +/* 0x17 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0x18 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x19 */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0x1A */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1B */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1C */ 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1D */ 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x1E */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0x1F */ 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, +/* 0x20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x21 */ 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x22 */ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x23 */ 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00, +/* 0x24 */ 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00, +/* 0x25 */ 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00, +/* 0x26 */ 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x27 */ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x28 */ 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00, +/* 0x29 */ 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00, +/* 0x2A */ 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2B */ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2C */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00, +/* 0x2D */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x2E */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x2F */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00, +/* 0x30 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, +/* 0x31 */ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0x32 */ 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x33 */ 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x34 */ 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, +/* 0x35 */ 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x36 */ 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x37 */ 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, +/* 0x38 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x39 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00, +/* 0x3A */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0x3B */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00, +/* 0x3C */ 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, +/* 0x3D */ 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x3E */ 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, +/* 0x3F */ 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x40 */ 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00, +/* 0x41 */ 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x42 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00, +/* 0x43 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00, +/* 0x44 */ 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00, +/* 0x45 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x46 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x47 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00, +/* 0x48 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x49 */ 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x4A */ 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, +/* 0x4B */ 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x4C */ 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x4D */ 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x4E */ 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x4F */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x50 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x51 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00, +/* 0x52 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x53 */ 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x54 */ 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x55 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x56 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00, +/* 0x57 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00, +/* 0x58 */ 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x59 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x5A */ 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x5B */ 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, +/* 0x5C */ 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, +/* 0x5D */ 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, +/* 0x5E */ 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x5F */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, +/* 0x60 */ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x61 */ 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x62 */ 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00, +/* 0x63 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x64 */ 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x65 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x66 */ 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x67 */ 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00, +/* 0x68 */ 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x69 */ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x6A */ 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, +/* 0x6B */ 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00, +/* 0x6C */ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x6D */ 0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x6E */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0x6F */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x70 */ 0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00, +/* 0x71 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00, +/* 0x72 */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, +/* 0x73 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x74 */ 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00, +/* 0x75 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x76 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0x77 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00, +/* 0x78 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00, +/* 0x79 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00, +/* 0x7A */ 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0x7B */ 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, +/* 0x7C */ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x7D */ 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, +/* 0x7E */ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0x7F */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0x80 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00, +/* 0x81 */ 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x82 */ 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x83 */ 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x84 */ 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x85 */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x86 */ 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x87 */ 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00, +/* 0x88 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x89 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x8A */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x8B */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8C */ 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8D */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0x8E */ 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x8F */ 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0x90 */ 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00, +/* 0x91 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00, +/* 0x92 */ 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00, +/* 0x93 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x94 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x95 */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x96 */ 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x97 */ 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0x98 */ 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, +/* 0x99 */ 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x9A */ 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0x9B */ 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x9C */ 0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00, +/* 0x9D */ 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0x9E */ 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00, +/* 0x9F */ 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00, +/* 0xA0 */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0xA1 */ 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, +/* 0xA2 */ 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0xA3 */ 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, +/* 0xA4 */ 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, +/* 0xA5 */ 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0xA6 */ 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xA7 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xA8 */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, +/* 0xA9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00, +/* 0xAA */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, +/* 0xAB */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00, +/* 0xAC */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00, +/* 0xAD */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, +/* 0xAE */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xAF */ 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xB0 */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, +/* 0xB1 */ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, +/* 0xB2 */ 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77, +/* 0xB3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB4 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB5 */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB6 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xB7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xB8 */ 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xB9 */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBA */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBB */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xBC */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBD */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBE */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xBF */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC1 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC4 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC6 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xC7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xC8 */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xC9 */ 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCA */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xCB */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCC */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCD */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xCE */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xCF */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD0 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD1 */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD3 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD4 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xD5 */ 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD6 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, +/* 0xD8 */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xD9 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xDA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xDB */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0xDC */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +/* 0xDD */ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, +/* 0xDE */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, +/* 0xDF */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xE0 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00, +/* 0xE1 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00, +/* 0xE2 */ 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00, +/* 0xE3 */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00, +/* 0xE4 */ 0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, +/* 0xE5 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, +/* 0xE6 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00, +/* 0xE7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/* 0xE8 */ 0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, +/* 0xE9 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, +/* 0xEA */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00, +/* 0xEB */ 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, +/* 0xEC */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xED */ 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00, +/* 0xEE */ 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00, +/* 0xEF */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, +/* 0xF0 */ 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00, +/* 0xF1 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, +/* 0xF2 */ 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00, +/* 0xF3 */ 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00, +/* 0xF4 */ 0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 0xF5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, +/* 0xF6 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, +/* 0xF7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xF8 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xF9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFB */ 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00, +/* 0xFC */ 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFD */ 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 0xFE */ 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00, +}; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/kbd.c linux/arch/ppc/boot/prep/kbd.c --- v2.4.4/linux/arch/ppc/boot/prep/kbd.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/kbd.c Thu May 24 15:02:07 2001 @@ -0,0 +1,218 @@ +/* + * BK Id: SCCS/s.kbd.c 1.7 05/18/01 06:20:29 patch + */ +#include + +#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ + + +unsigned char shfts, ctls, alts, caps; + +#define KBDATAP 0x60 /* kbd data port */ +#define KBSTATUSPORT 0x61 /* kbd status */ +#define KBSTATP 0x64 /* kbd status port */ +#define KBINRDY 0x01 +#define KBOUTRDY 0x02 + +extern unsigned char inb(int port); +extern void outb(int port, char val); +extern void puts(const char *); +extern void puthex(unsigned long val); +extern void udelay(long x); + +static int kbd(int noblock) +{ + unsigned char dt, brk, val; + unsigned code; +loop: + if (noblock) { + if ((inb(KBSTATP) & KBINRDY) == 0) + return (-1); + } else while((inb(KBSTATP) & KBINRDY) == 0) ; + + dt = inb(KBDATAP); + + brk = dt & 0x80; /* brk == 1 on key release */ + dt = dt & 0x7f; /* keycode */ + + if (shfts) + code = shift_map[dt]; + else if (ctls) + code = ctrl_map[dt]; + else + code = plain_map[dt]; + + val = KVAL(code); + switch (KTYP(code) & 0x0f) { + case KT_LATIN: + if (brk) + break; + if (alts) + val |= 0x80; + if (val == 0x7f) /* map delete to backspace */ + val = '\b'; + return val; + + case KT_LETTER: + if (brk) + break; + if (caps) + val -= 'a'-'A'; + return val; + + case KT_SPEC: + if (brk) + break; + if (val == KVAL(K_CAPS)) + caps = !caps; + else if (val == KVAL(K_ENTER)) { +enter: /* Wait for key up */ + while (1) { + while((inb(KBSTATP) & KBINRDY) == 0) ; + dt = inb(KBDATAP); + if (dt & 0x80) /* key up */ break; + } + return 10; + } + break; + + case KT_PAD: + if (brk) + break; + if (val < 10) + return val; + if (val == KVAL(K_PENTER)) + goto enter; + break; + + case KT_SHIFT: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + shfts = brk ? 0 : 1; + break; + case KG_ALT: + case KG_ALTGR: + alts = brk ? 0 : 1; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + ctls = brk ? 0 : 1; + break; + } + break; + + case KT_LOCK: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + if (brk) + shfts = !shfts; + break; + case KG_ALT: + case KG_ALTGR: + if (brk) + alts = !alts; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + if (brk) + ctls = !ctls; + break; + } + break; + } + if (brk) return (-1); /* Ignore initial 'key up' codes */ + goto loop; +} + +static void kbdreset(void) +{ + unsigned char c; + int i; + + /* flush input queue */ + while ((inb(KBSTATP) & KBINRDY)) + { + (void)inb(KBDATAP); + } + /* Send self-test */ + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0xAA); + while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + if ((c = inb(KBDATAP)) != 0x55) + { + puts("Keyboard self test failed - result:"); + puthex(c); + puts("\n"); + } + /* Enable interrupts and keyboard controller */ + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0x60); + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBDATAP,0x45); + for (i = 0; i < 10000; i++) udelay(1); + + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0x20); + while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + if (! (inb(KBDATAP) & 0x40)) { + /* + * 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." (KBINRDY and KBOUTRDY) + */ + + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0xF0); + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0x01); + } + + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0xAE); +} + +/* We have to actually read the keyboard when CRT_tstc is called, + * since the pending data might be a key release code, and therefore + * not valid data. In this case, kbd() will return -1, even though there's + * data to be read. Of course, we might actually read a valid key press, + * in which case it gets queued into key_pending for use by CRT_getc. + */ + +static int kbd_reset = 0; + +static int key_pending = -1; + +int CRT_getc(void) +{ + int c; + if (!kbd_reset) {kbdreset(); kbd_reset++; } + + if (key_pending != -1) { + c = key_pending; + key_pending = -1; + return c; + } else { + while ((c = kbd(0)) == 0) ; + return c; + } +} + +int CRT_tstc(void) +{ + if (!kbd_reset) {kbdreset(); kbd_reset++; } + + while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { + key_pending = kbd(1); + } + + return (key_pending != -1); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/misc.c linux/arch/ppc/boot/prep/misc.c --- v2.4.4/linux/arch/ppc/boot/prep/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/misc.c Thu May 24 15:02:07 2001 @@ -0,0 +1,453 @@ +/* + * BK Id: SCCS/s.misc.c 1.8 05/18/01 06:20:29 patch + */ +/* + * misc.c + * + * Adapted for PowerPC by Gary Thomas + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort + */ + +#include +#include "zlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_SERIAL_CONSOLE) +unsigned long com_port; +#endif /* CONFIG_SERIAL_CONSOLE */ + +/* + * Please send me load/board info and such data for hardware not + * listed here so I can keep track since things are getting tricky + * with the different load addrs with different firmware. This will + * help to avoid breaking the load/boot process. + * -- Cort + */ +char *avail_ram; +char *end_avail; +extern char _end[]; + +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE ""; +#endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +int keyb_present = 1; /* keyboard controller is present by default */ +RESIDUAL hold_resid_buf; +RESIDUAL *hold_residual = &hold_resid_buf; +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +char *vidmem = (char *)0xC00B8000; +int lines, cols; +int orig_x, orig_y; + +extern void puts(const char *); +extern void putc(const char c); +extern int tstc(void); +extern int getc(void); +extern void puthex(unsigned long val); +extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n); +extern int CRT_tstc(void); +extern void of_init(void *handler); +extern int of_finddevice(const char *device_specifier, int *phandle); +extern int of_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); +extern __kernel_size_t strlen(const char *s); +extern int vga_init(unsigned char *ISA_mem); +extern void udelay(long x); +void gunzip(void *, int, unsigned char *, int *); +unsigned char inb(int); + +void +writel(unsigned int val, unsigned int address) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + *(unsigned int *)address = cpu_to_le32(val); +} + +unsigned int +readl(unsigned int address) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return le32_to_cpu(*(unsigned int *)address); +} + +#define PCI_CFG_ADDR(dev,off) ((0x80<<24) | (dev<<8) | (off&0xfc)) +#define PCI_CFG_DATA(off) (0x80000cfc+(off&3)) + +static void +pci_read_config_32(unsigned char devfn, + unsigned char offset, + unsigned int *val) +{ + writel(PCI_CFG_ADDR(devfn,offset), 0x80000cf8); + *val = readl(PCI_CFG_DATA(offset)); + return; +} + +void +scroll() +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +/* + * This routine is used to control the second processor on the + * Motorola dual processor platforms. + */ +void +park_cpus() +{ + volatile void (*go)(RESIDUAL *, int, int, char *, int); + unsigned int i; + volatile unsigned long *smp_iar = &(hold_residual->VitalProductData.SmpIar); + + /* Wait for indication to continue. If the kernel + was not compiled with SMP support then the second + processor will spin forever here makeing the kernel + multiprocessor safe. */ + while (*smp_iar == 0) { + for (i=0; i < 512; i++); + } + + (unsigned long)go = hold_residual->VitalProductData.SmpIar; + go(hold_residual, 0, 0, cmd_line, sizeof(cmd_preset)); +} + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + RESIDUAL *residual, void *OFW_interface) +{ + int timer; + extern unsigned long start; + char *cp, ch; + unsigned long TotalMemory; + unsigned long orig_MSR; + int dev_handle; + int mem_info[2]; + int res, size; + unsigned char board_type; + unsigned char base_mod; + int start_multi = 0; + unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base; + + lines = 25; + cols = 80; + orig_x = 0; + orig_y = 24; + + /* + * IBM's have the MMU on, so we have to disable it or + * things get really unhappy in the kernel when + * trying to setup the BATs with the MMU on + * -- Cort + */ + flush_instruction_cache(); + _put_HID0(_get_HID0() & ~0x0000C000); + _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); + +#if defined(CONFIG_SERIAL_CONSOLE) + com_port = serial_init(0); +#endif /* CONFIG_SERIAL_CONSOLE */ + vga_init((char)0xC0000000); + + if (residual) + { + /* Is this Motorola PPCBug? */ + if ((1 & residual->VitalProductData.FirmwareSupports) && + (1 == residual->VitalProductData.FirmwareSupplier)) { + board_type = inb(0x800) & 0xF0; + + /* + * Reset the onboard 21x4x Ethernet + * Motorola Ethernet is at IDSEL 14 (devfn 0x70) + */ + pci_read_config_32(0x70, 0x00, &pci_viddid); + pci_did = (pci_viddid & 0xffff0000) >> 16; + /* Be sure we've really found a 21x4x chip */ + if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_DEC) && + ((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) || + (pci_did == PCI_DEVICE_ID_DEC_TULIP) || + (pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) || + (pci_did == PCI_DEVICE_ID_DEC_21142))) + { + pci_read_config_32(0x70, + 0x10, + &tulip_pci_base); + /* Get the physical base address */ + tulip_base = + (tulip_pci_base & ~0x03UL) + 0x80000000; + /* Strobe the 21x4x reset bit in CSR0 */ + writel(0x1, tulip_base); + } + + /* If this is genesis 2 board then check for no + * keyboard controller and more than one processor. + */ + if (board_type == 0xe0) { + base_mod = inb(0x803); + /* if a MVME2300/2400 or a Sitka then no keyboard */ + if((base_mod == 0xFA) || (base_mod == 0xF9) || + (base_mod == 0xE1)) { + keyb_present = 0; /* no keyboard */ + } + } + /* If this is a multiprocessor system then + * park the other processor so that the + * kernel knows where to find them. + */ + if (residual->MaxNumCpus > 1) { + start_multi = 1; + } + } + memcpy(hold_residual,residual,sizeof(RESIDUAL)); + } else { + /* Assume 32M in the absence of more info... */ + TotalMemory = 0x02000000; + /* + * This is a 'best guess' check. We want to make sure + * we don't try this on a PReP box without OF + * -- Cort + */ + while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) + { + /* The MMU needs to be on when we call OFW */ + _put_MSR(orig_MSR); + of_init(OFW_interface); + + /* get handle to memory description */ + res = of_finddevice("/memory@0", + &dev_handle); + // puthex(res); puts("\n"); + if (res) break; + + /* get the info */ + // puts("get info = "); + res = of_getprop(dev_handle, + "reg", + mem_info, + sizeof(mem_info), + &size); + // puthex(res); puts(", info = "); puthex(mem_info[0]); + // puts(" "); puthex(mem_info[1]); puts("\n"); + if (res) break; + + TotalMemory = mem_info[1]; + break; + } + hold_residual->TotalMemory = TotalMemory; + residual = hold_residual; + /* Turn MMU back off */ + _put_MSR(orig_MSR & ~0x0030); + } + + if (start_multi) { + hold_residual->VitalProductData.SmpIar = 0; + hold_residual->Cpus[1].CpuState = CPU_GOOD_FW; + residual->VitalProductData.SmpIar = (unsigned long)park_cpus; + residual->Cpus[1].CpuState = CPU_GOOD; + hold_residual->VitalProductData.Reserved5 = 0xdeadbeef; + } + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* tell the user where we were loaded at and where we + * were relocated to for debugging this process + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( residual ) + { + puts("board data at: "); puthex((unsigned long)residual); + puts(" "); + puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); + puts("\n"); + puts("relocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including the + size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; + + /* + * Find a place to stick the zimage and initrd and + * relocate them if we have to. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + if ( (unsigned long)zimage_start <= 0x00800000 ) + { + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + avail_ram = (char *)PAGE_ALIGN( + (unsigned long)zimage_size+(unsigned long)zimage_start); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); + initrd_start = (unsigned long)avail_ram; + initrd_end = initrd_start + INITRD_SIZE; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + } else if ( initrd_start ) { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + if (keyb_present) + CRT_tstc(); /* Forces keyboard to be initialized */ + + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\n"); + + /* mappings on early boot can only handle 16M */ + if ( (int)(cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( (int)hold_residual > (16<<20)) + puts("hold_residual located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + + { + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN(zimage_size); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + memcpy( (void *)rec->data, "prepboot", 9); + rec->size = sizeof(struct bi_record) + 8 + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_prep; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((ulong)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + puts("Now booting the kernel\n"); + return (unsigned long)hold_residual; +} + +/* + * PCI/ISA I/O support + */ + +volatile unsigned char *ISA_io = (unsigned char *)0x80000000; +volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; + +void +outb(int port, char val) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + ISA_io[port] = val; +} + +unsigned char +inb(int port) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return (ISA_io[port]); +} + +unsigned long +local_to_PCI(unsigned long addr) +{ + return ((addr & 0x7FFFFFFF) | 0x80000000); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/of1275.c linux/arch/ppc/boot/prep/of1275.c --- v2.4.4/linux/arch/ppc/boot/prep/of1275.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/of1275.c Thu May 24 15:02:07 2001 @@ -0,0 +1,430 @@ +/* + * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort + */ +/* Open Firmware Client Interface */ + + +#include "of1275.h" + + +static int (*of_server)(void *) = (int(*)(void*))-1; + +void +of_init(void *handler) +{ + of_server = (int(*)(void*))handler; +} + + +/* 6.3.2.1 Client interface */ + + +int +of_test(const char *name, int *missing) +{ + int result; + static of_test_service s; + s.service = "test"; + s.n_args = 1; + s.n_returns = 1; + s.name = name; + result = of_server(&s); + *missing = s.missing; + return result; +} + + +/* 6.3.2.2 Device tree */ + + +int +of_peer(int phandle, int *sibling_phandle) +{ + int result; + static of_peer_service s; + s.service = "peer"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *sibling_phandle = s.sibling_phandle; + return result; +} + +int +of_child(int phandle, int *child_phandle) +{ + int result; + static of_child_service s; + s.service = "child"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *child_phandle = s.child_phandle; + return result; +} + +int +of_parent(int phandle, int *parent_phandle) +{ + int result; + static of_parent_service s; + s.service = "parent"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *parent_phandle = s.parent_phandle; + return result; +} + +int +of_instance_to_package(int ihandle, int *phandle) +{ + int result; + static of_instance_to_package_service s; + s.service = "instance-to-package"; + s.n_args = 1; + s.n_returns = 1; + s.ihandle = ihandle; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_getproplen(int phandle, const char *name, int *proplen) +{ + int result; + static of_getproplen_service s; + s.service = "getproplen"; + s.n_args = 2; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + result = of_server(&s); + *proplen = s.proplen; + return result; +} + +int +of_getprop(int phandle, const char *name, void *buf, int buflen, int *size) +{ + int result; + static of_getprop_service s; + s.service = "getprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_nextprop(int phandle, const char *previous, void *buf, int *flag) +{ + int result; + static of_nextprop_service s; + s.service = "nextprop"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.previous = previous; + s.buf = buf; + result = of_server(&s); + *flag = s.flag; + return result; +} + +int +of_setprop(int phandle, const char *name, void *buf, int len, int *size) +{ + int result; + static of_setprop_service s; + s.service = "setprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.len = len; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_canon(const char *device_specifier, void *buf, int buflen, int *length) +{ + int result; + static of_canon_service s; + s.service = "canon"; + s.n_args = 3; + s.n_returns = 1; + s.device_specifier = device_specifier; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_finddevice(const char *device_specifier, int *phandle) +{ + int result; + static of_finddevice_service s; + s.service = "finddevice"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_instance_to_path(int ihandle, void *buf, int buflen, int *length) +{ + int result; + static of_instance_to_path_service s; + s.service = "instance-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_package_to_path(int phandle, void *buf, int buflen, int *length) +{ + int result; + static of_package_to_path_service s; + s.service = "package-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +/* int of_call_method(const char *method, int ihandle, ...); */ + + +/* 6.3.2.3 Device I/O */ + + +int +of_open(const char *device_specifier, int *ihandle) +{ + int result; + static of_open_service s; + s.service = "open"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *ihandle = s.ihandle; + return result; +} + +int +of_close(int ihandle) +{ + int result; + static of_close_service s; + s.service = "close"; + s.n_args = 1; + s.n_returns = 0; + s.ihandle = ihandle; + result = of_server(&s); + return result; +} + +int +of_read(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_read_service s; + s.service = "read"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_write(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_write_service s; + s.service = "write"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_seek(int ihandle, int pos_hi, int pos_lo, int *status) +{ + int result; + static of_seek_service s; + s.service = "seek"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.pos_hi = pos_hi; + s.pos_lo = pos_lo; + result = of_server(&s); + *status = s.status; + return result; +} + + +/* 6.3.2.4 Memory */ + + +int +of_claim(void *virt, int size, int align, void **baseaddr) +{ + int result; + static of_claim_service s; + s.service = "claim"; + s.n_args = 3; + s.n_returns = 1; + s.virt = virt; + s.size = size; + s.align = align; + result = of_server(&s); + *baseaddr = s.baseaddr; + return result; +} + +int +of_release(void *virt, int size) +{ + int result; + static of_release_service s; + s.service = "release"; + s.n_args = 2; + s.n_returns = 0; + s.virt = virt; + s.size = size; + result = of_server(&s); + return result; +} + + +/* 6.3.2.5 Control transfer */ + + +int +of_boot(const char *bootspec) +{ + int result; + static of_boot_service s; + s.service = "boot"; + s.n_args = 1; + s.n_returns = 0; + s.bootspec = bootspec; + result = of_server(&s); + return result; +} + +int +of_enter(void) +{ + int result; + static of_enter_service s; + s.service = "enter"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +int +of_exit(void) +{ + int result; + static of_exit_service s; + s.service = "exit"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +/* int of_chain(void *virt, int size, void *entry, void *args, int len); */ + + +/* 6.3.2.6 User interface */ + + +/* int of_interpret(const char *arg, ...); */ + +int +of_set_callback(void *newfunc, void **oldfunc) +{ + int result; + static of_set_callback_service s; + s.service = "set-callback"; + s.n_args = 1; + s.n_returns = 1; + s.newfunc = newfunc; + result = of_server(&s); + *oldfunc = s.oldfunc; + return result; +} + +int +of_set_symbol_lookup(void *sym_to_value, void *value_to_sym) +{ + int result; + static of_set_symbol_lookup_service s; + s.service = "set-symbol-lookup"; + s.n_args = 2; + s.n_returns = 0; + s.sym_to_value = sym_to_value; + s.value_to_sym = s.value_to_sym; + result = of_server(&s); + return result; +} + + +/* 6.3.2.7 Time */ + + +int +of_milliseconds(int *ms) +{ + int result; + static of_milliseconds_service s; + s.service = "milliseconds"; + s.n_args = 0; + s.n_returns = 1; + result = of_server(&s); + *ms = s.ms; + return result; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/of1275.h linux/arch/ppc/boot/prep/of1275.h --- v2.4.4/linux/arch/ppc/boot/prep/of1275.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/of1275.h Thu May 24 15:02:07 2001 @@ -0,0 +1,424 @@ +/* + * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort + */ +/* 6.3.2.1 Client interface */ + + +typedef struct _of_test_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *name; + /*out*/ + int missing; +} of_test_service; + +int of_test(const char *name, int *missing); + + +/* 6.3.2.2 Device tree */ + + +typedef struct _of_peer_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int sibling_phandle; +} of_peer_service; + +int of_peer(int phandle, int *sibling_phandle); + + +typedef struct _of_child_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int child_phandle; +} of_child_service; + +int of_child(int phandle, int *child_phandle); + + +typedef struct _of_parent_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int parent_phandle; +} of_parent_service; + +int of_child(int phandle, int *parent_phandle); + + +typedef struct _of_instance_to_package_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ + int phandle; +} of_instance_to_package_service; + +int of_instance_to_package(int ihandle, int *phandle); + + +typedef struct _of_getproplen_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + /*out*/ + int proplen; +} of_getproplen_service; + +int of_getproplen(int phandle, const char *name, int *proplen); + + +typedef struct _of_getprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int buflen; + /*out*/ + int size; +} of_getprop_service; + +int of_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); + + +typedef struct _of_nextprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *previous; + void *buf; + /*out*/ + int flag; +} of_nextprop_service; + +int of_nextprop(int phandle, const char *previous, void *buf, int *flag); + + +typedef struct _of_setprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int len; + /*out*/ + int size; +} of_setprop_service; + +int of_setprop(int phandle, const char *name, void *buf, int len, int *size); + + +typedef struct _of_canon_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + void *buf; + int buflen; + /*out*/ + int length; +} of_canon_service; + +int of_canon(const char *device_specifier, void *buf, int buflen, int *length); + + +typedef struct _of_finddevice_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int phandle; +} of_finddevice_service; + +int of_finddevice(const char *device_specifier, int *phandle); + + +typedef struct _of_instance_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_instance_to_path_service; + +int of_instance_to_path(int ihandle, void *buf, int buflen, int *length); + + +typedef struct _of_package_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_package_to_path_service; + +int of_package_to_path(int phandle, void *buf, int buflen, int *length); + + +typedef struct _of_call_method_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *method; + int ihandle; + /*...*/ + int args[0]; +} of_call_method_service; + +int of_call_method(const char *method, int ihandle, ...); + + +/* 6.3.2.3 Device I/O */ + + +typedef struct _of_open_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int ihandle; +} of_open_service; + +int of_open(const char *device_specifier, + int *ihandle); + + +typedef struct _of_close_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ +} of_close_service; + +int of_close(int ihandle); + + +typedef struct _of_read_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_read_service; + +int of_read(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_write_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_write_service; + +int of_write(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_seek_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + int pos_hi; + int pos_lo; + /*out*/ + int status; +} of_seek_service; + +int of_seek(int ihandle, int pos_hi, int pos_lo, int *status); + + +/* 6.3.2.4 Memory */ + + +typedef struct _of_claim_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ + void *baseaddr; +} of_claim_service; + +int of_claim(void *virt, int size, int align, void **baseaddr); + + +typedef struct _of_release_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ +} of_release_service; + +int of_release(void *virt, int size); + + +/* 6.3.2.5 Control transfer */ + + +typedef struct _of_boot_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *bootspec; + /*out*/ +} of_boot_service; + +int of_boot(const char *bootspec); + + +typedef struct _of_enter_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_enter_service; + +int of_enter(void); + + +typedef struct _of_exit_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_exit_service; + +int of_exit(void); + + +typedef struct _of_chain_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + void *entry; + void *args; + int len; + /*out*/ +} of_chain_service; + +int of_chain(void *virt, int size, void *entry, void *args, int len); + + +/* 6.3.2.6 User interface */ + + +typedef struct _of_interpret_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *cmd; + int args[0]; + /*...*/ + /*out*/ + /*...*/ +} of_interpret_service; + +int of_interpret(const char *arg, ...); + + +typedef struct _of_set_callback_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *newfunc; + /*out*/ + void *oldfunc; +} of_set_callback_service; + +int of_set_callback(void *newfunc, void **oldfunc); + + +typedef struct _of_set_symbol_lookup_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *sym_to_value; + void *value_to_sym; + /*out*/ +} of_set_symbol_lookup_service; + +int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym); + + +/* 6.3.2.7 Time */ + + +typedef struct _of_milliseconds_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ + int ms; +} of_milliseconds_service; + +int of_milliseconds(int *ms); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/prep/vreset.c linux/arch/ppc/boot/prep/vreset.c --- v2.4.4/linux/arch/ppc/boot/prep/vreset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/prep/vreset.c Thu May 24 15:02:07 2001 @@ -0,0 +1,863 @@ +/* + * BK Id: SCCS/s.vreset.c 1.9 05/18/01 06:20:29 patch + */ +/* + * vreset.c + * + * Initialize the VGA control registers to 80x25 text mode. + * + * Adapted from a program by: + * Steve Sellgren + * San Francisco Indigo Company + * sfindigo!sellgren@uunet.uu.net + * + * Original concept by: + * Gary Thomas + * Adapted for Moto boxes by: + * Pat Kane & Mark Scott, 1996 + * Adapted for IBM portables by: + * Takeshi Ishimoto + * Multi-console support: + * Terje Malmedal + */ + +#include "iso_font.h" + +extern char *vidmem; +extern int lines, cols; +extern void udelay(long x); +extern void outb(int port, char val); +extern unsigned char inb(int port); +struct VaRegs; + +/* + * VGA Register + */ +struct VgaRegs +{ + unsigned short io_port; + unsigned char io_index; + unsigned char io_value; +}; + +void unlockVideo(int slot); +void setTextRegs(struct VgaRegs *svp); +void setTextCLUT(int shift); +void clearVideoMemory(); +void loadFont(unsigned char *ISA_mem); + +static void mdelay(int ms) +{ + for (; ms > 0; --ms) + udelay(1000); +} + +/* + * Default console text mode registers used to reset + * graphics adapter. + */ +#define NREGS 54 +#define ENDMK 0xFFFF /* End marker */ + +#define S3Vendor 0x5333 +#define CirrusVendor 0x1013 +#define DiamondVendor 0x100E +#define MatroxVendor 0x102B +#define ParadiseVendor 0x101C + +struct VgaRegs GenVgaTextRegs[NREGS+1] = { +/* port index value */ + /* SR Regs */ + 0x3c4, 0x1, 0x0, + 0x3c4, 0x2, 0x3, + 0x3c4, 0x3, 0x0, + 0x3c4, 0x4, 0x2, + /* CR Regs */ + 0x3d4, 0x0, 0x5f, + 0x3d4, 0x1, 0x4f, + 0x3d4, 0x2, 0x50, + 0x3d4, 0x3, 0x82, + 0x3d4, 0x4, 0x55, + 0x3d4, 0x5, 0x81, + 0x3d4, 0x6, 0xbf, + 0x3d4, 0x7, 0x1f, + 0x3d4, 0x8, 0x00, + 0x3d4, 0x9, 0x4f, + 0x3d4, 0xa, 0x0d, + 0x3d4, 0xb, 0x0e, + 0x3d4, 0xc, 0x00, + 0x3d4, 0xd, 0x00, + 0x3d4, 0xe, 0x00, + 0x3d4, 0xf, 0x00, + 0x3d4, 0x10, 0x9c, + 0x3d4, 0x11, 0x8e, + 0x3d4, 0x12, 0x8f, + 0x3d4, 0x13, 0x28, + 0x3d4, 0x14, 0x1f, + 0x3d4, 0x15, 0x96, + 0x3d4, 0x16, 0xb9, + 0x3d4, 0x17, 0xa3, + /* GR Regs */ + 0x3ce, 0x0, 0x0, + 0x3ce, 0x1, 0x0, + 0x3ce, 0x2, 0x0, + 0x3ce, 0x3, 0x0, + 0x3ce, 0x4, 0x0, + 0x3ce, 0x5, 0x10, + 0x3ce, 0x6, 0xe, + 0x3ce, 0x7, 0x0, + 0x3ce, 0x8, 0xff, + ENDMK +}; + +struct VgaRegs S3TextRegs[NREGS+1] = { +/* port index value */ + /* SR Regs */ + 0x3c4, 0x1, 0x0, + 0x3c4, 0x2, 0x3, + 0x3c4, 0x3, 0x0, + 0x3c4, 0x4, 0x2, + /* CR Regs */ + 0x3d4, 0x0, 0x5f, + 0x3d4, 0x1, 0x4f, + 0x3d4, 0x2, 0x50, + 0x3d4, 0x3, 0x82, + 0x3d4, 0x4, 0x55, + 0x3d4, 0x5, 0x81, + 0x3d4, 0x6, 0xbf, + 0x3d4, 0x7, 0x1f, + 0x3d4, 0x8, 0x00, + 0x3d4, 0x9, 0x4f, + 0x3d4, 0xa, 0x0d, + 0x3d4, 0xb, 0x0e, + 0x3d4, 0xc, 0x00, + 0x3d4, 0xd, 0x00, + 0x3d4, 0xe, 0x00, + 0x3d4, 0xf, 0x00, + 0x3d4, 0x10, 0x9c, + 0x3d4, 0x11, 0x8e, + 0x3d4, 0x12, 0x8f, + 0x3d4, 0x13, 0x28, + 0x3d4, 0x14, 0x1f, + 0x3d4, 0x15, 0x96, + 0x3d4, 0x16, 0xb9, + 0x3d4, 0x17, 0xa3, + /* GR Regs */ + 0x3ce, 0x0, 0x0, + 0x3ce, 0x1, 0x0, + 0x3ce, 0x2, 0x0, + 0x3ce, 0x3, 0x0, + 0x3ce, 0x4, 0x0, + 0x3ce, 0x5, 0x10, + 0x3ce, 0x6, 0xe, + 0x3ce, 0x7, 0x0, + 0x3ce, 0x8, 0xff, + ENDMK +}; + +struct RGBColors +{ + unsigned char r, g, b; +}; + +/* + * Default console text mode color table. + * These values were obtained by booting Linux with + * text mode firmware & then dumping the registers. + */ +struct RGBColors TextCLUT[256] = +{ + /* red green blue */ + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2a, + 0x0, 0x2a, 0x0, + 0x0, 0x2a, 0x2a, + 0x2a, 0x0, 0x0, + 0x2a, 0x0, 0x2a, + 0x2a, 0x2a, 0x0, + 0x2a, 0x2a, 0x2a, + 0x0, 0x0, 0x15, + 0x0, 0x0, 0x3f, + 0x0, 0x2a, 0x15, + 0x0, 0x2a, 0x3f, + 0x2a, 0x0, 0x15, + 0x2a, 0x0, 0x3f, + 0x2a, 0x2a, 0x15, + 0x2a, 0x2a, 0x3f, + 0x0, 0x15, 0x0, + 0x0, 0x15, 0x2a, + 0x0, 0x3f, 0x0, + 0x0, 0x3f, 0x2a, + 0x2a, 0x15, 0x0, + 0x2a, 0x15, 0x2a, + 0x2a, 0x3f, 0x0, + 0x2a, 0x3f, 0x2a, + 0x0, 0x15, 0x15, + 0x0, 0x15, 0x3f, + 0x0, 0x3f, 0x15, + 0x0, 0x3f, 0x3f, + 0x2a, 0x15, 0x15, + 0x2a, 0x15, 0x3f, + 0x2a, 0x3f, 0x15, + 0x2a, 0x3f, 0x3f, + 0x15, 0x0, 0x0, + 0x15, 0x0, 0x2a, + 0x15, 0x2a, 0x0, + 0x15, 0x2a, 0x2a, + 0x3f, 0x0, 0x0, + 0x3f, 0x0, 0x2a, + 0x3f, 0x2a, 0x0, + 0x3f, 0x2a, 0x2a, + 0x15, 0x0, 0x15, + 0x15, 0x0, 0x3f, + 0x15, 0x2a, 0x15, + 0x15, 0x2a, 0x3f, + 0x3f, 0x0, 0x15, + 0x3f, 0x0, 0x3f, + 0x3f, 0x2a, 0x15, + 0x3f, 0x2a, 0x3f, + 0x15, 0x15, 0x0, + 0x15, 0x15, 0x2a, + 0x15, 0x3f, 0x0, + 0x15, 0x3f, 0x2a, + 0x3f, 0x15, 0x0, + 0x3f, 0x15, 0x2a, + 0x3f, 0x3f, 0x0, + 0x3f, 0x3f, 0x2a, + 0x15, 0x15, 0x15, + 0x15, 0x15, 0x3f, + 0x15, 0x3f, 0x15, + 0x15, 0x3f, 0x3f, + 0x3f, 0x15, 0x15, + 0x3f, 0x15, 0x3f, + 0x3f, 0x3f, 0x15, + 0x3f, 0x3f, 0x3f, + 0x39, 0xc, 0x5, + 0x15, 0x2c, 0xf, + 0x26, 0x10, 0x3d, + 0x29, 0x29, 0x38, + 0x4, 0x1a, 0xe, + 0x2, 0x1e, 0x3a, + 0x3c, 0x25, 0x33, + 0x3c, 0xc, 0x2c, + 0x3f, 0x3, 0x2b, + 0x1c, 0x9, 0x13, + 0x25, 0x2a, 0x35, + 0x1e, 0xa, 0x38, + 0x24, 0x8, 0x3, + 0x3, 0xe, 0x36, + 0xc, 0x6, 0x2a, + 0x26, 0x3, 0x32, + 0x5, 0x2f, 0x33, + 0x3c, 0x35, 0x2f, + 0x2d, 0x26, 0x3e, + 0xd, 0xa, 0x10, + 0x25, 0x3c, 0x11, + 0xd, 0x4, 0x2e, + 0x5, 0x19, 0x3e, + 0xc, 0x13, 0x34, + 0x2b, 0x6, 0x24, + 0x4, 0x3, 0xd, + 0x2f, 0x3c, 0xc, + 0x2a, 0x37, 0x1f, + 0xf, 0x12, 0x38, + 0x38, 0xe, 0x2a, + 0x12, 0x2f, 0x19, + 0x29, 0x2e, 0x31, + 0x25, 0x13, 0x3e, + 0x33, 0x3e, 0x33, + 0x1d, 0x2c, 0x25, + 0x15, 0x15, 0x5, + 0x32, 0x25, 0x39, + 0x1a, 0x7, 0x1f, + 0x13, 0xe, 0x1d, + 0x36, 0x17, 0x34, + 0xf, 0x15, 0x23, + 0x2, 0x35, 0xd, + 0x15, 0x3f, 0xc, + 0x14, 0x2f, 0xf, + 0x19, 0x21, 0x3e, + 0x27, 0x11, 0x2f, + 0x38, 0x3f, 0x3c, + 0x36, 0x2d, 0x15, + 0x16, 0x17, 0x2, + 0x1, 0xa, 0x3d, + 0x1b, 0x11, 0x3f, + 0x21, 0x3c, 0xd, + 0x1a, 0x39, 0x3d, + 0x8, 0xe, 0xe, + 0x22, 0x21, 0x23, + 0x1e, 0x30, 0x5, + 0x1f, 0x22, 0x3d, + 0x1e, 0x2f, 0xa, + 0x0, 0x1c, 0xe, + 0x0, 0x1c, 0x15, + 0x0, 0x1c, 0x1c, + 0x0, 0x15, 0x1c, + 0x0, 0xe, 0x1c, + 0x0, 0x7, 0x1c, + 0xe, 0xe, 0x1c, + 0x11, 0xe, 0x1c, + 0x15, 0xe, 0x1c, + 0x18, 0xe, 0x1c, + 0x1c, 0xe, 0x1c, + 0x1c, 0xe, 0x18, + 0x1c, 0xe, 0x15, + 0x1c, 0xe, 0x11, + 0x1c, 0xe, 0xe, + 0x1c, 0x11, 0xe, + 0x1c, 0x15, 0xe, + 0x1c, 0x18, 0xe, + 0x1c, 0x1c, 0xe, + 0x18, 0x1c, 0xe, + 0x15, 0x1c, 0xe, + 0x11, 0x1c, 0xe, + 0xe, 0x1c, 0xe, + 0xe, 0x1c, 0x11, + 0xe, 0x1c, 0x15, + 0xe, 0x1c, 0x18, + 0xe, 0x1c, 0x1c, + 0xe, 0x18, 0x1c, + 0xe, 0x15, 0x1c, + 0xe, 0x11, 0x1c, + 0x14, 0x14, 0x1c, + 0x16, 0x14, 0x1c, + 0x18, 0x14, 0x1c, + 0x1a, 0x14, 0x1c, + 0x1c, 0x14, 0x1c, + 0x1c, 0x14, 0x1a, + 0x1c, 0x14, 0x18, + 0x1c, 0x14, 0x16, + 0x1c, 0x14, 0x14, + 0x1c, 0x16, 0x14, + 0x1c, 0x18, 0x14, + 0x1c, 0x1a, 0x14, + 0x1c, 0x1c, 0x14, + 0x1a, 0x1c, 0x14, + 0x18, 0x1c, 0x14, + 0x16, 0x1c, 0x14, + 0x14, 0x1c, 0x14, + 0x14, 0x1c, 0x16, + 0x14, 0x1c, 0x18, + 0x14, 0x1c, 0x1a, + 0x14, 0x1c, 0x1c, + 0x14, 0x1a, 0x1c, + 0x14, 0x18, 0x1c, + 0x14, 0x16, 0x1c, + 0x0, 0x0, 0x10, + 0x4, 0x0, 0x10, + 0x8, 0x0, 0x10, + 0xc, 0x0, 0x10, + 0x10, 0x0, 0x10, + 0x10, 0x0, 0xc, + 0x10, 0x0, 0x8, + 0x10, 0x0, 0x4, + 0x10, 0x0, 0x0, + 0x10, 0x4, 0x0, + 0x10, 0x8, 0x0, + 0x10, 0xc, 0x0, + 0x10, 0x10, 0x0, + 0xc, 0x10, 0x0, + 0x8, 0x10, 0x0, + 0x4, 0x10, 0x0, + 0x0, 0x10, 0x0, + 0x0, 0x10, 0x4, + 0x0, 0x10, 0x8, + 0x0, 0x10, 0xc, + 0x0, 0x10, 0x10, + 0x0, 0xc, 0x10, + 0x0, 0x8, 0x10, + 0x0, 0x4, 0x10, + 0x8, 0x8, 0x10, + 0xa, 0x8, 0x10, + 0xc, 0x8, 0x10, + 0xe, 0x8, 0x10, + 0x10, 0x8, 0x10, + 0x10, 0x8, 0xe, + 0x10, 0x8, 0xc, + 0x10, 0x8, 0xa, + 0x10, 0x8, 0x8, + 0x10, 0xa, 0x8, + 0x10, 0xc, 0x8, + 0x10, 0xe, 0x8, + 0x10, 0x10, 0x8, + 0xe, 0x10, 0x8, + 0xc, 0x10, 0x8, + 0xa, 0x10, 0x8, + 0x8, 0x10, 0x8, + 0x8, 0x10, 0xa, + 0x8, 0x10, 0xc, + 0x8, 0x10, 0xe, + 0x8, 0x10, 0x10, + 0x8, 0xe, 0x10, + 0x8, 0xc, 0x10, + 0x8, 0xa, 0x10, + 0xb, 0xb, 0x10, + 0xc, 0xb, 0x10, + 0xd, 0xb, 0x10, + 0xf, 0xb, 0x10, + 0x10, 0xb, 0x10, + 0x10, 0xb, 0xf, + 0x10, 0xb, 0xd, + 0x10, 0xb, 0xc, + 0x10, 0xb, 0xb, + 0x10, 0xc, 0xb, + 0x10, 0xd, 0xb, + 0x10, 0xf, 0xb, + 0x10, 0x10, 0xb, + 0xf, 0x10, 0xb, + 0xd, 0x10, 0xb, + 0xc, 0x10, 0xb, + 0xb, 0x10, 0xb, + 0xb, 0x10, 0xc, + 0xb, 0x10, 0xd, + 0xb, 0x10, 0xf, + 0xb, 0x10, 0x10, + 0xb, 0xf, 0x10, + 0xb, 0xd, 0x10, + 0xb, 0xc, 0x10, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0 +}; + +unsigned char AC[21] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x0C, 0x00, 0x0F, 0x08, 0x00}; + +static int scanPCI(int start_slt); +static int PCIVendor(int); +#ifdef DEBUG +static void printslots(void); +#endif +extern void puthex(unsigned long); +extern void puts(const char *); +static void unlockS3(void); + +static void inline +outw(int port, unsigned short val) +{ + outb(port, val >> 8); + outb(port+1, val); +} + +#define PPC_601 1 + +int +vga_init(unsigned char *ISA_mem) +{ + int slot; + struct VgaRegs *VgaTextRegs; +#if 0 + if ((_get_PVR()>>16) == PPC_601) { + return(old_vga_init(ISA_mem)); + } +#endif + + /* See if VGA already in TEXT mode - exit if so! */ + outb(0x3CE, 0x06); + if ((inb(0x3CF) & 0x01) == 0){ + puts("VGA already in text mode\n"); + return 0; + } + + /* If no VGA responding in text mode, then we have some work to do... + */ + slot = -1; + while((slot = scanPCI(slot)) > -1) { /* find video card in use */ + unlockVideo(slot); /* enable I/O to card */ + VgaTextRegs = GenVgaTextRegs; + + switch (PCIVendor(slot)) { + default: + break; + case(S3Vendor): + unlockS3(); + VgaTextRegs = S3TextRegs; + break; + + case(CirrusVendor): + outw(0x3C4, 0x0612); /* unlock ext regs */ + outw(0x3C4, 0x0700); /* reset ext sequence mode */ + break; + + case(ParadiseVendor): /* IBM Portable 850 */ + outw(0x3ce, 0x0f05); /* unlock pardise registers */ + outw(0x3c4, 0x0648); + outw(0x3d4, 0x2985); + outw(0x3d4, 0x34a6); + outb(0x3ce, 0x0b); /* disable linear addressing */ + outb(0x3cf, inb(0x3cf) & ~0x30); + outw(0x3c4, 0x1400); + outb(0x3ce, 0x0e); /* disable 256 color mode */ + outb(0x3cf, inb(0x3cf) & ~0x01); + outb(0xd00, 0xff); /* enable auto-centering */ + if (!(inb(0xd01) & 0x03)) { + outb(0x3d4, 0x33); + outb(0x3d5, inb(0x3d5) & ~0x90); + outb(0x3d4, 0x32); + outb(0x3d5, inb(0x3d5) | 0x04); + outw(0x3d4, 0x0250); + outw(0x3d4, 0x07ba); + outw(0x3d4, 0x0900); + outw(0x3d4, 0x15e7); + outw(0x3d4, 0x2a95); + } + outw(0x3d4, 0x34a0); + break; + + #if 0 /* Untested - probably doesn't work */ + case(MatroxVendor): + case(DiamondVendor): + puts("VGA Chip Vendor ID: "); + puthex(PCIVendor(slot)); + puts("\n"); + mdelay(1000); + #endif + }; + + outw(0x3C4, 0x0120); /* disable video */ + setTextRegs(VgaTextRegs); /* initial register setup */ + setTextCLUT(0); /* load color lookup table */ + loadFont(ISA_mem); /* load font */ + setTextRegs(VgaTextRegs); /* reload registers */ + outw(0x3C4, 0x0100); /* re-enable video */ + clearVideoMemory(); + + if (PCIVendor(slot) == S3Vendor) { + outb(0x3c2, 0x63); /* MISC */ + } /* endif */ + + #ifdef DEBUG + printslots(); + mdelay(5000); + #endif + + mdelay(1000); /* give time for the video monitor to come up */ + } + return (1); /* 'CRT' I/O supported */ +} + +/* + * Write to VGA Attribute registers. + */ +void +writeAttr(unsigned char index, unsigned char data, unsigned char videoOn) +{ + unsigned char v; + v = inb(0x3da); /* reset attr. address toggle */ + if (videoOn) + outb(0x3c0, (index & 0x1F) | 0x20); + else + outb(0x3c0, (index & 0x1F)); + outb(0x3c0, data); +} + +void +setTextRegs(struct VgaRegs *svp) +{ + int i; + + /* + * saved settings + */ + while( svp->io_port != ENDMK ) { + outb(svp->io_port, svp->io_index); + outb(svp->io_port+1, svp->io_value); + svp++; + } + + outb(0x3c2, 0x67); /* MISC */ + outb(0x3c6, 0xff); /* MASK */ + + for ( i = 0; i < 0x10; i++) + writeAttr(i, AC[i], 0); /* pallete */ + writeAttr(0x10, 0x0c, 0); /* text mode */ + writeAttr(0x11, 0x00, 0); /* overscan color (border) */ + writeAttr(0x12, 0x0f, 0); /* plane enable */ + writeAttr(0x13, 0x08, 0); /* pixel panning */ + writeAttr(0x14, 0x00, 1); /* color select; video on */ +} + +void +setTextCLUT(int shift) +{ + int i; + + outb(0x3C6, 0xFF); + i = inb(0x3C7); + outb(0x3C8, 0); + i = inb(0x3C7); + + for ( i = 0; i < 256; i++) { + outb(0x3C9, TextCLUT[i].r << shift); + outb(0x3C9, TextCLUT[i].g << shift); + outb(0x3C9, TextCLUT[i].b << shift); + } +} + +void +loadFont(unsigned char *ISA_mem) +{ + int i, j; + unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; + + outb(0x3C2, 0x67); + /* + * Load font + */ + i = inb(0x3DA); /* Reset Attr toggle */ + + outb(0x3C0,0x30); + outb(0x3C0, 0x01); /* graphics mode */ + + outw(0x3C4, 0x0001); /* reset sequencer */ + outw(0x3C4, 0x0204); /* write to plane 2 */ + outw(0x3C4, 0x0406); /* enable plane graphics */ + outw(0x3C4, 0x0003); /* reset sequencer */ + outw(0x3CE, 0x0402); /* read plane 2 */ + outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ + outw(0x3CE, 0x0605); /* set graphics mode */ + + for (i = 0; i < sizeof(font); i += 16) { + for (j = 0; j < 16; j++) { + __asm__ volatile("eieio"); + font_page[(2*i)+j] = font[i+j]; + } + } +} + +static void +unlockS3(void) +{ + int s3_device_id; + outw(0x3d4, 0x3848); + outw(0x3d4, 0x39a5); + outb(0x3d4, 0x2d); + s3_device_id = inb(0x3d5) << 8; + outb(0x3d4, 0x2e); + s3_device_id |= inb(0x3d5); + + if (s3_device_id != 0x8812) { + /* From the S3 manual */ + outb(0x46E8, 0x10); /* Put into setup mode */ + outb(0x3C3, 0x10); + outb(0x102, 0x01); /* Enable registers */ + outb(0x46E8, 0x08); /* Enable video */ + outb(0x3C3, 0x08); + outb(0x4AE8, 0x00); + +#if 0 + outb(0x42E8, 0x80); /* Reset graphics engine? */ +#endif + + outb(0x3D4, 0x38); /* Unlock all registers */ + outb(0x3D5, 0x48); + outb(0x3D4, 0x39); + outb(0x3D5, 0xA5); + outb(0x3D4, 0x40); + outb(0x3D5, inb(0x3D5)|0x01); + outb(0x3D4, 0x33); + outb(0x3D5, inb(0x3D5)&~0x52); + outb(0x3D4, 0x35); + outb(0x3D5, inb(0x3D5)&~0x30); + outb(0x3D4, 0x3A); + outb(0x3D5, 0x00); + outb(0x3D4, 0x53); + outb(0x3D5, 0x00); + outb(0x3D4, 0x31); + outb(0x3D5, inb(0x3D5)&~0x4B); + outb(0x3D4, 0x58); + + outb(0x3D5, 0); + + outb(0x3D4, 0x54); + outb(0x3D5, 0x38); + outb(0x3D4, 0x60); + outb(0x3D5, 0x07); + outb(0x3D4, 0x61); + outb(0x3D5, 0x80); + outb(0x3D4, 0x62); + outb(0x3D5, 0xA1); + outb(0x3D4, 0x69); /* High order bits for cursor address */ + outb(0x3D5, 0); + + outb(0x3D4, 0x32); + outb(0x3D5, inb(0x3D5)&~0x10); + } else { + outw(0x3c4, 0x0806); /* IBM Portable 860 */ + outw(0x3c4, 0x1041); + outw(0x3c4, 0x1128); + outw(0x3d4, 0x4000); + outw(0x3d4, 0x3100); + outw(0x3d4, 0x3a05); + outw(0x3d4, 0x6688); + outw(0x3d4, 0x5800); /* disable linear addressing */ + outw(0x3d4, 0x4500); /* disable H/W cursor */ + outw(0x3c4, 0x5410); /* enable auto-centering */ + outw(0x3c4, 0x561f); + outw(0x3c4, 0x1b80); /* lock DCLK selection */ + outw(0x3d4, 0x3900); /* lock S3 registers */ + outw(0x3d4, 0x3800); + } /* endif */ +} + +/* + * cursor() sets an offset (0-1999) into the 80x25 text area + */ +void +cursor(int x, int y) +{ + int pos = (y*cols)+x; + outb(0x3D4, 14); + outb(0x3D5, pos >> 8); + outb(0x3D4, 15); + outb(0x3D5, pos); +} + +void +clearVideoMemory() +{ + int i, j; + for (i = 0; i < lines; i++) { + for (j = 0; j < cols; j++) { + vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */ + vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */ + } + } +} + +/* ============ */ + + +#define NSLOTS 8 +#define NPCIREGS 5 + + +/* + should use devfunc number/indirect method to be totally safe on + all machines, this works for now on 3 slot Moto boxes +*/ + +struct PCI_ConfigInfo { + unsigned long * config_addr; + unsigned long regs[NPCIREGS]; +} PCI_slots [NSLOTS] = { + + { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */ + { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */ + { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */ + { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */ +}; + + + +/* + * The following code modifies the PCI Command register + * to enable memory and I/O accesses. + */ +void +unlockVideo(int slot) +{ + volatile unsigned char * ppci; + + ppci = (unsigned char * )PCI_slots[slot].config_addr; + ppci[4] = 0x0003; /* enable memory and I/O accesses */ + ppci[0x10] = 0x00000; /* turn off memory mapping */ + ppci[0x11] = 0x00000; /* mem_base = 0 */ + ppci[0x12] = 0x00000; + ppci[0x13] = 0x00000; + __asm__ volatile("eieio"); + + outb(0x3d4, 0x11); + outb(0x3d5, 0x0e); /* unlock CR0-CR7 */ +} + +long +SwapBytes(long lv) /* turn little endian into big indian long */ +{ + long t; + t = (lv&0x000000FF) << 24; + t |= (lv&0x0000FF00) << 8; + t |= (lv&0x00FF0000) >> 8; + t |= (lv&0xFF000000) >> 24; + return(t); +} + + +#define DEVID 0 +#define CMD 1 +#define CLASS 2 +#define MEMBASE 4 + +int +scanPCI(int start_slt) +{ + int slt, r; + struct PCI_ConfigInfo *pslot; + int theSlot = -1; + int highVgaSlot = 0; + + for ( slt = start_slt + 1; slt < NSLOTS; slt++) { + pslot = &PCI_slots[slt]; + for ( r = 0; r < NPCIREGS; r++) { + pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); + } + /* card in slot ? */ + if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { + /* VGA ? */ + if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || + ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { + highVgaSlot = slt; + /* did firmware enable it ? */ + if ( (pslot->regs[CMD] & 0x03) ) { + theSlot = slt; + break; + } + } + } + } + + return ( theSlot ); +} + +/* return Vendor ID of card in the slot */ +static +int PCIVendor(int slotnum) { + struct PCI_ConfigInfo *pslot; + + pslot = &PCI_slots[slotnum]; + +return (pslot->regs[DEVID] & 0xFFFF); +} + +#ifdef DEBUG +static +void printslots(void) +{ + int i; +#if 0 + struct PCI_ConfigInfo *pslot; +#endif + for(i=0; i < NSLOTS; i++) { +#if 0 + pslot = &PCI_slots[i]; + printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n", + i, pslot->config_addr, pslot->regs[0], pslot->regs[2]); +#else + puts("PCI Slot number: "); puthex(i); + puts(" Vendor ID: "); + puthex(PCIVendor(i)); puts("\n"); +#endif + } +} +#endif /* DEBUG */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/size linux/arch/ppc/boot/size --- v2.4.4/linux/arch/ppc/boot/size Wed Sep 30 10:14:16 1998 +++ linux/arch/ppc/boot/size Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` -echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/Makefile linux/arch/ppc/boot/tree/Makefile --- v2.4.4/linux/arch/ppc/boot/tree/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/Makefile Thu May 24 15:02:07 2001 @@ -0,0 +1,65 @@ +# BK Id: SCCS/s.Makefile 1.5 05/18/01 06:20:29 patch +# +# +# Module name: Makefile +# +# Description: +# Makefile for the IBM "tree" evaluation board Linux kernel +# boot loaders. +# +# +# Copyright (c) 1999 Grant Erickson +# +# PPC-405 modification +# Copyright 2000-2001 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# frank_rowand@mvista.com or source@mvista.com +# debbie_chu@mvista.com +# + +HOSTCFLAGS = -O -I$(TOPDIR)/include + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump + +GZIP = gzip -vf9 +RM = rm -f +MKEVIMG = ../utils/mkevimg -l +MKIRIMG = ../utils/mkirimg +LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic + +OBJS = ../common/crt0.o main.o misc.o irSect.o ../common/string.o \ + ../common/misc-common.o +LIBS = ../lib/zlib.a + +treeboot: $(OBJS) $(LIBS) ld.script + $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) + +zImage: vmlinux.img + +zImage.initrd: vmlinux.initrd.img + +treeboot.image: treeboot + $(OBJCOPY) --add-section=image=../images/vmlinux.gz treeboot $@ + +treeboot.initrd: treeboot.image ramdisk.image.gz + $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ + +vmlinux.img: treeboot.image + $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt + $(MKEVIMG) treeboot.image.out ../images/vmlinux.tree.img + $(RM) treeboot.image treeboot.image.out irSectStart.txt + +vmlinux.initrd.img: treeboot.initrd + $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt + $(MKEVIMG) treeboot.initrd.out ../images/vmlinux.tree.initrd.img + $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt + +clean: + rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/irSect.c linux/arch/ppc/boot/tree/irSect.c --- v2.4.4/linux/arch/ppc/boot/tree/irSect.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/irSect.c Thu May 24 15:02:07 2001 @@ -0,0 +1,39 @@ +/* + * BK Id: SCCS/s.irSect.c 1.6 05/18/01 15:17:22 cort + */ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.c + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#include "irSect.h" + + +/* + * The order of globals below must not change. If more globals are added, + * you must change the script 'mkirimg' accordingly. + * + */ + +/* + * irSectStart must be at beginning of file + */ +unsigned int irSectStart = 0xdeadbeaf; + +unsigned int imageSect_start = 0; +unsigned int imageSect_size = 0; +unsigned int initrdSect_start = 0; +unsigned int initrdSect_size = 0; + +/* + * irSectEnd must be at end of file + */ +unsigned int irSectEnd = 0xdeadbeaf; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/irSect.h linux/arch/ppc/boot/tree/irSect.h --- v2.4.4/linux/arch/ppc/boot/tree/irSect.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/irSect.h Thu May 24 15:02:07 2001 @@ -0,0 +1,35 @@ +/* + * BK Id: SCCS/s.irSect.h 1.6 05/18/01 15:17:22 cort + */ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.h + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#ifndef __IRSECT_H__ +#define __IRSECT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int imageSect_start; +extern unsigned int imageSect_size; + +extern unsigned int initrdSect_start; +extern unsigned int initrdSect_size; + + +#ifdef __cplusplus +} +#endif + +#endif /* __IRSECT_H__ */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/ld.script linux/arch/ppc/boot/tree/ld.script --- v2.4.4/linux/arch/ppc/boot/tree/ld.script Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/ld.script Thu May 24 15:02:07 2001 @@ -0,0 +1,68 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.rodata) + *(.rodata1) + *(.got1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _etext = .; + PROVIDE (etext = .); + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/main.c linux/arch/ppc/boot/tree/main.c --- v2.4.4/linux/arch/ppc/boot/tree/main.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/main.c Thu May 24 15:02:07 2001 @@ -0,0 +1,248 @@ +/* + * BK Id: SCCS/s.main.c 1.7 05/18/01 06:20:29 patch + */ +/* + * Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for an ELF-based IBM evaluation board version. + * Copyright 2000-2001 MontaVista Software Inc. + * PPC405GP modifications + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * + * Module name: main.c + * + * Description: + * This module does most of the real work for the boot loader. It + * checks the variables holding the absolute start address and size + * of the Linux kernel "image" and initial RAM disk "initrd" sections + * and if they are present, moves them to their "proper" locations. + * + * For the Linux kernel, "proper" is physical address 0x00000000. + * For the RAM disk, "proper" is the image's size below the top + * of physical memory. The Linux kernel may be in either raw + * binary form or compressed with GNU zip (aka gzip). + * + * 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. + * + */ + +#include +#include + +#include "nonstdio.h" +#include "irSect.h" +#if defined(CONFIG_SERIAL_CONSOLE) +#include "ns16550.h" +#endif /* CONFIG_SERIAL_CONSOLE */ + + +/* Preprocessor Defines */ + +/* + * Location of the IBM boot ROM function pointer address for retrieving + * the board information structure. + */ + +#define BOARD_INFO_VECTOR 0xFFFE0B50 + +/* + * Warning: the board_info doesn't contain valid data until get_board_info() + * gets called in start(). + */ +#define RAM_SIZE board_info.bi_memsize + +#define RAM_PBASE 0x00000000 +#define RAM_PEND (RAM_PBASE + RAM_SIZE) + +#define RAM_VBASE 0xC0000000 +#define RAM_VEND (RAM_VBASE + RAM_SIZE) + +#define RAM_START RAM_PBASE +#define RAM_END RAM_PEND +#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) + +#define PROG_START RAM_START + + +/* Function Macros */ + +#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + +#define stringify(s) tostring(s) +#define tostring(s) #s + +#define mtdcr(rn, v) asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v)) +#define mfdcr(rn) ({unsigned int rval; \ + asm volatile("mfdcr %0," stringify(rn) \ + : "=r" (rval)); rval;}) +#define DCRN_MALCR 0x180 /* MAL Configuration */ +#define MALCR_SR 0x80000000 /* Software Reset */ + +/* Global Variables */ + +/* Needed by zalloc and zfree for allocating memory */ + +char *avail_ram; /* Indicates start of RAM available for heap */ +char *end_avail; /* Indicates end of RAM available for heap */ + +bd_t board_info; + +/* + * XXX - Until either the IBM boot ROM provides a way of passing arguments to + * the program it launches or until I/O is working in the boot loader, + * this is a good spot to pass in command line arguments to the kernel + * (e.g. console=tty0). + */ + + +/* +** The bootrom may change bootrom_cmdline to point to a buffer in the +** bootrom. +*/ +char *bootrom_cmdline = ""; +char treeboot_bootrom_cmdline[512]; + +#ifdef CONFIG_CMDLINE +char *cmdline = CONFIG_CMDLINE; +#else +char *cmdline = ""; +#endif + +/* Function Prototypes */ + +extern void *zalloc(void *x, unsigned items, unsigned size); + +/* serial I/O functions. + * These should have generic names, although this is similar to 16550.... + */ +static volatile unsigned char *uart0_lsr = (unsigned char *)0xef600305; +static volatile unsigned char *uart0_xcvr = (unsigned char *)0xef600300; + +void +serial_putc(void *unused, unsigned char c) +{ + while ((*uart0_lsr & LSR_THRE) == 0); + *uart0_xcvr = c; +} + +unsigned char +serial_getc(void *unused) +{ + while ((*uart0_lsr & LSR_DR) == 0); + return (*uart0_xcvr); +} + +int +serial_tstc(void *unused) +{ + return ((*uart0_lsr & LSR_DR) != 0); +} + + +void start(void) +{ + void *options; + int ns, oh, i; + unsigned long sa, len; + void *dst; + unsigned char *im; + unsigned long initrd_start, initrd_size; + bd_t *(*get_board_info)(void) = + (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); + bd_t *bip = NULL; + volatile unsigned long *em0mr0 = (long *)0xEF600800; /* ftr fixup */ + + + +#if defined(CONFIG_WALNUT) + /* turn off ethernet */ + /* This is to fix a problem with early walnut bootrom. */ + + mtdcr(DCRN_MALCR, MALCR_SR); /* 1st reset MAL */ + + while (mfdcr(DCRN_MALCR) & MALCR_SR) {}; /* wait for the reset */ + + *em0mr0 = 0x20000000; /* then reset EMAC */ +#endif + + +#if 0 + /* ftr revisit - remove printf()s */ + + printf("\n\nbootrom_cmdline = >%s<\n\n", bootrom_cmdline); + if (*bootrom_cmdline != '\0') { + printf("bootrom_cmdline != NULL, copying it into cmdline\n\n"); + *treeboot_bootrom_cmdline = '\0'; + strcat(treeboot_bootrom_cmdline, bootrom_cmdline); + cmdline = treeboot_bootrom_cmdline; + } +#endif + + + if ((bip = get_board_info()) != NULL) + memcpy(&board_info, bip, sizeof(bd_t)); + + /* Init RAM disk (initrd) section */ + + if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + + _printk("Initial RAM disk at 0x%08x (%u bytes)\n", + initrd_start, initrd_size); + + memcpy((char *)initrd_start, + (char *)(initrdSect_start), + initrdSect_size); + + end_avail = (char *)initrd_start; + } else { + initrd_start = initrd_size = 0; + end_avail = (char *)RAM_END; + } + + /* Linux kernel image section */ + + im = (unsigned char *)(imageSect_start); + len = imageSect_size; + dst = (void *)PROG_START; + + /* Check for the gzip archive magic numbers */ + + if (im[0] == 0x1f && im[1] == 0x8b) { + + /* The gunzip routine needs everything nice and aligned */ + + void *cp = (void *)ALIGN_UP(RAM_FREE, 8); + avail_ram = (void *)(cp + ALIGN_UP(len, 8)); /* used by zalloc() */ + memcpy(cp, im, len); + + /* I'm not sure what the 0x200000 parameter is for, but it works. */ + /* It tells gzip the end of the area you wish to reserve, and it + * can use data past that point....unfortunately, this value + * isn't big enough (luck ran out). -- Dan + */ + + gunzip(dst, 0x400000, cp, (int *)&len); + } else { + memmove(dst, im, len); + } + + + flush_cache(dst, len); + + sa = (unsigned long)dst; + + (*(void (*)())sa)(&board_info, + initrd_start, + initrd_start + initrd_size, + cmdline, + cmdline + strlen(cmdline)); + + pause(); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/tree/misc.S linux/arch/ppc/boot/tree/misc.S --- v2.4.4/linux/arch/ppc/boot/tree/misc.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/tree/misc.S Thu May 24 15:02:07 2001 @@ -0,0 +1,43 @@ +/* + * BK Id: SCCS/s.misc.S 1.7 05/18/01 06:20:29 patch + */ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + +#include "../../kernel/ppc_asm.tmpl" + + .text + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + mfpvr r5 # Get processor version register + extrwi r5,r5,16,0 # Get the version bits + cmpwi cr0,r5,0x0020 # Is this a 403-based processor? + beq 1f # Yes, it is + li r5,32 # It is not a 403, set to 32 bytes + addi r4,r4,32-1 # len += line_size - 1 + srwi. r4,r4,5 # Convert from bytes to lines + b 2f +1: li r5,16 # It is a 403, set to 16 bytes + addi r4,r4,16-1 # len += line_size - 1 + srwi. r4,r4,4 # Convert from bytes to lines +2: mtctr r4 # Set-up the counter register + beqlr # If it is 0, we are done +3: dcbf r0,r3 # Flush and invalidate the data line + icbi r0,r3 # Invalidate the instruction line + add r3,r3,r5 # Move to the next line + bdnz 3b # Are we done yet? + sync + isync + blr # Return to the caller diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/Makefile linux/arch/ppc/boot/utils/Makefile --- v2.4.4/linux/arch/ppc/boot/utils/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/Makefile Thu May 24 15:02:07 2001 @@ -0,0 +1,19 @@ +# +# arch/ppc/boot/utils/Makefile +# +# 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. + +HOSTCFLAGS += -I$(TOPDIR)/arch/$(ARCH)/boot/include + +# Simple programs with 1 file and no extra CFLAGS +UTILS = addnote hack-coff mkprep mksimage mknote piggyback mkpmon mkbugboot + +$(UTILS): + $(HOSTCC) $(HOSTCFLAGS) -o $@ $@.c + +clean: + rm -f $(UTILS) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/addnote.c linux/arch/ppc/boot/utils/addnote.c --- v2.4.4/linux/arch/ppc/boot/utils/addnote.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/addnote.c Thu May 24 15:02:07 2001 @@ -0,0 +1,177 @@ +/* + * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort + */ +/* + * Program to hack in a PT_NOTE program header entry in an ELF file. + * This is needed for OF on RS/6000s to load an image correctly. + * Note that OF needs a program header entry for the note, not an + * ELF section. + * + * Copyright 2000 Paul Mackerras. + * + * 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. + * + * Usage: addnote zImage + */ +#include +#include +#include +#include + +char arch[] = "PowerPC"; + +#define N_DESCR 6 +unsigned int descr[N_DESCR] = { +#if 1 + /* values for IBM RS/6000 machines */ + 0xffffffff, /* real-mode = true */ + 0x00c00000, /* real-base, i.e. where we expect OF to be */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x4000, /* load-base */ +#else + /* values for longtrail CHRP */ + 0, /* real-mode = false */ + 0xffffffff, /* real-base */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x00600000, /* load-base */ +#endif +}; + +unsigned char buf[512]; + +#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) +#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) + +#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ + PUT_16BE((off) + 2, (v))) + +/* Structure of an ELF file */ +#define E_IDENT 0 /* ELF header */ +#define E_PHOFF 28 +#define E_PHENTSIZE 42 +#define E_PHNUM 44 +#define E_HSIZE 52 /* size of ELF header */ + +#define EI_MAGIC 0 /* offsets in E_IDENT area */ +#define EI_CLASS 4 +#define EI_DATA 5 + +#define PH_TYPE 0 /* ELF program header */ +#define PH_OFFSET 4 +#define PH_FILESZ 16 +#define PH_HSIZE 32 /* size of program header */ + +#define PT_NOTE 4 /* Program header type = note */ + +#define ELFCLASS32 1 +#define ELFDATA2MSB 2 + +unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; + +int main(int ac, char **av) +{ + int fd, n, i; + int ph, ps, np; + int nnote, ns; + + if (ac != 2) { + fprintf(stderr, "Usage: %s elf-file\n", av[0]); + exit(1); + } + fd = open(av[1], O_RDWR); + if (fd < 0) { + perror(av[1]); + exit(1); + } + + nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; + + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + perror("read"); + exit(1); + } + + if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + goto notelf; + + if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 + || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { + fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", + av[1]); + exit(1); + } + + ph = GET_32BE(E_PHOFF); + ps = GET_16BE(E_PHENTSIZE); + np = GET_16BE(E_PHNUM); + if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) + goto notelf; + if (ph + (np + 1) * ps + nnote > n) + goto nospace; + + for (i = 0; i < np; ++i) { + if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { + fprintf(stderr, "%s already has a note entry\n", + av[1]); + exit(0); + } + ph += ps; + } + + /* XXX check that the area we want to use is all zeroes */ + for (i = 0; i < ps + nnote; ++i) + if (buf[ph + i] != 0) + goto nospace; + + /* fill in the program header entry */ + ns = ph + ps; + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote); + + /* fill in the note area we point to */ + /* XXX we should probably make this a proper section */ + PUT_32BE(ns, strlen(arch) + 1); + PUT_32BE(ns + 4, N_DESCR * 4); + PUT_32BE(ns + 8, 0x1275); + strcpy(&buf[ns + 12], arch); + ns += 12 + strlen(arch) + 1; + for (i = 0; i < N_DESCR; ++i) + PUT_32BE(ns + i * 4, descr[i]); + + /* Update the number of program headers */ + PUT_16BE(E_PHNUM, np + 1); + + /* write back */ + lseek(fd, (long) 0, SEEK_SET); + i = write(fd, buf, n); + if (i < 0) { + perror("write"); + exit(1); + } + if (i < n) { + fprintf(stderr, "%s: write truncated\n", av[1]); + exit(1); + } + + exit(0); + + notelf: + fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); + exit(1); + + nospace: + fprintf(stderr, "sorry, I can't find space in %s to put the note\n", + av[0]); + exit(1); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/elf.pl linux/arch/ppc/boot/utils/elf.pl --- v2.4.4/linux/arch/ppc/boot/utils/elf.pl Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/elf.pl Thu May 24 15:02:07 2001 @@ -0,0 +1,33 @@ +# +# ELF header field numbers +# + +$e_ident = 0; # Identification bytes / magic number +$e_type = 1; # ELF file type +$e_machine = 2; # Target machine type +$e_version = 3; # File version +$e_entry = 4; # Start address +$e_phoff = 5; # Program header file offset +$e_shoff = 6; # Section header file offset +$e_flags = 7; # File flags +$e_ehsize = 8; # Size of ELF header +$e_phentsize = 9; # Size of program header +$e_phnum = 10; # Number of program header entries +$e_shentsize = 11; # Size of section header +$e_shnum = 12; # Number of section header entries +$e_shstrndx = 13; # Section header table string index + +# +# Section header field numbers +# + +$sh_name = 0; # Section name +$sh_type = 1; # Section header type +$sh_flags = 2; # Section header flags +$sh_addr = 3; # Virtual address +$sh_offset = 4; # File offset +$sh_size = 5; # Section size +$sh_link = 6; # Miscellaneous info +$sh_info = 7; # More miscellaneous info +$sh_addralign = 8; # Memory alignment +$sh_entsize = 9; # Entry size if this is a table diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/hack-coff.c linux/arch/ppc/boot/utils/hack-coff.c --- v2.4.4/linux/arch/ppc/boot/utils/hack-coff.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/hack-coff.c Thu May 24 15:02:07 2001 @@ -0,0 +1,85 @@ +/* + * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch + */ +/* + * hack-coff.c - hack the header of an xcoff file to fill in + * a few fields needed by the Open Firmware xcoff loader on + * Power Macs but not initialized by objcopy. + * + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ +#include +#include +#include +#include "rs6000.h" + +#define AOUT_MAGIC 0x010b + +#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \ + + ((unsigned char *)(x))[1]) +#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \ + ((unsigned char *)(x))[1] = (v) & 0xff) +#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \ + + (((unsigned char *)(x))[1] << 16) \ + + (((unsigned char *)(x))[2] << 8) \ + + ((unsigned char *)(x))[3]) + +int +main(int ac, char **av) +{ + int fd; + int i, nsect; + int aoutsz; + struct external_filehdr fhdr; + AOUTHDR aout; + struct external_scnhdr shdr; + + if (ac != 2) { + fprintf(stderr, "Usage: hack-coff coff-file\n"); + exit(1); + } + if ((fd = open(av[1], 2)) == -1) { + perror(av[2]); + exit(1); + } + if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr)) + goto readerr; + i = get_16be(fhdr.f_magic); + if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) { + fprintf(stderr, "%s: not an xcoff file\n", av[1]); + exit(1); + } + aoutsz = get_16be(fhdr.f_opthdr); + if (read(fd, &aout, aoutsz) != aoutsz) + goto readerr; + nsect = get_16be(fhdr.f_nscns); + for (i = 0; i < nsect; ++i) { + if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) + goto readerr; + if (strcmp(shdr.s_name, ".text") == 0) { + put_16be(aout.o_snentry, i+1); + put_16be(aout.o_sntext, i+1); + } else if (strcmp(shdr.s_name, ".data") == 0) { + put_16be(aout.o_sndata, i+1); + } else if (strcmp(shdr.s_name, ".bss") == 0) { + put_16be(aout.o_snbss, i+1); + } + } + put_16be(aout.magic, AOUT_MAGIC); + if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1 + || write(fd, &aout, aoutsz) != aoutsz) { + fprintf(stderr, "%s: write error\n", av[1]); + exit(1); + } + close(fd); + exit(0); + +readerr: + fprintf(stderr, "%s: read error or file too short\n", av[1]); + exit(1); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/mkevimg linux/arch/ppc/boot/utils/mkevimg --- v2.4.4/linux/arch/ppc/boot/utils/mkevimg Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/mkevimg Thu May 24 15:02:07 2001 @@ -0,0 +1,437 @@ +#!/usr/bin/perl + +# +# Copyright (c) 1998-1999 TiVo, Inc. +# All rights reserved. +# +# Copyright (c) 1999 Grant Erickson +# Major syntactic and usability rework. +# +# Module name: mkevimg +# +# Description: +# Converts an ELF output file from the linker into the format used by +# the IBM evaluation board ROM Monitor to load programs from a host +# onto the evaluation board. The ELF file must be an otherwise execut- +# able file (with the text and data addresses bound at link time) and +# have space reserved after the entry point for the load information +# block: +# +# typedef struct boot_block { +# unsigned long magic; 0x0052504F +# unsigned long dest; Target address of the image +# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks +# unsigned long debug_flag; Run the debugger or image after load +# unsigned long entry_point; The image address to jump to after load +# unsigned long reserved[3]; +# } boot_block_t; +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hlvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkevimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hlvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_l) { + $linux = 1; + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ifile = shift(@ARGV))) { + usage(1); + } + + if (!($ofile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ifile)) { + exit(1); + } + +} + +# +# ELF file and section header field numbers +# + +require '../utils/elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + + decode_options(); + + open(ELF, "<$ifile") || die "Cannot open input file"; + + $ifilesize = (-s $ifile); + + if ($verbose) { + print("Output file: $ofile\n"); + print("Input file: $ifile, $ifilesize bytes.\n"); + } + + if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { + print("Failed to read input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ifile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); + exit (1); + } + + if ($verbose) { + print("File header:\n"); + printf(" Identifier: %s\n", $eh[$e_ident]); + printf(" Type: %d\n", $eh[$e_type]); + printf(" Machine: %d\n", $eh[$e_machine]); + printf(" Version: %d\n", $eh[$e_version]); + printf(" Entry point: 0x%08x\n", $eh[$e_entry]); + printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); + printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); + printf(" Flags: 0x%08x\n", $eh[$e_flags]); + printf(" Header size: %d\n", $eh[$e_ehsize]); + printf(" Program entry size: %d\n", $eh[$e_phentsize]); + printf(" Program table entries: %d\n", $eh[$e_phnum]); + printf(" Section header size: %d\n", $eh[$e_shentsize]); + printf(" Section table entries: %d\n", $eh[$e_shnum]); + printf(" String table section: %d\n", $eh[$e_shstrndx]); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.text' and '.bss' sections in + # particular. + + if ($verbose) { + print("Section headers:\n"); + print("Idx Name Size Address File off Algn\n"); + print("--- ------------------------ -------- -------- -------- ----\n"); + } + + $off = $eh[$e_shoff]; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + if ($verbose) { + printf("%3d %-24s %8x %08x %08x %4d\n", + $i, $name, $sh[$sh_size], $sh[$sh_addr], + $sh[$sh_offset], $sh[$sh_addralign]); + } + + # Attempt to find the .text and .bss sections + + if ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.text$/) { + ($text_addr, $text_offset, $text_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\image$/)) { + $image_found = 1; + + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\initrd$/)) { + $initrd_found = 1; + + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + printf("Text section - Address: 0x%08x, Size: 0x%08x\n", + $text_addr, $text_size); + printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", + $bss_addr, $bss_size); + + if ($linux) { + if ($image_found) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } + + if ($initrd_found) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } + } + + # + # Open output file + # + + open(BOOT, ">$ofile") || die "Cannot open output file"; + + # + # Compute image size + # + + $output_size = $bss_offset - $text_offset + $bss_size; + + if ($linux && $image_found) { + $output_size += $image_size; + } + + if ($linux && $initrd_found) { + $output_size += $initrd_size; + } + + $num_blocks = $output_size / 512 + 1; + + # + # Write IBM PowerPC evaluation board boot_block_t header + # + + $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, + $text_addr, 0, 0, 0); + + $bytes = length($header); + + if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { + die("Could not write boot image header to output file."); + } + + printf("Entry point = 0x%08x\n", $text_addr); + printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", + $output_size, $output_size, $num_blocks); + + # + # Write image starting after ELF and program headers and + # continuing to beginning of bss + # + + $bytes = $bss_offset - $text_offset + $bss_size; + + if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + + # + # If configured, write out the image and initrd sections as well + # + + if ($linux) { + if ($image_found) { + $bytes = $image_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + + if ($initrd_found) { + $bytes = $initrd_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + } + + # + # Pad to a multiple of 512 bytes + # + + $pad_size = 512 - (length($header) + $output_size) % 512; + + if ($verbose) { + print("Padding boot image by an additional $pad_size bytes.\n"); + } + + $pad_string = pack(("H8","deadbeef") x 128); + + syswrite(BOOT, $pad_string, $pad_size) or + die "Could not pad boot image in output file.\n"; + + # + # Clean-up and leave + # + + close(BOOT); + + print("\nBoot image file \"$ofile\" built successfully.\n\n"); + + exit(0); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/mkirimg linux/arch/ppc/boot/utils/mkirimg --- v2.4.4/linux/arch/ppc/boot/utils/mkirimg Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/mkirimg Thu May 24 15:02:07 2001 @@ -0,0 +1,367 @@ +#!/usr/bin/perl +# +# Copyright (c) 1998-1999 TiVo, Inc. +# Original ELF parsing code. +# +# Copyright (c) 1999 Grant Erickson +# Original code from 'mkevimg'. +# +# Module name: mkirimg +# +# Description: +# Reads an ELF file and assigns global variables 'imageSect_start', +# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from +# the "image" and "initrd" section header information. It then +# rewrites the input ELF file with assigned globals to an output +# file. +# +# An input file, "irSectStart.txt" has the memory address of +# 'irSectStart'. The irSectStart memory address is used to find +# the global variables in the ".data" section of the ELF file. +# The 'irSectStart' and the above global variables are defined +# in "irSect.c". +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkirimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ElfFile = shift(@ARGV))) { + usage(1); + } + + if (!($OutputFile = shift(@ARGV))) { + usage (1); + } + + if (!($IrFile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ElfFile)) { + exit(1); + } + + if (file_check($IrFile)) { + exit(1); + } +} + +# +# ELF file and section header field numbers +# + +require '../utils/elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + decode_options(); + + open(ELF, "<$ElfFile") || die "Cannot open input file"; + open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; + open(IR, "$IrFile") || die "Cannot open input file"; + + $ElfFilesize = (-s $ElfFile); + + if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { + print("Failed to read ELF input file!\n"); + exit(1); + } + + if (read(IR, $irbuf, 8) != 8) { + print("Failed to read Ir input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ElfFile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); + exit (1); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.data', 'image', and + # 'initrd' sections in particular. + + $off = $eh[$e_shoff]; + $imageFound = 0; + $initrdFound = 0; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + # Attempt to find the .data, image, and initrd sections + + if ($name =~ /^\image$/) { + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $imageFound = 1; + + } elsif ($name =~ /^\initrd$/) { + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $initrdFound = 1; + + } elsif ($name =~ /^\.data$/) { + ($data_addr, $data_offset, $data_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + if ($verbose) { + printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $data_addr, $data_size, $data_offset); + printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $bss_addr, $bss_size, $bss_offset); + } + + if ($verbose) { + if ($imageFound) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } else { + printf("Image section not found in file: $ElfFile\n"); + } + + if ($initrdFound) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } else { + printf("Initrd section not found in file: $ElfFile\n"); + } + } + + # get file offset of irSectStart + + $irSectStartoffset = hex ($irbuf); + + if ($verbose) { + printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); + } + + # get the offset of global variables + + $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; + + # write modified values to OUTPUT file + + syswrite(OUTPUT, $ibuf, $initialOffset); + + if ($imageFound) { + $testN = pack ("N2", $bss_addr + $bss_size, $image_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"imageSect_start\" to 0x%08x\n", + $bss_addr + $bss_size); + printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); + } else { + syswrite(OUTPUT, $ibuf, 8, $initialOffset); + } + + if ($initrdFound) { + $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", + $bss_addr + $bss_size + $image_size); + printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); + } else { + syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); + } + + syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), + $initialOffset + 16); + + # + # Clean-up and leave + # + + close (ELF); + close (OUTPUT); + close (IR); + + exit (0); +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/mknote.c linux/arch/ppc/boot/utils/mknote.c --- v2.4.4/linux/arch/ppc/boot/utils/mknote.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/mknote.c Thu May 24 15:02:07 2001 @@ -0,0 +1,46 @@ +/* + * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort + */ +/* + * Copyright (C) Cort Dougan 1999. + * + * 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. + * + * Generate a note section as per the CHRP specification. + * + */ + +#include + +#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); + +int main(void) +{ +/* header */ + /* namesz */ + PL(strlen("PowerPC")+1); + /* descrsz */ + PL(6*4); + /* type */ + PL(0x1275); + /* name */ + printf("PowerPC"); printf("%c", 0); + +/* descriptor */ + /* real-mode */ + PL(0xffffffff); + /* real-base */ + PL(0x00c00000); + /* real-size */ + PL(0xffffffff); + /* virt-base */ + PL(0xffffffff); + /* virt-size */ + PL(0xffffffff); + /* load-base */ + PL(0x4000); + return 0; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/mkprep.c linux/arch/ppc/boot/utils/mkprep.c --- v2.4.4/linux/arch/ppc/boot/utils/mkprep.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/mkprep.c Thu May 24 15:02:07 2001 @@ -0,0 +1,292 @@ +/* + * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch + */ +/* + * Makes a prep bootable image which can be dd'd onto + * a disk device to make a bootdisk. Will take + * as input a elf executable, strip off the header + * and write out a boot image as: + * 1) default - strips elf header + * suitable as a network boot image + * 2) -pbp - strips elf header and writes out prep boot partition image + * cat or dd onto disk for booting + * 3) -asm - strips elf header and writes out as asm data + * useful for generating data for a compressed image + * -- Cort + * + * Modified for x86 hosted builds by Matt Porter + */ + +#include +#include +#include +#include +#include +#include + +#define cpu_to_le32(x) le32_to_cpu((x)) +unsigned long le32_to_cpu(unsigned long x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24)); +} + + +#define cpu_to_le16(x) le16_to_cpu((x)) +unsigned short le16_to_cpu(unsigned short x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} + +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_be16(x) (x) +#define be16_to_cpu(x) (x) + +/* size of read buffer */ +#define SIZE 0x1000 + + +typedef unsigned long dword_t; +typedef unsigned short word_t; +typedef unsigned char byte_t; +typedef byte_t block_t[512]; +typedef byte_t page_t[4096]; + + +/* + * Partition table entry + * - from the PReP spec + */ +typedef struct partition_entry { + byte_t boot_indicator; + byte_t starting_head; + byte_t starting_sector; + byte_t starting_cylinder; + + byte_t system_indicator; + byte_t ending_head; + byte_t ending_sector; + byte_t ending_cylinder; + + dword_t beginning_sector; + dword_t number_of_sectors; +} partition_entry_t; + +#define BootActive 0x80 +#define SystemPrep 0x41 + +void copy_image(int , int); +void write_prep_partition(int , int ); +void write_asm_data( int in, int out ); + +unsigned int elfhdr_size = 65536; + +int main(int argc, char *argv[]) +{ + int in_fd, out_fd; + int argptr = 1; + unsigned int prep = 0; + unsigned int asmoutput = 0; + + if ( (argc < 3) || (argc > 4) ) + { + fprintf(stderr, "usage: %s [-pbp] [-asm] \n",argv[0]); + exit(-1); + } + + /* needs to handle args more elegantly -- but this is a small/simple program */ + + /* check for -pbp */ + if ( !strcmp( argv[argptr], "-pbp" ) ) + { + prep = 1; + argptr++; + } + + /* check for -asm */ + if ( !strcmp( argv[argptr], "-asm" ) ) + { + asmoutput = 1; + argptr++; + } + + /* input file */ + if ( !strcmp( argv[argptr], "-" ) ) + in_fd = 0; /* stdin */ + else + if ((in_fd = open( argv[argptr] , 0)) < 0) + exit(-1); + argptr++; + + /* output file */ + if ( !strcmp( argv[argptr], "-" ) ) + out_fd = 1; /* stdout */ + else + if ((out_fd = creat( argv[argptr] , 0755)) < 0) + exit(-1); + argptr++; + + /* skip elf header in input file */ + /*if ( !prep )*/ + lseek(in_fd, elfhdr_size, SEEK_SET); + + /* write prep partition if necessary */ + if ( prep ) + write_prep_partition( in_fd, out_fd ); + + /* write input image to bootimage */ + if ( asmoutput ) + write_asm_data( in_fd, out_fd ); + else + copy_image(in_fd, out_fd); + + return 0; +} + +void write_prep_partition(int in, int out) +{ + unsigned char block[512]; + partition_entry_t *pe = (partition_entry_t *)&block[0x1BE]; + dword_t *entry = (dword_t *)&block[0]; + dword_t *length = (dword_t *)&block[sizeof(long)]; + struct stat info; + + if (fstat(in, &info) < 0) + { + fprintf(stderr,"info failed\n"); + exit(-1); + } + + bzero( block, sizeof block ); + + /* set entry point and boot image size skipping over elf header */ +#ifdef __i386__ + *entry = 0x400/*+65536*/; + *length = info.st_size-elfhdr_size+0x400; +#else + *entry = cpu_to_le32(0x400/*+65536*/); + *length = cpu_to_le32(info.st_size-elfhdr_size+0x400); +#endif /* __i386__ */ + + /* sets magic number for msdos partition (used by linux) */ + block[510] = 0x55; + block[511] = 0xAA; + + /* + * Build a "PReP" partition table entry in the boot record + * - "PReP" may only look at the system_indicator + */ + pe->boot_indicator = BootActive; + pe->system_indicator = SystemPrep; + /* + * The first block of the diskette is used by this "boot record" which + * actually contains the partition table. (The first block of the + * partition contains the boot image, but I digress...) We'll set up + * one partition on the diskette and it shall contain the rest of the + * diskette. + */ + pe->starting_head = 0; /* zero-based */ + pe->starting_sector = 2; /* one-based */ + pe->starting_cylinder = 0; /* zero-based */ + pe->ending_head = 1; /* assumes two heads */ + pe->ending_sector = 18; /* assumes 18 sectors/track */ + pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */ + + /* + * The "PReP" software ignores the above fields and just looks at + * the next two. + * - size of the diskette is (assumed to be) + * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette) + * - unlike the above sector numbers, the beginning sector is zero-based! + */ +#if 0 + pe->beginning_sector = cpu_to_le32(1); +#else + /* This has to be 0 on the PowerStack? */ +#ifdef __i386__ + pe->beginning_sector = 0; +#else + pe->beginning_sector = cpu_to_le32(0); +#endif /* __i386__ */ +#endif + +#ifdef __i386__ + pe->number_of_sectors = 2*18*80-1; +#else + pe->number_of_sectors = cpu_to_le32(2*18*80-1); +#endif /* __i386__ */ + + write( out, block, sizeof(block) ); + write( out, entry, sizeof(*entry) ); + write( out, length, sizeof(*length) ); + /* set file position to 2nd sector where image will be written */ + lseek( out, 0x400, SEEK_SET ); +} + + + +void +copy_image(int in, int out) +{ + char buf[SIZE]; + int n; + + while ( (n = read(in, buf, SIZE)) > 0 ) + write(out, buf, n); +} + + +void +write_asm_data( int in, int out ) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[SIZE]; + unsigned char str[256]; + + write( out, "\t.data\n\t.globl input_data\ninput_data:\n", + strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) ); + pos = 0; + cksum = 0; + while ((len = read(in, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + write( out, "\t.long\t", strlen( "\t.long\t" ) ); + } + sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + write( out, str, strlen(str) ); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + sprintf( str, " # %x \n", pos+i-12); + write( out, str, strlen(str) ); + } else + { + write( out, ",", 1 ); + } + } + if (cnt) + { + write( out, "0\n", 2 ); + } + pos += len; + } + sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos); + write( out, str, strlen(str) ); + + fprintf(stderr, "cksum = %x\n", cksum); +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/mksimage.c linux/arch/ppc/boot/utils/mksimage.c --- v2.4.4/linux/arch/ppc/boot/utils/mksimage.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/mksimage.c Thu May 24 15:02:07 2001 @@ -0,0 +1,127 @@ +/* + * BK Id: SCCS/s.mksimage.c 1.6 05/18/01 15:16:42 cort + */ +/* + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SIZE 1024 +#define BLOCK_ALIGN(x) (((x)+SIZE-1)&(~(SIZE-1))) + +static void +die(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + exit(1); +} + +static void +usage(void) +{ + printf("Usage: mkbinimg -o \n"); + exit(1); +} + +static int +copy_blocks(int ifd, int ofd, unsigned long *offset, unsigned long *size) +{ + off_t cur; + int amt; + unsigned long len = 0; + char buffer[SIZE]; + + cur = lseek(ofd, 0, SEEK_CUR); + + if (cur % SIZE) { + cur = BLOCK_ALIGN(cur); + cur = lseek(ofd, cur, SEEK_SET); + } + + *offset = (unsigned long) cur; + while((amt = read(ifd, buffer, SIZE)) > 0) { + write(ofd, buffer, amt); + len += amt; + } + *size = len; + return 0; +} + + +int +main(int argc, char *argv[]) +{ + char *kernel, *loader, *rdimage = NULL; + unsigned long ld_off, kern_off, rd_off; + unsigned long ld_size, kern_size, rd_size; + int fd, ofd, len; + char buffer[500]; + + if (argc < 5 && !strcmp(argv[argc-2], "-o")) + usage(); + + if (argc > 5) + rdimage = argv[3]; + + kernel = argv[2]; + loader = argv[1]; + + ofd = open(argv[argc-1], (O_RDWR|O_CREAT), 0755); + if (ofd < 0) { + die("can't open %s: %s", argv[5], strerror(errno)); + } + + ld_off = kern_off = rd_off = 0; + ld_size = kern_size = rd_size = 0; + memset(buffer, 0, 500); + len = 0; + + fd = open(loader, O_RDONLY); + if (fd < 0) + die("can't open loader: %s", strerror(errno)); + + copy_blocks(fd, ofd, &ld_off, &ld_size); + len = sprintf(buffer, "bootloader: %x %x\n", ld_off, ld_size); + close(fd); + + fd = open(kernel, O_RDONLY); + if (fd < 0) + die("can't open kernel: %s", strerror(errno)); + + copy_blocks(fd, ofd, &kern_off, &kern_size); + len += sprintf(buffer+len, "zimage: %x %x\n", kern_off, kern_size); + close(fd); + + if (rdimage) { + fd = open(rdimage, O_RDONLY); + if (fd < 0) + die("can't get ramdisk: %s", strerror(errno)); + + copy_blocks(fd, ofd, &rd_off, &rd_size); + close(fd); + } + + len += sprintf(buffer+len, "initrd: %x %x", rd_off, rd_size); + + close(ofd); + + printf("%s\n", buffer); + + return 0; +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/offset linux/arch/ppc/boot/utils/offset --- v2.4.4/linux/arch/ppc/boot/utils/offset Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/offset Thu May 24 15:02:07 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/piggyback.c linux/arch/ppc/boot/utils/piggyback.c --- v2.4.4/linux/arch/ppc/boot/utils/piggyback.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/piggyback.c Thu May 24 15:02:07 2001 @@ -0,0 +1,69 @@ +/* + * BK Id: SCCS/s.piggyback.c 1.7 05/18/01 15:17:23 cort + */ +#include +#include + +extern long ce_exec_config[]; + +int main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 2) + { + fprintf(stderr, "usage: %s name out-file\n", + argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl %s_data\n", argv[1]); + fprintf(stdout, "%s_data:\n", argv[1]); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl %s_len\n", argv[1]); + fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/sioffset linux/arch/ppc/boot/utils/sioffset --- v2.4.4/linux/arch/ppc/boot/utils/sioffset Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/sioffset Thu May 24 15:02:07 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/sisize linux/arch/ppc/boot/utils/sisize --- v2.4.4/linux/arch/ppc/boot/utils/sisize Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/sisize Thu May 24 15:02:07 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/utils/size linux/arch/ppc/boot/utils/size --- v2.4.4/linux/arch/ppc/boot/utils/size Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/utils/size Thu May 24 15:02:07 2001 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/boot/vreset.c linux/arch/ppc/boot/vreset.c --- v2.4.4/linux/arch/ppc/boot/vreset.c Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/boot/vreset.c Wed Dec 31 16:00:00 1969 @@ -1,838 +0,0 @@ -/* - * vreset.c - * - * Initialize the VGA control registers to 80x25 text mode. - * - * Adapted from a program by: - * Steve Sellgren - * San Francisco Indigo Company - * sfindigo!sellgren@uunet.uu.net - * - * Original concept by: - * Gary Thomas - * Adapted for Moto boxes by: - * Pat Kane & Mark Scott, 1996 - * Adapted for IBM portables by: - * Takeshi Ishimoto - * Multi-console support: - * Terje Malmedal - */ - -#include "iso_font.h" - -extern char *vidmem; -extern int lines, cols; - -static void mdelay(int ms) -{ - for (; ms > 0; --ms) - udelay(1000); -} - -/* - * VGA Register - */ -struct VgaRegs -{ - unsigned short io_port; - unsigned char io_index; - unsigned char io_value; -}; - -/* - * Default console text mode registers used to reset - * graphics adapter. - */ -#define NREGS 54 -#define ENDMK 0xFFFF /* End marker */ - -#define S3Vendor 0x5333 -#define CirrusVendor 0x1013 -#define DiamondVendor 0x100E -#define MatroxVendor 0x102B -#define ParadiseVendor 0x101C - -struct VgaRegs GenVgaTextRegs[NREGS+1] = { -/* port index value */ - /* SR Regs */ - 0x3c4, 0x1, 0x0, - 0x3c4, 0x2, 0x3, - 0x3c4, 0x3, 0x0, - 0x3c4, 0x4, 0x2, - /* CR Regs */ - 0x3d4, 0x0, 0x5f, - 0x3d4, 0x1, 0x4f, - 0x3d4, 0x2, 0x50, - 0x3d4, 0x3, 0x82, - 0x3d4, 0x4, 0x55, - 0x3d4, 0x5, 0x81, - 0x3d4, 0x6, 0xbf, - 0x3d4, 0x7, 0x1f, - 0x3d4, 0x8, 0x00, - 0x3d4, 0x9, 0x4f, - 0x3d4, 0xa, 0x0d, - 0x3d4, 0xb, 0x0e, - 0x3d4, 0xc, 0x00, - 0x3d4, 0xd, 0x00, - 0x3d4, 0xe, 0x00, - 0x3d4, 0xf, 0x00, - 0x3d4, 0x10, 0x9c, - 0x3d4, 0x11, 0x8e, - 0x3d4, 0x12, 0x8f, - 0x3d4, 0x13, 0x28, - 0x3d4, 0x14, 0x1f, - 0x3d4, 0x15, 0x96, - 0x3d4, 0x16, 0xb9, - 0x3d4, 0x17, 0xa3, - /* GR Regs */ - 0x3ce, 0x0, 0x0, - 0x3ce, 0x1, 0x0, - 0x3ce, 0x2, 0x0, - 0x3ce, 0x3, 0x0, - 0x3ce, 0x4, 0x0, - 0x3ce, 0x5, 0x10, - 0x3ce, 0x6, 0xe, - 0x3ce, 0x7, 0x0, - 0x3ce, 0x8, 0xff, - ENDMK -}; - -struct VgaRegs S3TextRegs[NREGS+1] = { -/* port index value */ - /* SR Regs */ - 0x3c4, 0x1, 0x0, - 0x3c4, 0x2, 0x3, - 0x3c4, 0x3, 0x0, - 0x3c4, 0x4, 0x2, - /* CR Regs */ - 0x3d4, 0x0, 0x5f, - 0x3d4, 0x1, 0x4f, - 0x3d4, 0x2, 0x50, - 0x3d4, 0x3, 0x82, - 0x3d4, 0x4, 0x55, - 0x3d4, 0x5, 0x81, - 0x3d4, 0x6, 0xbf, - 0x3d4, 0x7, 0x1f, - 0x3d4, 0x8, 0x00, - 0x3d4, 0x9, 0x4f, - 0x3d4, 0xa, 0x0d, - 0x3d4, 0xb, 0x0e, - 0x3d4, 0xc, 0x00, - 0x3d4, 0xd, 0x00, - 0x3d4, 0xe, 0x00, - 0x3d4, 0xf, 0x00, - 0x3d4, 0x10, 0x9c, - 0x3d4, 0x11, 0x8e, - 0x3d4, 0x12, 0x8f, - 0x3d4, 0x13, 0x28, - 0x3d4, 0x14, 0x1f, - 0x3d4, 0x15, 0x96, - 0x3d4, 0x16, 0xb9, - 0x3d4, 0x17, 0xa3, - /* GR Regs */ - 0x3ce, 0x0, 0x0, - 0x3ce, 0x1, 0x0, - 0x3ce, 0x2, 0x0, - 0x3ce, 0x3, 0x0, - 0x3ce, 0x4, 0x0, - 0x3ce, 0x5, 0x10, - 0x3ce, 0x6, 0xe, - 0x3ce, 0x7, 0x0, - 0x3ce, 0x8, 0xff, - ENDMK -}; - -struct RGBColors -{ - unsigned char r, g, b; -}; - -/* - * Default console text mode color table. - * These values were obtained by booting Linux with - * text mode firmware & then dumping the registers. - */ -struct RGBColors TextCLUT[256] = -{ - /* red green blue */ - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2a, - 0x0, 0x2a, 0x0, - 0x0, 0x2a, 0x2a, - 0x2a, 0x0, 0x0, - 0x2a, 0x0, 0x2a, - 0x2a, 0x2a, 0x0, - 0x2a, 0x2a, 0x2a, - 0x0, 0x0, 0x15, - 0x0, 0x0, 0x3f, - 0x0, 0x2a, 0x15, - 0x0, 0x2a, 0x3f, - 0x2a, 0x0, 0x15, - 0x2a, 0x0, 0x3f, - 0x2a, 0x2a, 0x15, - 0x2a, 0x2a, 0x3f, - 0x0, 0x15, 0x0, - 0x0, 0x15, 0x2a, - 0x0, 0x3f, 0x0, - 0x0, 0x3f, 0x2a, - 0x2a, 0x15, 0x0, - 0x2a, 0x15, 0x2a, - 0x2a, 0x3f, 0x0, - 0x2a, 0x3f, 0x2a, - 0x0, 0x15, 0x15, - 0x0, 0x15, 0x3f, - 0x0, 0x3f, 0x15, - 0x0, 0x3f, 0x3f, - 0x2a, 0x15, 0x15, - 0x2a, 0x15, 0x3f, - 0x2a, 0x3f, 0x15, - 0x2a, 0x3f, 0x3f, - 0x15, 0x0, 0x0, - 0x15, 0x0, 0x2a, - 0x15, 0x2a, 0x0, - 0x15, 0x2a, 0x2a, - 0x3f, 0x0, 0x0, - 0x3f, 0x0, 0x2a, - 0x3f, 0x2a, 0x0, - 0x3f, 0x2a, 0x2a, - 0x15, 0x0, 0x15, - 0x15, 0x0, 0x3f, - 0x15, 0x2a, 0x15, - 0x15, 0x2a, 0x3f, - 0x3f, 0x0, 0x15, - 0x3f, 0x0, 0x3f, - 0x3f, 0x2a, 0x15, - 0x3f, 0x2a, 0x3f, - 0x15, 0x15, 0x0, - 0x15, 0x15, 0x2a, - 0x15, 0x3f, 0x0, - 0x15, 0x3f, 0x2a, - 0x3f, 0x15, 0x0, - 0x3f, 0x15, 0x2a, - 0x3f, 0x3f, 0x0, - 0x3f, 0x3f, 0x2a, - 0x15, 0x15, 0x15, - 0x15, 0x15, 0x3f, - 0x15, 0x3f, 0x15, - 0x15, 0x3f, 0x3f, - 0x3f, 0x15, 0x15, - 0x3f, 0x15, 0x3f, - 0x3f, 0x3f, 0x15, - 0x3f, 0x3f, 0x3f, - 0x39, 0xc, 0x5, - 0x15, 0x2c, 0xf, - 0x26, 0x10, 0x3d, - 0x29, 0x29, 0x38, - 0x4, 0x1a, 0xe, - 0x2, 0x1e, 0x3a, - 0x3c, 0x25, 0x33, - 0x3c, 0xc, 0x2c, - 0x3f, 0x3, 0x2b, - 0x1c, 0x9, 0x13, - 0x25, 0x2a, 0x35, - 0x1e, 0xa, 0x38, - 0x24, 0x8, 0x3, - 0x3, 0xe, 0x36, - 0xc, 0x6, 0x2a, - 0x26, 0x3, 0x32, - 0x5, 0x2f, 0x33, - 0x3c, 0x35, 0x2f, - 0x2d, 0x26, 0x3e, - 0xd, 0xa, 0x10, - 0x25, 0x3c, 0x11, - 0xd, 0x4, 0x2e, - 0x5, 0x19, 0x3e, - 0xc, 0x13, 0x34, - 0x2b, 0x6, 0x24, - 0x4, 0x3, 0xd, - 0x2f, 0x3c, 0xc, - 0x2a, 0x37, 0x1f, - 0xf, 0x12, 0x38, - 0x38, 0xe, 0x2a, - 0x12, 0x2f, 0x19, - 0x29, 0x2e, 0x31, - 0x25, 0x13, 0x3e, - 0x33, 0x3e, 0x33, - 0x1d, 0x2c, 0x25, - 0x15, 0x15, 0x5, - 0x32, 0x25, 0x39, - 0x1a, 0x7, 0x1f, - 0x13, 0xe, 0x1d, - 0x36, 0x17, 0x34, - 0xf, 0x15, 0x23, - 0x2, 0x35, 0xd, - 0x15, 0x3f, 0xc, - 0x14, 0x2f, 0xf, - 0x19, 0x21, 0x3e, - 0x27, 0x11, 0x2f, - 0x38, 0x3f, 0x3c, - 0x36, 0x2d, 0x15, - 0x16, 0x17, 0x2, - 0x1, 0xa, 0x3d, - 0x1b, 0x11, 0x3f, - 0x21, 0x3c, 0xd, - 0x1a, 0x39, 0x3d, - 0x8, 0xe, 0xe, - 0x22, 0x21, 0x23, - 0x1e, 0x30, 0x5, - 0x1f, 0x22, 0x3d, - 0x1e, 0x2f, 0xa, - 0x0, 0x1c, 0xe, - 0x0, 0x1c, 0x15, - 0x0, 0x1c, 0x1c, - 0x0, 0x15, 0x1c, - 0x0, 0xe, 0x1c, - 0x0, 0x7, 0x1c, - 0xe, 0xe, 0x1c, - 0x11, 0xe, 0x1c, - 0x15, 0xe, 0x1c, - 0x18, 0xe, 0x1c, - 0x1c, 0xe, 0x1c, - 0x1c, 0xe, 0x18, - 0x1c, 0xe, 0x15, - 0x1c, 0xe, 0x11, - 0x1c, 0xe, 0xe, - 0x1c, 0x11, 0xe, - 0x1c, 0x15, 0xe, - 0x1c, 0x18, 0xe, - 0x1c, 0x1c, 0xe, - 0x18, 0x1c, 0xe, - 0x15, 0x1c, 0xe, - 0x11, 0x1c, 0xe, - 0xe, 0x1c, 0xe, - 0xe, 0x1c, 0x11, - 0xe, 0x1c, 0x15, - 0xe, 0x1c, 0x18, - 0xe, 0x1c, 0x1c, - 0xe, 0x18, 0x1c, - 0xe, 0x15, 0x1c, - 0xe, 0x11, 0x1c, - 0x14, 0x14, 0x1c, - 0x16, 0x14, 0x1c, - 0x18, 0x14, 0x1c, - 0x1a, 0x14, 0x1c, - 0x1c, 0x14, 0x1c, - 0x1c, 0x14, 0x1a, - 0x1c, 0x14, 0x18, - 0x1c, 0x14, 0x16, - 0x1c, 0x14, 0x14, - 0x1c, 0x16, 0x14, - 0x1c, 0x18, 0x14, - 0x1c, 0x1a, 0x14, - 0x1c, 0x1c, 0x14, - 0x1a, 0x1c, 0x14, - 0x18, 0x1c, 0x14, - 0x16, 0x1c, 0x14, - 0x14, 0x1c, 0x14, - 0x14, 0x1c, 0x16, - 0x14, 0x1c, 0x18, - 0x14, 0x1c, 0x1a, - 0x14, 0x1c, 0x1c, - 0x14, 0x1a, 0x1c, - 0x14, 0x18, 0x1c, - 0x14, 0x16, 0x1c, - 0x0, 0x0, 0x10, - 0x4, 0x0, 0x10, - 0x8, 0x0, 0x10, - 0xc, 0x0, 0x10, - 0x10, 0x0, 0x10, - 0x10, 0x0, 0xc, - 0x10, 0x0, 0x8, - 0x10, 0x0, 0x4, - 0x10, 0x0, 0x0, - 0x10, 0x4, 0x0, - 0x10, 0x8, 0x0, - 0x10, 0xc, 0x0, - 0x10, 0x10, 0x0, - 0xc, 0x10, 0x0, - 0x8, 0x10, 0x0, - 0x4, 0x10, 0x0, - 0x0, 0x10, 0x0, - 0x0, 0x10, 0x4, - 0x0, 0x10, 0x8, - 0x0, 0x10, 0xc, - 0x0, 0x10, 0x10, - 0x0, 0xc, 0x10, - 0x0, 0x8, 0x10, - 0x0, 0x4, 0x10, - 0x8, 0x8, 0x10, - 0xa, 0x8, 0x10, - 0xc, 0x8, 0x10, - 0xe, 0x8, 0x10, - 0x10, 0x8, 0x10, - 0x10, 0x8, 0xe, - 0x10, 0x8, 0xc, - 0x10, 0x8, 0xa, - 0x10, 0x8, 0x8, - 0x10, 0xa, 0x8, - 0x10, 0xc, 0x8, - 0x10, 0xe, 0x8, - 0x10, 0x10, 0x8, - 0xe, 0x10, 0x8, - 0xc, 0x10, 0x8, - 0xa, 0x10, 0x8, - 0x8, 0x10, 0x8, - 0x8, 0x10, 0xa, - 0x8, 0x10, 0xc, - 0x8, 0x10, 0xe, - 0x8, 0x10, 0x10, - 0x8, 0xe, 0x10, - 0x8, 0xc, 0x10, - 0x8, 0xa, 0x10, - 0xb, 0xb, 0x10, - 0xc, 0xb, 0x10, - 0xd, 0xb, 0x10, - 0xf, 0xb, 0x10, - 0x10, 0xb, 0x10, - 0x10, 0xb, 0xf, - 0x10, 0xb, 0xd, - 0x10, 0xb, 0xc, - 0x10, 0xb, 0xb, - 0x10, 0xc, 0xb, - 0x10, 0xd, 0xb, - 0x10, 0xf, 0xb, - 0x10, 0x10, 0xb, - 0xf, 0x10, 0xb, - 0xd, 0x10, 0xb, - 0xc, 0x10, 0xb, - 0xb, 0x10, 0xb, - 0xb, 0x10, 0xc, - 0xb, 0x10, 0xd, - 0xb, 0x10, 0xf, - 0xb, 0x10, 0x10, - 0xb, 0xf, 0x10, - 0xb, 0xd, 0x10, - 0xb, 0xc, 0x10, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0 -}; - -unsigned char AC[21] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x0C, 0x00, 0x0F, 0x08, 0x00}; - -static int scanPCI(int start_slt); -static int PCIVendor(int); -static void printslots(void); -extern void puthex(unsigned long); -extern void puts(const char *); -static void unlockS3(void); - -static inline -outw(int port, unsigned short val) -{ - outb(port, val >> 8); - outb(port+1, val); -} - -#define PPC_601 1 - -vga_init(unsigned char *ISA_mem) -{ - int slot; - struct VgaRegs *VgaTextRegs; -#if 0 - if ((_get_PVR()>>16) == PPC_601) { - return(old_vga_init(ISA_mem)); - } -#endif - - /* See if VGA already in TEXT mode - exit if so! */ - outb(0x3CE, 0x06); - if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;} - - /* If no VGA responding in text mode, then we have some work to do... - */ - slot = -1; - while((slot = scanPCI(slot)) > -1) { /* find video card in use */ - unlockVideo(slot); /* enable I/O to card */ - VgaTextRegs = GenVgaTextRegs; - - switch (PCIVendor(slot)) { - default: - break; - case(S3Vendor): - unlockS3(); - VgaTextRegs = S3TextRegs; - break; - - case(CirrusVendor): - outw(0x3C4, 0x0612); /* unlock ext regs */ - outw(0x3C4, 0x0700); /* reset ext sequence mode */ - break; - - case(ParadiseVendor): /* IBM Portable 850 */ - outw(0x3ce, 0x0f05); /* unlock pardise registers */ - outw(0x3c4, 0x0648); - outw(0x3d4, 0x2985); - outw(0x3d4, 0x34a6); - outb(0x3ce, 0x0b); /* disable linear addressing */ - outb(0x3cf, inb(0x3cf) & ~0x30); - outw(0x3c4, 0x1400); - outb(0x3ce, 0x0e); /* disable 256 color mode */ - outb(0x3cf, inb(0x3cf) & ~0x01); - outb(0xd00, 0xff); /* enable auto-centering */ - if (!(inb(0xd01) & 0x03)) { - outb(0x3d4, 0x33); - outb(0x3d5, inb(0x3d5) & ~0x90); - outb(0x3d4, 0x32); - outb(0x3d5, inb(0x3d5) | 0x04); - outw(0x3d4, 0x0250); - outw(0x3d4, 0x07ba); - outw(0x3d4, 0x0900); - outw(0x3d4, 0x15e7); - outw(0x3d4, 0x2a95); - } - outw(0x3d4, 0x34a0); - break; - - #if 0 /* Untested - probably doesn't work */ - case(MatroxVendor): - case(DiamondVendor): - puts("VGA Chip Vendor ID: "); - puthex(PCIVendor(slot)); - puts("\n"); - mdelay(1000); - #endif - }; - - outw(0x3C4, 0x0120); /* disable video */ - setTextRegs(VgaTextRegs); /* initial register setup */ - setTextCLUT(0); /* load color lookup table */ - loadFont(ISA_mem); /* load font */ - setTextRegs(VgaTextRegs); /* reload registers */ - outw(0x3C4, 0x0100); /* re-enable video */ - clearVideoMemory(); - - if (PCIVendor(slot) == S3Vendor) { - outb(0x3c2, 0x63); /* MISC */ - } /* endif */ - - #ifdef DEBUG - printslots(); - mdelay(5000); - #endif - - mdelay(1000); /* give time for the video monitor to come up */ - } - return (1); /* 'CRT' I/O supported */ -} - -/* - * Write to VGA Attribute registers. - */ -writeAttr(index, data, videoOn) - unsigned char index; - unsigned char data; - unsigned char videoOn; /* video on flag */ -{ - unsigned char v; - v = inb(0x3da); /* reset attr. address toggle */ - if (videoOn) - outb(0x3c0, (index & 0x1F) | 0x20); - else - outb(0x3c0, (index & 0x1F)); - outb(0x3c0, data); -} - -setTextRegs(struct VgaRegs *svp) -{ - int i; - - /* - * saved settings - */ - while( svp->io_port != ENDMK ) { - outb(svp->io_port, svp->io_index); - outb(svp->io_port+1, svp->io_value); - svp++; - } - - outb(0x3c2, 0x67); /* MISC */ - outb(0x3c6, 0xff); /* MASK */ - - for ( i = 0; i < 0x10; i++) - writeAttr(i, AC[i], 0); /* pallete */ - writeAttr(0x10, 0x0c, 0); /* text mode */ - writeAttr(0x11, 0x00, 0); /* overscan color (border) */ - writeAttr(0x12, 0x0f, 0); /* plane enable */ - writeAttr(0x13, 0x08, 0); /* pixel panning */ - writeAttr(0x14, 0x00, 1); /* color select; video on */ -} - -setTextCLUT(int shift) -{ - int i; - - outb(0x3C6, 0xFF); - i = inb(0x3C7); - outb(0x3C8, 0); - i = inb(0x3C7); - - for ( i = 0; i < 256; i++) { - outb(0x3C9, TextCLUT[i].r << shift); - outb(0x3C9, TextCLUT[i].g << shift); - outb(0x3C9, TextCLUT[i].b << shift); - } -} - - -loadFont(unsigned char *ISA_mem) -{ - int i, j; - unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; - - outb(0x3C2, 0x67); - /* - * Load font - */ - i = inb(0x3DA); /* Reset Attr toggle */ - - outb(0x3C0,0x30); - outb(0x3C0, 0x01); /* graphics mode */ - - outw(0x3C4, 0x0001); /* reset sequencer */ - outw(0x3C4, 0x0204); /* write to plane 2 */ - outw(0x3C4, 0x0406); /* enable plane graphics */ - outw(0x3C4, 0x0003); /* reset sequencer */ - outw(0x3CE, 0x0402); /* read plane 2 */ - outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */ - outw(0x3CE, 0x0605); /* set graphics mode */ - - for (i = 0; i < sizeof(font); i += 16) { - for (j = 0; j < 16; j++) { - __asm__ volatile("eieio"); - font_page[(2*i)+j] = font[i+j]; - } - } -} - -static void -unlockS3(void) -{ - int s3_device_id; - outw(0x3d4, 0x3848); - outw(0x3d4, 0x39a5); - outb(0x3d4, 0x2d); - s3_device_id = inb(0x3d5) << 8; - outb(0x3d4, 0x2e); - s3_device_id |= inb(0x3d5); - - if (s3_device_id != 0x8812) { - /* From the S3 manual */ - outb(0x46E8, 0x10); /* Put into setup mode */ - outb(0x3C3, 0x10); - outb(0x102, 0x01); /* Enable registers */ - outb(0x46E8, 0x08); /* Enable video */ - outb(0x3C3, 0x08); - outb(0x4AE8, 0x00); - -#if 0 - outb(0x42E8, 0x80); /* Reset graphics engine? */ -#endif - - outb(0x3D4, 0x38); /* Unlock all registers */ - outb(0x3D5, 0x48); - outb(0x3D4, 0x39); - outb(0x3D5, 0xA5); - outb(0x3D4, 0x40); - outb(0x3D5, inb(0x3D5)|0x01); - outb(0x3D4, 0x33); - outb(0x3D5, inb(0x3D5)&~0x52); - outb(0x3D4, 0x35); - outb(0x3D5, inb(0x3D5)&~0x30); - outb(0x3D4, 0x3A); - outb(0x3D5, 0x00); - outb(0x3D4, 0x53); - outb(0x3D5, 0x00); - outb(0x3D4, 0x31); - outb(0x3D5, inb(0x3D5)&~0x4B); - outb(0x3D4, 0x58); - - outb(0x3D5, 0); - - outb(0x3D4, 0x54); - outb(0x3D5, 0x38); - outb(0x3D4, 0x60); - outb(0x3D5, 0x07); - outb(0x3D4, 0x61); - outb(0x3D5, 0x80); - outb(0x3D4, 0x62); - outb(0x3D5, 0xA1); - outb(0x3D4, 0x69); /* High order bits for cursor address */ - outb(0x3D5, 0); - - outb(0x3D4, 0x32); - outb(0x3D5, inb(0x3D5)&~0x10); - } else { - outw(0x3c4, 0x0806); /* IBM Portable 860 */ - outw(0x3c4, 0x1041); - outw(0x3c4, 0x1128); - outw(0x3d4, 0x4000); - outw(0x3d4, 0x3100); - outw(0x3d4, 0x3a05); - outw(0x3d4, 0x6688); - outw(0x3d4, 0x5800); /* disable linear addressing */ - outw(0x3d4, 0x4500); /* disable H/W cursor */ - outw(0x3c4, 0x5410); /* enable auto-centering */ - outw(0x3c4, 0x561f); - outw(0x3c4, 0x1b80); /* lock DCLK selection */ - outw(0x3d4, 0x3900); /* lock S3 registers */ - outw(0x3d4, 0x3800); - } /* endif */ -} - -/* - * cursor() sets an offset (0-1999) into the 80x25 text area - */ -void -cursor(int x, int y) -{ - int pos = (y*cols)+x; - outb(0x3D4, 14); - outb(0x3D5, pos >> 8); - outb(0x3D4, 15); - outb(0x3D5, pos); -} - -clearVideoMemory() -{ - int i, j; - for (i = 0; i < lines; i++) { - for (j = 0; j < cols; j++) { - vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */ - vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */ - } - } -} - -/* ============ */ - - -#define NSLOTS 8 -#define NPCIREGS 5 - - -/* - should use devfunc number/indirect method to be totally safe on - all machines, this works for now on 3 slot Moto boxes -*/ - -struct PCI_ConfigInfo { - unsigned long * config_addr; - unsigned long regs[NPCIREGS]; -} PCI_slots [NSLOTS] = { - - { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */ - { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */ - { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */ -}; - - - -/* - * The following code modifies the PCI Command register - * to enable memory and I/O accesses. - */ -unlockVideo(slot) -{ - volatile unsigned char * ppci; - - ppci = (unsigned char * )PCI_slots[slot].config_addr; - ppci[4] = 0x0003; /* enable memory and I/O accesses */ - ppci[0x10] = 0x00000; /* turn off memory mapping */ - ppci[0x11] = 0x00000; /* mem_base = 0 */ - ppci[0x12] = 0x00000; - ppci[0x13] = 0x00000; - __asm__ volatile("eieio"); - - outb(0x3d4, 0x11); - outb(0x3d5, 0x0e); /* unlock CR0-CR7 */ -} - -long -SwapBytes(long lv) /* turn little endian into big indian long */ -{ - long t; - t = (lv&0x000000FF) << 24; - t |= (lv&0x0000FF00) << 8; - t |= (lv&0x00FF0000) >> 8; - t |= (lv&0xFF000000) >> 24; - return(t); -} - - -#define DEVID 0 -#define CMD 1 -#define CLASS 2 -#define MEMBASE 4 - -int -scanPCI(int start_slt) -{ - int slt, r; - struct PCI_ConfigInfo *pslot; - int theSlot = -1; - int highVgaSlot = 0; - - for ( slt = start_slt + 1; slt < NSLOTS; slt++) { - pslot = &PCI_slots[slt]; - for ( r = 0; r < NPCIREGS; r++) { - pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); - } - /* card in slot ? */ - if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { - /* VGA ? */ - if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || - ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { - highVgaSlot = slt; - /* did firmware enable it ? */ - if ( (pslot->regs[CMD] & 0x03) ) { - theSlot = slt; - break; - } - } - } - } - - return ( theSlot ); -} - -/* return Vendor ID of card in the slot */ -static -int PCIVendor(int slotnum) { - struct PCI_ConfigInfo *pslot; - - pslot = &PCI_slots[slotnum]; - -return (pslot->regs[DEVID] & 0xFFFF); -} - -static -void printslots(void) -{ - int i; - struct PCI_ConfigInfo *pslot; - for(i=0; i < NSLOTS; i++) { -#if 0 - pslot = &PCI_slots[i]; - printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n", - i, pslot->config_addr, pslot->regs[0], pslot->regs[2]); -#else - puts("PCI Slot number: "); puthex(i); - puts(" Vendor ID: "); - puthex(PCIVendor(i)); puts("\n"); -#endif - } -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.4.4/linux/arch/ppc/chrpboot/Makefile Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/chrpboot/Makefile Wed Dec 31 16:00:00 1969 @@ -1,101 +0,0 @@ -# Makefile for making ELF bootable images for booting on CHRP -# using Open Firmware. -# -# Geert Uytterhoeven September 1997 -# -# Based on coffboot by Paul Mackerras - -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -AFLAGS += -Wa,-mppc64bridge -else -MSIZE= -endif - -.c.o: - $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS -LD_ARGS = -Ttext 0x00400000 - -OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o -LIBS = $(TOPDIR)/lib/lib.a - -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE) -endif - -all: $(TOPDIR)/zImage - -# -# Only build anything here if we're configured for ALL_PPC -# -- cort -# -ifeq ($(CONFIG_ALL_PPC),y) -znetboot: zImage - cp zImage $(TFTPIMAGE) - -znetboot.initrd: zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - -floppy: zImage - mcopy zImage a:zImage - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c - -addnote: addnote.c - $(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c - -image.o: piggyback ../coffboot/vmlinux.gz - ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o - -sysmap.o: piggyback ../../../System.map - ./piggyback sysmap < ../../../System.map | $(AS) -o sysmap.o - -initrd.o: ramdisk.image.gz piggyback - ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o - -zImage: $(OBJS) no_initrd.o addnote - $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - cp $@ $@.rs6k - ./addnote $@.rs6k - -zImage.initrd: $(OBJS) initrd.o addnote - $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) - cp $@ $@.rs6k - ./addnote $@.rs6k - -else -znetboot: - -znetboot.initrd: - -floppy: - -zImage: - -zImage.initrd: - -endif - -# just here to match coffboot/Makefile -vmlinux.coff: - -vmlinux.coff.initrd: - - -clean: - rm -f piggyback note addnote $(OBJS) zImage - rm -f zImage.rs6k zImage.initrd zImage.initrd.rs6k - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend - -dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/addnote.c linux/arch/ppc/chrpboot/addnote.c --- v2.4.4/linux/arch/ppc/chrpboot/addnote.c Sun Sep 17 09:48:06 2000 +++ linux/arch/ppc/chrpboot/addnote.c Wed Dec 31 16:00:00 1969 @@ -1,174 +0,0 @@ -/* - * Program to hack in a PT_NOTE program header entry in an ELF file. - * This is needed for OF on RS/6000s to load an image correctly. - * Note that OF needs a program header entry for the note, not an - * ELF section. - * - * Copyright 2000 Paul Mackerras. - * - * 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. - * - * Usage: addnote zImage - */ -#include -#include -#include -#include - -char arch[] = "PowerPC"; - -#define N_DESCR 6 -unsigned int descr[N_DESCR] = { -#if 1 - /* values for IBM RS/6000 machines */ - 0xffffffff, /* real-mode = true */ - 0x00c00000, /* real-base, i.e. where we expect OF to be */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x4000, /* load-base */ -#else - /* values for longtrail CHRP */ - 0, /* real-mode = false */ - 0xffffffff, /* real-base */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x00600000, /* load-base */ -#endif -}; - -unsigned char buf[512]; - -#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) -#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) - -#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ - buf[(off) + 1] = (v) & 0xff) -#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ - PUT_16BE((off) + 2, (v))) - -/* Structure of an ELF file */ -#define E_IDENT 0 /* ELF header */ -#define E_PHOFF 28 -#define E_PHENTSIZE 42 -#define E_PHNUM 44 -#define E_HSIZE 52 /* size of ELF header */ - -#define EI_MAGIC 0 /* offsets in E_IDENT area */ -#define EI_CLASS 4 -#define EI_DATA 5 - -#define PH_TYPE 0 /* ELF program header */ -#define PH_OFFSET 4 -#define PH_FILESZ 16 -#define PH_HSIZE 32 /* size of program header */ - -#define PT_NOTE 4 /* Program header type = note */ - -#define ELFCLASS32 1 -#define ELFDATA2MSB 2 - -unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; - -int main(int ac, char **av) -{ - int fd, n, i; - int ph, ps, np; - int nnote, ns; - - if (ac != 2) { - fprintf(stderr, "Usage: %s elf-file\n", av[0]); - exit(1); - } - fd = open(av[1], O_RDWR); - if (fd < 0) { - perror(av[1]); - exit(1); - } - - nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; - - n = read(fd, buf, sizeof(buf)); - if (n < 0) { - perror("read"); - exit(1); - } - - if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) - goto notelf; - - if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 - || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { - fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", - av[1]); - exit(1); - } - - ph = GET_32BE(E_PHOFF); - ps = GET_16BE(E_PHENTSIZE); - np = GET_16BE(E_PHNUM); - if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) - goto notelf; - if (ph + (np + 1) * ps + nnote > n) - goto nospace; - - for (i = 0; i < np; ++i) { - if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { - fprintf(stderr, "%s already has a note entry\n", - av[1]); - exit(0); - } - ph += ps; - } - - /* XXX check that the area we want to use is all zeroes */ - for (i = 0; i < ps + nnote; ++i) - if (buf[ph + i] != 0) - goto nospace; - - /* fill in the program header entry */ - ns = ph + ps; - PUT_32BE(ph + PH_TYPE, PT_NOTE); - PUT_32BE(ph + PH_OFFSET, ns); - PUT_32BE(ph + PH_FILESZ, nnote); - - /* fill in the note area we point to */ - /* XXX we should probably make this a proper section */ - PUT_32BE(ns, strlen(arch) + 1); - PUT_32BE(ns + 4, N_DESCR * 4); - PUT_32BE(ns + 8, 0x1275); - strcpy(&buf[ns + 12], arch); - ns += 12 + strlen(arch) + 1; - for (i = 0; i < N_DESCR; ++i) - PUT_32BE(ns + i * 4, descr[i]); - - /* Update the number of program headers */ - PUT_16BE(E_PHNUM, np + 1); - - /* write back */ - lseek(fd, (long) 0, SEEK_SET); - i = write(fd, buf, n); - if (i < 0) { - perror("write"); - exit(1); - } - if (i < n) { - fprintf(stderr, "%s: write truncated\n", av[1]); - exit(1); - } - - exit(0); - - notelf: - fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); - exit(1); - - nospace: - fprintf(stderr, "sorry, I can't find space in %s to put the note\n", - av[0]); - exit(1); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/crt0.S linux/arch/ppc/chrpboot/crt0.S --- v2.4.4/linux/arch/ppc/chrpboot/crt0.S Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/chrpboot/crt0.S Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - .globl _start -_start: - lis 9,_start@h - lis 8,_etext@ha - addi 8,8,_etext@l -1: dcbf 0,9 - icbi 0,9 - addi 9,9,0x20 - cmplwi 0,9,8 - blt 1b - b start diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.4.4/linux/arch/ppc/chrpboot/main.c Mon Jun 19 17:59:35 2000 +++ linux/arch/ppc/chrpboot/main.c Wed Dec 31 16:00:00 1969 @@ -1,195 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include "../coffboot/nonstdio.h" -#include "../coffboot/zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -void gunzip(void *, int, unsigned char *, int *); - -#define RAM_START 0x00000000 -#define RAM_END (64<<20) - -#define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) - -#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) -#define PROG_START 0x00010000 - -char *avail_ram; -char *end_avail; - -extern char _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; -extern char sysmap_data[]; -extern int sysmap_len; - -static char scratch[1024<<10]; /* 1MB of scratch space for gunzip */ - -chrpboot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - extern char _start; - - printf("chrpboot starting: loaded at 0x%x\n\r", &_start); - - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - - im = image_data; - len = image_len; - /* claim 4MB starting at PROG_START */ - claim(PROG_START, (4<<20) - PROG_START, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - avail_ram = scratch; - end_avail = scratch + sizeof(scratch); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 0x400000, im, &len); - printf("done %u bytes\n\r", len); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n\r", sa); - - { - struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "chrpboot"); - rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_chrp; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#if 0 - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap_data; - rec->data[1] = sysmap_len; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#endif - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - } - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n\r"); - - pause(); -} - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p = avail_ram; - - size *= items; - size = (size + 7) & -8; - avail_ram += size; - if (avail_ram > end_avail) { - printf("oops... out of memory\n\r"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - nb = (nb + 7) & -8; - if (addr == (avail_ram - nb)) { - avail_ram -= nb; - } -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/misc.S linux/arch/ppc/chrpboot/misc.S --- v2.4.4/linux/arch/ppc/chrpboot/misc.S Tue Apr 14 17:33:57 1998 +++ linux/arch/ppc/chrpboot/misc.S Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - -/* - * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000. - */ - .globl setup_bats -setup_bats: - mfpvr 3 - rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,3,1 - lis 4,0x9000 - bne 4f - ori 4,4,4 /* set up BAT registers for 601 */ - li 5,0x7f - b 5f -4: ori 4,4,0xff /* set up BAT registers for 604 */ - li 5,2 - mtdbatu 3,4 - mtdbatl 3,5 -5: mtibatu 3,4 - mtibatl 3,5 - isync - blr - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ - rlwinm. 4,4,27,5,31 - mtctr 4 - beqlr -1: dcbf 0,3 - icbi 0,3 - addi 3,3,0x20 - bdnz 1b - sync - isync - blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/mknote.c linux/arch/ppc/chrpboot/mknote.c --- v2.4.4/linux/arch/ppc/chrpboot/mknote.c Mon Jun 7 12:11:51 1999 +++ linux/arch/ppc/chrpboot/mknote.c Wed Dec 31 16:00:00 1969 @@ -1,43 +0,0 @@ -/* - * Copyright (C) Cort Dougan 1999. - * - * 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. - * - * Generate a note section as per the CHRP specification. - * - */ - -#include - -#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); - -int main(void) -{ -/* header */ - /* namesz */ - PL(strlen("PowerPC")+1); - /* descrsz */ - PL(6*4); - /* type */ - PL(0x1275); - /* name */ - printf("PowerPC"); printf("%c", 0); - -/* descriptor */ - /* real-mode */ - PL(0xffffffff); - /* real-base */ - PL(0x00c00000); - /* real-size */ - PL(0xffffffff); - /* virt-base */ - PL(0xffffffff); - /* virt-size */ - PL(0xffffffff); - /* load-base */ - PL(0x4000); - return 0; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/no_initrd.c linux/arch/ppc/chrpboot/no_initrd.c --- v2.4.4/linux/arch/ppc/chrpboot/no_initrd.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/chrpboot/no_initrd.c Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -char initrd_data[1]; -int initrd_len = 0; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/piggyback.c linux/arch/ppc/chrpboot/piggyback.c --- v2.4.4/linux/arch/ppc/chrpboot/piggyback.c Tue Feb 22 22:27:43 2000 +++ linux/arch/ppc/chrpboot/piggyback.c Wed Dec 31 16:00:00 1969 @@ -1,66 +0,0 @@ -#include -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl %s_data\n", argv[1]); - fprintf(stdout, "%s_data:\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl %s_len\n", argv[1]); - fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/chrpboot/start.c linux/arch/ppc/chrpboot/start.c --- v2.4.4/linux/arch/ppc/chrpboot/start.c Mon Jun 19 17:59:35 2000 +++ linux/arch/ppc/chrpboot/start.c Wed Dec 31 16:00:00 1969 @@ -1,305 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include - -int (*prom)(); - -void *chosen_handle; -void *stdin; -void *stdout; -void *stderr; - -void exit(void); -void *finddevice(const char *name); -int getprop(void *phandle, const char *name, void *buf, int buflen); - -void printk(char *fmt, ...); - -void -start(int a1, int a2, void *promptr) -{ - prom = (int (*)()) promptr; - chosen_handle = finddevice("/chosen"); - if (chosen_handle == (void *) -1) - exit(); - if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) - exit(); - stderr = stdout; - if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) - exit(); - - chrpboot(a1, a2, promptr); - for (;;) - exit(); -} - -int -write(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "write"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -int -read(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "read"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -void -exit() -{ - struct prom_args { - char *service; - } args; - - for (;;) { - args.service = "exit"; - (*prom)(&args); - } -} - -void -pause() -{ - struct prom_args { - char *service; - } args; - - args.service = "enter"; - (*prom)(&args); -} - -void * -finddevice(const char *name) -{ - struct prom_args { - char *service; - int nargs; - int nret; - const char *devspec; - void *phandle; - } args; - - args.service = "finddevice"; - args.nargs = 1; - args.nret = 1; - args.devspec = name; - args.phandle = (void *) -1; - (*prom)(&args); - return args.phandle; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -int -getprop(void *phandle, const char *name, void *buf, int buflen) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *phandle; - const char *name; - void *buf; - int buflen; - int size; - } args; - - args.service = "getprop"; - args.nargs = 4; - args.nret = 1; - args.phandle = phandle; - args.name = name; - args.buf = buf; - args.buflen = buflen; - args.size = -1; - (*prom)(&args); - return args.size; -} - -int -putc(int c, void *f) -{ - char ch = c; - - if (c == '\n') - putc('\r', f); - return write(f, &ch, 1) == 1? c: -1; -} - -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -fputs(char *str, void *f) -{ - int n = strlen(str); - - return write(f, str, n) == n? 0: -1; -} - -int -readchar() -{ - char ch; - - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\r\n"); - return -1; - } - } -} - -static char line[256]; -static char *lineptr; -static int lineleft; - -int -getchar() -{ - int c; - - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; - } - } - } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; -} - -extern int vsprintf(char *buf, const char *fmt, va_list args); -static char sprint_buf[1024]; - -void -printk(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - write(stdout, sprint_buf, n); -} - -int -printf(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - write(stdout, sprint_buf, n); - return n; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile --- v2.4.4/linux/arch/ppc/coffboot/Makefile Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/coffboot/Makefile Wed Dec 31 16:00:00 1969 @@ -1,131 +0,0 @@ -# Makefile for making XCOFF bootable images for booting on PowerMacs -# using Open Firmware. -# -# Paul Mackerras January 1997 - -HOSTCFLAGS = -O -I$(TOPDIR)/include - -CFLAGS = $(CPPFLAGS) -O -fno-builtin -OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x01000000 - -COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o -CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o -LIBS = $(TOPDIR)/lib/lib.a - -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -else -MSIZE= -endif - -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) -endif - -ifeq ($(CONFIG_ALL_PPC),y) -chrpmain.o: chrpmain.c - $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c - -hack-coff: hack-coff.c - $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c - -znetboot: vmlinux.coff vmlinux.elf zImage - cp vmlinux.coff $(TFTPIMAGE) - cp vmlinux.elf $(TFTPIMAGE).elf - -znetboot.initrd: vmlinux.coff.initrd vmlinux.elf.initrd - cp vmlinux.coff.initrd $(TFTPIMAGE) - cp vmlinux.elf.initrd $(TFTPIMAGE).elf - -floppy: zImage -# mount -t hfs /dev/fd0 /mnt -# cp vmlinux.coff /mnt -# umount /mnt - -miboot.image: dummy.o vmlinux.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz dummy.o $@ - -miboot.image.initrd: miboot.image ramdisk.image.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz miboot.image $@ - -coffboot: $(COFFOBJS) no_initrd.o ld.script - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS) - -coffboot.initrd: $(COFFOBJS) initrd.o ld.script - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) - -piggyback: piggyback.c - $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c - -mknote: mknote.c - $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c - -image.o: piggyback vmlinux.gz - ./piggyback image < vmlinux.gz | $(AS) -o image.o - -initrd.o: ramdisk.image.gz piggyback - ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o - -vmlinux.coff: coffboot hack-coff - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@ - ./hack-coff $@ - ln -sf vmlinux.coff zImage - -vmlinux.coff.initrd: coffboot.initrd hack-coff - $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd $@ - ./hack-coff $@ - -vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) - ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note \ - --add-section=sysmap=../../../System.map -R .comment - $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ - -DSYSMAP_OFFSET=`sh ../boot/offset $(OBJDUMP) $@ sysmap` \ - -DSYSMAP_SIZE=`sh ../boot/size $(OBJDUMP) $@ sysmap` - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) - $(OBJCOPY) $@ $@ --add-section=.note=note \ - --add-section=sysmap=../../../System.map -R .comment - -vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote - $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS) - ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment - -zImage: vmlinux.coff vmlinux.elf miboot.image - -zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd - -else -znetboot: vmlinux.gz - -znetboot.initrd: vmlinux.gz - -coffboot: vmlinux.gz - -zImage: vmlinux.gz - -zImage.initrd: vmlinux.gz - -vmlinux.coff: vmlinux.gz - -vmlinux.coff.initrd: vmlinux.gz - -floppy: vmlinux.gz - -endif - -vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux - gzip -vf9 vmlinux - -clean: - rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz - rm -f mknote piggyback vmlinux.elf note - rm -f miboot.image miboot.image.initrd - -fastdep: diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c --- v2.4.4/linux/arch/ppc/coffboot/chrpmain.c Sun Sep 17 09:48:06 2000 +++ linux/arch/ppc/coffboot/chrpmain.c Wed Dec 31 16:00:00 1969 @@ -1,286 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include "nonstdio.h" -#include "zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -void make_bi_recs(unsigned long); -void gunzip(void *, int, unsigned char *, int *); -void stop_imac_ethernet(void); -void stop_imac_usb(void); - -#define get_16be(x) (*(unsigned short *)(x)) -#define get_32be(x) (*(unsigned *)(x)) - -#define RAM_END (16 << 20) - -#define PROG_START 0x00010000 -#define PROG_SIZE 0x003f0000 - -#define SCRATCH_SIZE (128 << 10) - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; -unsigned int heap_use; -unsigned int heap_max; - -extern char _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; - - -boot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - extern char _start; - - printf("chrpboot starting: loaded at 0x%x\n", &_start); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start, - initrd_data,initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; - /* claim 3MB starting at PROG_START */ - claim(PROG_START, PROG_SIZE, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ - avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); - begin_avail = avail_high = avail_ram; - end_avail = avail_ram + SCRATCH_SIZE; - printf("heap at 0x%x\n", avail_ram); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs((unsigned long) dst + len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} - -void make_bi_recs(unsigned long addr) -{ - struct bi_record *rec; - rec = (struct bi_record *)_ALIGN((unsigned long)addr+(1<<20)-1,(1<<20)); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "coffboot"); - rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_Pmac; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - -#ifdef SYSMAP_OFFSET - rec->tag = BI_SYSMAP; - rec->data[0] = SYSMAP_OFFSET; - rec->data[1] = SYSMAP_SIZE; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#endif /* SYSMAP_OFFSET */ - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -} - -#if 0 -#define eieio() asm volatile("eieio"); - -void stop_imac_ethernet(void) -{ - void *macio, *enet; - unsigned int macio_addr[5], enet_reg[6]; - int len; - volatile unsigned int *dbdma; - - macio = finddevice("/pci/mac-io"); - enet = finddevice("/pci/mac-io/ethernet"); - if (macio == NULL || enet == NULL) - return; - len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr)); - if (len != sizeof(macio_addr)) - return; - len = getprop(enet, "reg", enet_reg, sizeof(enet_reg)); - if (len != sizeof(enet_reg)) - return; - printf("macio base %x, dma at %x & %x\n", - macio_addr[2], enet_reg[2], enet_reg[4]); - - /* hope this is mapped... */ - dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]); - *dbdma = 0x80; /* clear the RUN bit */ - eieio(); - dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]); - *dbdma = 0x80; /* clear the RUN bit */ - eieio(); -} - -void stop_imac_usb(void) -{ - void *usb; - unsigned int usb_addr[5]; - int len; - volatile unsigned int *usb_ctrl; - - usb = finddevice("/pci/usb"); - if (usb == NULL) - return; - len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr)); - if (len != sizeof(usb_addr)) - return; - printf("usb base %x\n", usb_addr[2]); - - usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8); - *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ - eieio(); -} -#endif - -struct memchunk { - unsigned int size; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size *= items; - size = (size + 7) & -8; - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/coffcrt0.S linux/arch/ppc/coffboot/coffcrt0.S --- v2.4.4/linux/arch/ppc/coffboot/coffcrt0.S Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/coffboot/coffcrt0.S Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - .globl _start -_start: - .long __start,0,0 - - .globl __start -__start: - lis 9,_start@h - lis 8,_etext@ha - addi 8,8,_etext@l -1: dcbf 0,9 - icbi 0,9 - addi 9,9,0x20 - cmplwi 0,9,8 - blt 1b - b start diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/coffmain.c linux/arch/ppc/coffboot/coffmain.c --- v2.4.4/linux/arch/ppc/coffboot/coffmain.c Mon Jan 22 15:41:14 2001 +++ linux/arch/ppc/coffboot/coffmain.c Wed Dec 31 16:00:00 1969 @@ -1,226 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include "nonstdio.h" -#include "zlib.h" -#include -#include -#include - -extern void *finddevice(const char *); -extern int getprop(void *, const char *, void *, int); -extern char *claim(unsigned, unsigned, unsigned); -void make_bi_recs(unsigned long); -void gunzip(void *, int, unsigned char *, int *); - -#define get_16be(x) (*(unsigned short *)(x)) -#define get_32be(x) (*(unsigned *)(x)) - -#define RAM_START 0xc0000000 -#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ - -#define PROG_START RAM_START -#define PROG_SIZE 0x00400000 - -#define SCRATCH_SIZE (128 << 10) - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; -unsigned int heap_use; -unsigned int heap_max; - -extern char _start[], _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; - -char heap[SCRATCH_SIZE]; - -boot(int a1, int a2, void *prom) -{ - int ns, oh, i; - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned initrd_start, initrd_size; - - printf("coffboot starting: loaded at 0x%x\n", _start); - setup_bats(RAM_START); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; - /* claim 3MB starting at 0 */ - claim(0, PROG_SIZE, 0); - dst = (void *) RAM_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ - begin_avail = avail_high = avail_ram = heap; - end_avail = heap + sizeof(heap); - printf("heap at 0x%x\n", avail_ram); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, PROG_SIZE, im, &len); - printf("done %u bytes\n", len); - printf("%u bytes of heap consumed, max in use %u\n", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs((unsigned long)dst + len); - - sa = (unsigned long)PROG_START; - printf("start address = 0x%x\n", sa); - - (*(void (*)())sa)(a1, a2, prom); - - printf("returned?\n"); - - pause(); -} - -void make_bi_recs(unsigned long addr) -{ - struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN(addr); - - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "coffboot"); - rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = _MACH_Pmac; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -} - -struct memchunk { - unsigned int size; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size *= items; - size = (size + 7) & -8; - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - struct memchunk *mp = addr; - - nb = (nb + 7) & -8; - heap_use -= nb; - if (avail_ram == addr + nb) { - avail_ram = addr; - return; - } - mp->size = nb; - mp->next = freechunks; - freechunks = mp; -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/crt0.S linux/arch/ppc/coffboot/crt0.S --- v2.4.4/linux/arch/ppc/coffboot/crt0.S Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/coffboot/crt0.S Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - .globl _start -_start: - lis 9,_start@h - lis 8,_etext@ha - addi 8,8,_etext@l -1: dcbf 0,9 - icbi 0,9 - addi 9,9,0x20 - cmplwi 0,9,8 - blt 1b - b start diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/dummy.c linux/arch/ppc/coffboot/dummy.c --- v2.4.4/linux/arch/ppc/coffboot/dummy.c Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/coffboot/dummy.c Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -int main(void) -{ - return 0; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/hack-coff.c linux/arch/ppc/coffboot/hack-coff.c --- v2.4.4/linux/arch/ppc/coffboot/hack-coff.c Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/hack-coff.c Wed Dec 31 16:00:00 1969 @@ -1,79 +0,0 @@ -/* - * hack-coff.c - hack the header of an xcoff file to fill in - * a few fields needed by the Open Firmware xcoff loader on - * Power Macs but not initialized by objcopy. - * - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include -#include "rs6000.h" - -#define AOUT_MAGIC 0x010b - -#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \ - + ((unsigned char *)(x))[1]) -#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \ - ((unsigned char *)(x))[1] = (v) & 0xff) -#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \ - + (((unsigned char *)(x))[1] << 16) \ - + (((unsigned char *)(x))[2] << 8) \ - + ((unsigned char *)(x))[3]) - -main(int ac, char **av) -{ - int fd; - int i, nsect; - int aoutsz; - struct external_filehdr fhdr; - AOUTHDR aout; - struct external_scnhdr shdr; - - if (ac != 2) { - fprintf(stderr, "Usage: hack-coff coff-file\n"); - exit(1); - } - if ((fd = open(av[1], 2)) == -1) { - perror(av[2]); - exit(1); - } - if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr)) - goto readerr; - i = get_16be(fhdr.f_magic); - if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) { - fprintf(stderr, "%s: not an xcoff file\n", av[1]); - exit(1); - } - aoutsz = get_16be(fhdr.f_opthdr); - if (read(fd, &aout, aoutsz) != aoutsz) - goto readerr; - nsect = get_16be(fhdr.f_nscns); - for (i = 0; i < nsect; ++i) { - if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) - goto readerr; - if (strcmp(shdr.s_name, ".text") == 0) { - put_16be(aout.o_snentry, i+1); - put_16be(aout.o_sntext, i+1); - } else if (strcmp(shdr.s_name, ".data") == 0) { - put_16be(aout.o_sndata, i+1); - } else if (strcmp(shdr.s_name, ".bss") == 0) { - put_16be(aout.o_snbss, i+1); - } - } - put_16be(aout.magic, AOUT_MAGIC); - if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1 - || write(fd, &aout, aoutsz) != aoutsz) { - fprintf(stderr, "%s: write error\n", av[1]); - exit(1); - } - close(fd); - exit(0); - -readerr: - fprintf(stderr, "%s: read error or file too short\n", av[1]); - exit(1); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/ld.script linux/arch/ppc/coffboot/ld.script --- v2.4.4/linux/arch/ppc/coffboot/ld.script Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/ld.script Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0 - .plt : { *(.plt) } - .text : - { - *(.text) - *(.rodata) - *(.rodata1) - *(.got1) - } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - _etext = .; - PROVIDE (etext = .); - /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/misc.S linux/arch/ppc/coffboot/misc.S --- v2.4.4/linux/arch/ppc/coffboot/misc.S Sun Feb 13 10:47:01 2000 +++ linux/arch/ppc/coffboot/misc.S Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - -/* - * Use the BAT3 registers to map the 1st 8MB of RAM to - * the address given as the 1st argument. - */ - .globl setup_bats -setup_bats: - mfpvr 5 - rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,5,1 - li 0,0 - bne 4f - mtibatl 3,0 /* invalidate BAT first */ - ori 3,3,4 /* set up BAT registers for 601 */ - li 4,0x7f - mtibatu 3,3 - mtibatl 3,4 - b 5f -4: mtdbatu 3,0 /* invalidate BATs first */ - mtibatu 3,0 - ori 3,3,0xff /* set up BAT registers for 604 */ - li 4,2 - mtdbatl 3,4 - mtdbatu 3,3 - mtibatl 3,4 - mtibatu 3,3 -5: sync - isync - blr - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ - rlwinm. 4,4,27,5,31 - mtctr 4 - beqlr -1: dcbf 0,3 - icbi 0,3 - addi 3,3,0x20 - bdnz 1b - sync - isync - blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/mknote.c linux/arch/ppc/coffboot/mknote.c --- v2.4.4/linux/arch/ppc/coffboot/mknote.c Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/coffboot/mknote.c Wed Dec 31 16:00:00 1969 @@ -1,43 +0,0 @@ -/* - * Copyright (C) Cort Dougan 1999. - * - * 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. - * - * Generate a note section as per the CHRP specification. - * - */ - -#include - -#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); - -int main(void) -{ -/* header */ - /* namesz */ - PL(strlen("PowerPC")+1); - /* descrsz */ - PL(6*4); - /* type */ - PL(0x1275); - /* name */ - printf("PowerPC"); printf("%c", 0); - -/* descriptor */ - /* real-mode */ - PL(0xffffffff); - /* real-base */ - PL(0x00c00000); - /* real-size */ - PL(0xffffffff); - /* virt-base */ - PL(0xffffffff); - /* virt-size */ - PL(0xffffffff); - /* load-base */ - PL(0x4000); - return 0; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/no_initrd.c linux/arch/ppc/coffboot/no_initrd.c --- v2.4.4/linux/arch/ppc/coffboot/no_initrd.c Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/coffboot/no_initrd.c Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -char initrd_data[1]; -int initrd_len = 0; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/nonstdio.h linux/arch/ppc/coffboot/nonstdio.h --- v2.4.4/linux/arch/ppc/coffboot/nonstdio.h Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/nonstdio.h Wed Dec 31 16:00:00 1969 @@ -1,18 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -typedef int FILE; -extern FILE *stdin, *stdout; -#define NULL ((void *)0) -#define EOF (-1) -#define fopen(n, m) NULL -#define fflush(f) 0 -#define fclose(f) 0 -extern char *fgets(); - -#define perror(s) printf("%s: no files!\n", (s)) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/piggyback.c linux/arch/ppc/coffboot/piggyback.c --- v2.4.4/linux/arch/ppc/coffboot/piggyback.c Tue Feb 22 22:27:43 2000 +++ linux/arch/ppc/coffboot/piggyback.c Wed Dec 31 16:00:00 1969 @@ -1,66 +0,0 @@ -#include -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl %s_data\n", argv[1]); - fprintf(stdout, "%s_data:\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl %s_len\n", argv[1]); - fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/rs6000.h linux/arch/ppc/coffboot/rs6000.h --- v2.4.4/linux/arch/ppc/coffboot/rs6000.h Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/rs6000.h Wed Dec 31 16:00:00 1969 @@ -1,243 +0,0 @@ -/* IBM RS/6000 "XCOFF" file definitions for BFD. - Copyright (C) 1990, 1991 Free Software Foundation, Inc. - FIXME: Can someone provide a transliteration of this name into ASCII? - Using the following chars caused a compiler warning on HIUX (so I replaced - them with octal escapes), and isn't useful without an understanding of what - character set it is. - Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM - and John Gilmore of Cygnus Support. */ - -/********************** FILE HEADER **********************/ - -struct external_filehdr { - char f_magic[2]; /* magic number */ - char f_nscns[2]; /* number of sections */ - char f_timdat[4]; /* time & date stamp */ - char f_symptr[4]; /* file pointer to symtab */ - char f_nsyms[4]; /* number of symtab entries */ - char f_opthdr[2]; /* sizeof(optional hdr) */ - char f_flags[2]; /* flags */ -}; - - /* IBM RS/6000 */ -#define U802WRMAGIC 0730 /* writeable text segments **chh** */ -#define U802ROMAGIC 0735 /* readonly sharable text segments */ -#define U802TOCMAGIC 0737 /* readonly text segments and TOC */ - -#define BADMAG(x) \ - ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \ - (x).f_magic != U802TOCMAGIC) - -#define FILHDR struct external_filehdr -#define FILHSZ 20 - - -/********************** AOUT "OPTIONAL HEADER" **********************/ - - -typedef struct -{ - unsigned char magic[2]; /* type of file */ - unsigned char vstamp[2]; /* version stamp */ - unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */ - unsigned char dsize[4]; /* initialized data " " */ - unsigned char bsize[4]; /* uninitialized data " " */ - unsigned char entry[4]; /* entry pt. */ - unsigned char text_start[4]; /* base of text used for this file */ - unsigned char data_start[4]; /* base of data used for this file */ - unsigned char o_toc[4]; /* address of TOC */ - unsigned char o_snentry[2]; /* section number of entry point */ - unsigned char o_sntext[2]; /* section number of .text section */ - unsigned char o_sndata[2]; /* section number of .data section */ - unsigned char o_sntoc[2]; /* section number of TOC */ - unsigned char o_snloader[2]; /* section number of .loader section */ - unsigned char o_snbss[2]; /* section number of .bss section */ - unsigned char o_algntext[2]; /* .text alignment */ - unsigned char o_algndata[2]; /* .data alignment */ - unsigned char o_modtype[2]; /* module type (??) */ - unsigned char o_cputype[2]; /* cpu type */ - unsigned char o_maxstack[4]; /* max stack size (??) */ - unsigned char o_maxdata[4]; /* max data size (??) */ - unsigned char o_resv2[12]; /* reserved */ -} -AOUTHDR; - -#define AOUTSZ 72 -#define SMALL_AOUTSZ (28) -#define AOUTHDRSZ 72 - -#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */ -#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */ -#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */ - - -/********************** SECTION HEADER **********************/ - - -struct external_scnhdr { - char s_name[8]; /* section name */ - char s_paddr[4]; /* physical address, aliased s_nlib */ - char s_vaddr[4]; /* virtual address */ - char s_size[4]; /* section size */ - char s_scnptr[4]; /* file ptr to raw data for section */ - char s_relptr[4]; /* file ptr to relocation */ - char s_lnnoptr[4]; /* file ptr to line numbers */ - char s_nreloc[2]; /* number of relocation entries */ - char s_nlnno[2]; /* number of line number entries*/ - char s_flags[4]; /* flags */ -}; - -/* - * names of "special" sections - */ -#define _TEXT ".text" -#define _DATA ".data" -#define _BSS ".bss" -#define _PAD ".pad" -#define _LOADER ".loader" - -#define SCNHDR struct external_scnhdr -#define SCNHSZ 40 - -/* XCOFF uses a special .loader section with type STYP_LOADER. */ -#define STYP_LOADER 0x1000 - -/* XCOFF uses a special .debug section with type STYP_DEBUG. */ -#define STYP_DEBUG 0x2000 - -/* XCOFF handles line number or relocation overflow by creating - another section header with STYP_OVRFLO set. */ -#define STYP_OVRFLO 0x8000 - -/********************** LINE NUMBERS **********************/ - -/* 1 line number entry for every "breakpointable" source line in a section. - * Line numbers are grouped on a per function basis; first entry in a function - * grouping will have l_lnno = 0 and in place of physical address will be the - * symbol table index of the function name. - */ -struct external_lineno { - union { - char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ - char l_paddr[4]; /* (physical) address of line number */ - } l_addr; - char l_lnno[2]; /* line number */ -}; - - -#define LINENO struct external_lineno -#define LINESZ 6 - - -/********************** SYMBOLS **********************/ - -#define E_SYMNMLEN 8 /* # characters in a symbol name */ -#define E_FILNMLEN 14 /* # characters in a file name */ -#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ - -struct external_syment -{ - union { - char e_name[E_SYMNMLEN]; - struct { - char e_zeroes[4]; - char e_offset[4]; - } e; - } e; - char e_value[4]; - char e_scnum[2]; - char e_type[2]; - char e_sclass[1]; - char e_numaux[1]; -}; - - - -#define N_BTMASK (017) -#define N_TMASK (060) -#define N_BTSHFT (4) -#define N_TSHIFT (2) - - -union external_auxent { - struct { - char x_tagndx[4]; /* str, un, or enum tag indx */ - union { - struct { - char x_lnno[2]; /* declaration line number */ - char x_size[2]; /* str/union/array size */ - } x_lnsz; - char x_fsize[4]; /* size of function */ - } x_misc; - union { - struct { /* if ISFCN, tag, or .bb */ - char x_lnnoptr[4]; /* ptr to fcn line # */ - char x_endndx[4]; /* entry ndx past block end */ - } x_fcn; - struct { /* if ISARY, up to 4 dimen. */ - char x_dimen[E_DIMNUM][2]; - } x_ary; - } x_fcnary; - char x_tvndx[2]; /* tv index */ - } x_sym; - - union { - char x_fname[E_FILNMLEN]; - struct { - char x_zeroes[4]; - char x_offset[4]; - } x_n; - } x_file; - - struct { - char x_scnlen[4]; /* section length */ - char x_nreloc[2]; /* # relocation entries */ - char x_nlinno[2]; /* # line numbers */ - } x_scn; - - struct { - char x_tvfill[4]; /* tv fill value */ - char x_tvlen[2]; /* length of .tv */ - char x_tvran[2][2]; /* tv range */ - } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ - - struct { - unsigned char x_scnlen[4]; - unsigned char x_parmhash[4]; - unsigned char x_snhash[2]; - unsigned char x_smtyp[1]; - unsigned char x_smclas[1]; - unsigned char x_stab[4]; - unsigned char x_snstab[2]; - } x_csect; - -}; - -#define SYMENT struct external_syment -#define SYMESZ 18 -#define AUXENT union external_auxent -#define AUXESZ 18 -#define DBXMASK 0x80 /* for dbx storage mask */ -#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK) - - - -/********************** RELOCATION DIRECTIVES **********************/ - - -struct external_reloc { - char r_vaddr[4]; - char r_symndx[4]; - char r_size[1]; - char r_type[1]; -}; - - -#define RELOC struct external_reloc -#define RELSZ 10 - -#define DEFAULT_DATA_SECTION_ALIGNMENT 4 -#define DEFAULT_BSS_SECTION_ALIGNMENT 4 -#define DEFAULT_TEXT_SECTION_ALIGNMENT 4 -/* For new sections we havn't heard of before */ -#define DEFAULT_SECTION_ALIGNMENT 4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/start.c linux/arch/ppc/coffboot/start.c --- v2.4.4/linux/arch/ppc/coffboot/start.c Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/coffboot/start.c Wed Dec 31 16:00:00 1969 @@ -1,321 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include - -int (*prom)(); - -void *chosen_handle; -void *stdin; -void *stdout; -void *stderr; - -void exit(void); -void *finddevice(const char *name); -int getprop(void *phandle, const char *name, void *buf, int buflen); -void printk(char *fmt, ...); - -void -start(int a1, int a2, void *promptr) -{ - prom = (int (*)()) promptr; - chosen_handle = finddevice("/chosen"); - if (chosen_handle == (void *) -1) - exit(); - if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) - exit(); - stderr = stdout; - if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) - exit(); - - boot(a1, a2, promptr); - for (;;) - exit(); -} - -int -write(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "write"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -int writestring(void *f, char *ptr, int nb) -{ - int w = 0, i; - char *ret = "\r"; - - for (i = 0; i < nb; ++i) { - if (ptr[i] == '\n') { - if (i > w) { - write(f, ptr + w, i - w); - w = i; - } - write(f, ret, 1); - } - } - if (w < nb) - write(f, ptr + w, nb - w); - return nb; -} - -int -read(void *handle, void *ptr, int nb) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *ihandle; - void *addr; - int len; - int actual; - } args; - - args.service = "read"; - args.nargs = 3; - args.nret = 1; - args.ihandle = handle; - args.addr = ptr; - args.len = nb; - args.actual = -1; - (*prom)(&args); - return args.actual; -} - -void -exit() -{ - struct prom_args { - char *service; - } args; - - for (;;) { - args.service = "exit"; - (*prom)(&args); - } -} - -void -pause() -{ - struct prom_args { - char *service; - } args; - - args.service = "enter"; - (*prom)(&args); -} - -void * -finddevice(const char *name) -{ - struct prom_args { - char *service; - int nargs; - int nret; - const char *devspec; - void *phandle; - } args; - - args.service = "finddevice"; - args.nargs = 1; - args.nret = 1; - args.devspec = name; - args.phandle = (void *) -1; - (*prom)(&args); - return args.phandle; -} - -void * -claim(unsigned int virt, unsigned int size, unsigned int align) -{ - struct prom_args { - char *service; - int nargs; - int nret; - unsigned int virt; - unsigned int size; - unsigned int align; - void *ret; - } args; - - args.service = "claim"; - args.nargs = 3; - args.nret = 1; - args.virt = virt; - args.size = size; - args.align = align; - (*prom)(&args); - return args.ret; -} - -int -getprop(void *phandle, const char *name, void *buf, int buflen) -{ - struct prom_args { - char *service; - int nargs; - int nret; - void *phandle; - const char *name; - void *buf; - int buflen; - int size; - } args; - - args.service = "getprop"; - args.nargs = 4; - args.nret = 1; - args.phandle = phandle; - args.name = name; - args.buf = buf; - args.buflen = buflen; - args.size = -1; - (*prom)(&args); - return args.size; -} - -int -putc(int c, void *f) -{ - char ch = c; - - return writestring(f, &ch, 1) == 1? c: -1; -} - -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -fputs(char *str, void *f) -{ - int n = strlen(str); - - return writestring(f, str, n) == n? 0: -1; -} - -int -readchar() -{ - char ch; - - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\n"); - return -1; - } - } -} - -static char line[256]; -static char *lineptr; -static int lineleft; - -int -getchar() -{ - int c; - - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; - } - } - } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; -} - -extern int vsprintf(char *buf, const char *fmt, va_list args); -static char sprint_buf[1024]; - -void -printk(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); -} - -int -printf(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); - return n; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/string.S linux/arch/ppc/coffboot/string.S --- v2.4.4/linux/arch/ppc/coffboot/string.S Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/string.S Wed Dec 31 16:00:00 1969 @@ -1,206 +0,0 @@ -/* - * String handling functions for PowerPC. - * - * Copyright (C) 1996 Paul Mackerras. - * - * 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. - */ -#define r0 0 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 - - .globl strcpy -strcpy: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strncpy -strncpy: - cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - blr - - .globl strcat -strcat: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r5) - cmpwi 0,r0,0 - bne 1b - addi r5,r5,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strcmp -strcmp: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r5) - cmpwi 1,r3,0 - lbzu r0,1(r4) - subf. r3,r0,r3 - beqlr 1 - beq 1b - blr - - .globl strlen -strlen: - addi r4,r3,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - bne 1b - subf r3,r3,r4 - blr - - .globl memset -memset: - rlwimi r4,r4,8,16,23 - rlwimi r4,r4,16,0,15 - addi r6,r3,-4 - cmplwi 0,r5,4 - blt 7f - stwu r4,4(r6) - beqlr - andi. r0,r6,3 - add r5,r0,r5 - subf r6,r0,r6 - rlwinm r0,r5,32-2,2,31 - mtctr r0 - bdz 6f -1: stwu r4,4(r6) - bdnz 1b -6: andi. r5,r5,3 -7: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r6,3 -8: stbu r4,1(r6) - bdnz 8b - blr - - .globl bcopy -bcopy: - mr r6,r3 - mr r3,r4 - mr r4,r6 - b memcpy - - .globl memmove -memmove: - cmplw 0,r3,r4 - bgt backwards_memcpy - /* fall through */ - - .globl memcpy -memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - addi r6,r3,-4 - addi r4,r4,-4 - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ - mtctr r7 - bne 5f -1: lwz r7,4(r4) - lwzu r8,8(r4) - stw r7,4(r6) - stwu r8,8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,4(r4) - addi r5,r5,-4 - stwu r0,4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r4,r4,3 - addi r6,r6,3 -4: lbzu r0,1(r4) - stbu r0,1(r6) - bdnz 4b - blr -5: subfic r0,r0,4 - mtctr r0 -6: lbz r7,4(r4) - addi r4,r4,1 - stb r7,4(r6) - addi r6,r6,1 - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl backwards_memcpy -backwards_memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - add r6,r3,r5 - add r4,r4,r5 - beq 2f - andi. r0,r6,3 - mtctr r7 - bne 5f -1: lwz r7,-4(r4) - lwzu r8,-8(r4) - stw r7,-4(r6) - stwu r8,-8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,-4(r4) - subi r5,r5,4 - stwu r0,-4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 -4: lbzu r0,-1(r4) - stbu r0,-1(r6) - bdnz 4b - blr -5: mtctr r0 -6: lbzu r7,-1(r4) - stbu r7,-1(r6) - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl memcmp -memcmp: - cmpwi 0,r5,0 - blelr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r6) - lbzu r0,1(r4) - subf. r3,r0,r3 - bdnzt 2,1b - blr diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/zlib.c linux/arch/ppc/coffboot/zlib.c --- v2.4.4/linux/arch/ppc/coffboot/zlib.c Mon Jun 7 12:11:51 1999 +++ linux/arch/ppc/coffboot/zlib.c Wed Dec 31 16:00:00 1969 @@ -1,2148 +0,0 @@ -/* - * This file is derived from various .h and .c files from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. See zlib.h for conditions of - * distribution and use. - * - * Changes that have been made include: - * - changed functions not used outside this file to "local" - * - added minCompression parameter to deflateInit2 - * - added Z_PACKET_FLUSH (see zlib.h for details) - * - added inflateIncomp - * - * $Id: zlib.c,v 1.3 1999/05/27 22:22:54 cort Exp $ - */ - -/*+++++*/ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ - -#define _Z_UTIL_H - -#include "zlib.h" - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#define FAR - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern char *z_errmsg[]; /* indexed by 1-zlib_error */ - -#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) -/* To be used only when the state is known to be valid */ - -#ifndef NULL -#define NULL ((void *) 0) -#endif - - /* common constants */ - -#define DEFLATED 8 - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - - /* functions */ - -#include -#define zmemcpy memcpy -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include -# ifndef verbose -# define verbose 0 -# endif -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); - -/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ -/* void zcfree OF((voidpf opaque, voidpf ptr)); */ - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr, size) \ - (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) -#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} - -/* deflate.h -- internal compression state - * Copyright (C) 1995 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/*+++++*/ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -local inflate_blocks_statef * inflate_blocks_new OF(( - z_stream *z, - check_func c, /* check function */ - uInt w)); /* window size */ - -local int inflate_blocks OF(( - inflate_blocks_statef *, - z_stream *, - int)); /* initial return code */ - -local void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_addhistory OF(( - inflate_blocks_statef *, - z_stream *)); - -local int inflate_packet_flush OF(( - inflate_blocks_statef *)); - -/*+++++*/ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt Nalloc; /* number of these allocated here */ - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - local uInt inflate_hufts; -#endif - -local int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -local int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_stream *)); /* for zfree function */ - - -/*+++++*/ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -local inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_stream *)); - -local int inflate_codes OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -local void inflate_codes_free OF(( - inflate_codes_statef *, - z_stream *)); - - -/*+++++*/ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z) -z_stream *z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z) -z_stream *z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state, sizeof(struct internal_state)); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2(z, w) -z_stream *z; -int w; -{ - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; -/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ -/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit(z) -z_stream *z; -{ - return inflateInit2(z, DEF_WBITS); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z, f) -z_stream *z; -int f; -{ - int r; - uInt b; - - if (z == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) - { - z->state->mode = BAD; - z->msg = "unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = "invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - if ((b = NEXTBYTE) & 0x20) - { - z->state->mode = BAD; - z->msg = "invalid reserved bit"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = "incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - z->state->mode = BLOCKS; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = "incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int inflateIncomp(z) -z_stream *z; -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync(z) -z_stream *z; -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE - -/*+++++*/ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ - mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - int nblens; /* # elements allocated at blens */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl, *td; /* trees to free */ - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* - * The IBM 150 firmware munges the data right after _etext[]. This - * protects it. -- Cort - */ -local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; -/* And'ing with mask[n] masks the lower n bits */ -local uInt inflate_mask[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -/*+++++*/ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -local int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_stream *)); - - -/*+++++*/ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* Table for deflate from PKZIP's appnote.txt. */ -local uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -local void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -local inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_stream *z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -local int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = "invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if (((~b) >> 16) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : TYPE; - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BADB; - z->msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.trees.nblens = t; - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - s->mode = BADB; - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - s->mode = BADB; - z->msg = "invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BADB; - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local int inflate_blocks_free(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window, s->end - s->window); - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - Trace((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -local int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WRAP */ /* expand WRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -local int inflate_packet_flush(s) - inflate_blocks_statef *s; -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} - - -/*+++++*/ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - uIntf *, /* list of base values for non-simple codes */ - uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_stream *)); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -local void ffree OF(( - voidpf q, /* opaque pointer (not used) */ - voidpf p, /* what to free (not used) */ - uInt n)); /* number of bytes (not used) */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* actually lengths - 2; also see note #13 above about 258 */ -local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ -local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local uInt cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build(b, n, s, d, e, t, m, zs) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -uIntf *d; /* list of base values for non-simple codes */ -uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -z_stream *zs; /* for zalloc function */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (all zero length codes or an - over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } - q->word.Nalloc = z + 1; -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -local int inflate_trees_bits(c, bb, tb, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -z_stream *z; /* for zfree function */ -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tb, z); - z->msg = "incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_stream *z; /* for zfree function */ -{ - int r; - - /* build literal/length tree */ - if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_lock = 0; -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local uInt fixed_left = FIXEDH; -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc(q, n, s) -voidpf q; /* opaque pointer (not used) */ -uInt n; /* number of items */ -uInt s; /* size of item */ -{ - Assert(s == sizeof(inflate_huft) && n <= fixed_left, - "inflate_trees falloc overflow"); - if (q) s++; /* to make some compilers happy */ - fixed_left -= n; - return (voidpf)(fixed_mem + fixed_left); -} - - -local void ffree(q, p, n) -voidpf q; -voidpf p; -uInt n; -{ - Assert(0, "inflate_trees ffree called!"); - if (q) q = p; /* to make some compilers happy */ -} - - -local int inflate_trees_fixed(bl, bd, tl, td) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -{ - /* build fixed tables if not built already--lock out other instances */ - while (++fixed_lock > 1) - fixed_lock--; - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = ffree; - z.opaque = Z_NULL; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - fixed_built = 1; - } - fixed_lock--; - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -local int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_stream *z; /* for zfree function */ -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); - p = q; - } - return Z_OK; -} - -/*+++++*/ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl, *td; -z_stream *z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -local int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_stream *z; -{ - ZFREE(z, c, sizeof(struct inflate_codes_state)); - Tracev((stderr, "inflate: codes free\n")); -} - -/*+++++*/ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt n; - Bytef *p, *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - - -/*+++++*/ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -local int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl, *td; -inflate_blocks_statef *s; -z_stream *z; -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = "invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = "invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} - - -/*+++++*/ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ - -char *zlib_version = ZLIB_VERSION; - -char *z_errmsg[] = { -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -""}; - - -/*+++++*/ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf) {s1 += *buf++; s2 += s1;} -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); -#define DO16(buf) DO8(buf); DO8(buf); - -/* ========================================================================= */ -uLong adler32(adler, buf, len) - uLong adler; - Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - k -= 16; - } - if (k != 0) do { - DO1(buf); - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/coffboot/zlib.h linux/arch/ppc/coffboot/zlib.h --- v2.4.4/linux/arch/ppc/coffboot/zlib.h Sat Aug 16 09:51:08 1997 +++ linux/arch/ppc/coffboot/zlib.h Wed Dec 31 16:00:00 1969 @@ -1,432 +0,0 @@ -/* $Id: zlib.h,v 1.1 1997/07/31 07:16:15 paulus Exp $ */ - -/* - * This file is derived from zlib.h and zconf.h from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. - */ - -/* - * ==FILEVERSION 960122== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 0.95, Aug 16th, 1995. - - Copyright (C) 1995 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu - */ - -#ifndef _ZLIB_H -#define _ZLIB_H - -/* #include "zconf.h" */ /* included directly here */ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ - -/* - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. - */ - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints - * at addresses which are not a multiple of their size. - * Under DOS, -DFAR=far or -DFAR=__far may be needed. - */ - -#ifndef STDC -# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) -# define STDC -# endif -#endif - -#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ -# include -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -#ifndef FAR -# define FAR -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -/* end of original zconf.h */ - -#define ZLIB_VERSION "0.95P" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same - stream interface. - - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidp opaque; /* private data object passed to zalloc and zfree */ - - Byte data_type; /* best guess about the data type: ascii or binary */ - -} z_stream; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_FULL_FLUSH 2 -#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ -#define Z_FINISH 4 -#define Z_PACKET_FLUSH 5 -/* See deflate() below for the usage of these constants */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -/* error codes for the compression/decompression functions */ - -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Used to set the data_type field */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -extern char *zlib_version; -/* The application can compare zlib_version and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - */ - - /* basic functions */ - -extern int inflateInit OF((z_stream *strm)); -/* - Initializes the internal stream state for decompression. The fields - zalloc and zfree must be initialized before by the caller. If zalloc and - zfree are set to Z_NULL, inflateInit updates them to use default allocation - functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory. msg is set to null if there is no error message. - inflateInit does not perform any decompression: this will be done by - inflate(). -*/ - - -extern int inflate OF((z_stream *strm, int flush)); -/* - Performs one or both of the following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() always provides as much output as possible - (until there is no more input data or no more space in the output buffer). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). - - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, - inflate flushes as much output as possible to the output buffer. The - flushing behavior of inflate is not specified for values of the flush - parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - inflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if the end of the - compressed data has been reached and all uncompressed output has been - produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if - the stream structure was inconsistent (for example if next_in or next_out - was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no - progress is possible or if there was not enough room in the output buffer - when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then - call inflateSync to look for a good compression block. */ - - -extern int inflateEnd OF((z_stream *strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* advanced functions */ - -extern int inflateInit2 OF((z_stream *strm, - int windowBits)); -/* - This is another version of inflateInit with more compression options. The - fields next_out, zalloc and zfree must be initialized before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library (the value 16 will be allowed soon). The - default value is 15 if inflateInit is used instead. If a compressed stream - with a larger window size is given as input, inflate() will return with - the error code Z_DATA_ERROR instead of trying to allocate a larger window. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1< diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/apus_pci.c linux/arch/ppc/kernel/apus_pci.c --- v2.4.4/linux/arch/ppc/kernel/apus_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/apus_pci.c Mon May 21 17:04:46 2001 @@ -0,0 +1,189 @@ +/* + * BK Id: SCCS/s.apus_pci.c 1.3 05/17/01 18:14:21 cort + */ +/* + * Copyright (C) Michel Dänzer + * + * APUS PCI routines. + * + * Currently, only B/CVisionPPC cards (Permedia2) are supported. + * + * Thanks to Geert Uytterhoeven for the idea: + * Read values from given config space(s) for the first devices, -1 otherwise + * + */ + +#include +#ifdef CONFIG_AMIGA + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "apus_pci.h" + + +/* These definitions are mostly adapted from pm2fb.c */ + +#undef APUS_PCI_MASTER_DEBUG +#ifdef APUS_PCI_MASTER_DEBUG +#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b) +#else +#define DPRINTK(a,b...) +#endif + +/* + * The _DEFINITIVE_ memory mapping/unmapping functions. + * This is due to the fact that they're changing soooo often... + */ +#define DEFW() wmb() +#define DEFR() rmb() +#define DEFRW() mb() + +#define DEVNO(d) ((d)>>3) +#define FNNO(d) ((d)&7) + + +extern unsigned long powerup_PCI_present; + +static struct pci_controller *apus_hose; + + +__apus +void *pci_io_base(unsigned int bus) +{ + return 0; +} + + +#define cfg_read(val, addr, type, op) *val = op((type)(addr)) +#define cfg_write(val, addr, type, op) op((val), (type *)(addr)); DEFW() +#define cfg_read_bad *val = ~0; +#define cfg_write_bad ; +#define cfg_read_val(val) *val +#define cfg_write_val(val) val + +#define APUS_PCI_OP(rw, size, type, op, mask) \ +__apus int \ +apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + int fnno = FNNO(dev->devfn); \ + int devno = DEVNO(dev->devfn); \ + \ + if (dev->bus->number > 0 || devno != 1) { \ + cfg_##rw##_bad; \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + } \ + /* base address + function offset + offset ^ endianness conversion */ \ + cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask), \ + type, op); \ + \ + DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n", \ + dev->bus->number, dev->devfn>>3, dev->devfn&7, \ + offset, cfg_##rw##_val(val)); \ + return PCIBIOS_SUCCESSFUL; \ +} + +APUS_PCI_OP(read, byte, u8 *, readb, 3) +APUS_PCI_OP(read, word, u16 *, readw, 2) +APUS_PCI_OP(read, dword, u32 *, readl, 0) +APUS_PCI_OP(write, byte, u8, writeb, 3) +APUS_PCI_OP(write, word, u16, writew, 2) +APUS_PCI_OP(write, dword, u32, writel, 0) + + +static struct pci_ops apus_pci_ops = { + apus_pcibios_read_config_byte, + apus_pcibios_read_config_word, + apus_pcibios_read_config_dword, + apus_pcibios_write_config_byte, + apus_pcibios_write_config_word, + apus_pcibios_write_config_dword +}; + +static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM }; + +void __init +apus_pcibios_fixup(void) +{ +/* struct pci_dev *dev = pci_find_slot(0, 1<<3); + unsigned int reg, val, offset;*/ + + /* FIXME: interrupt? */ + /*dev->interrupt = xxx;*/ + + request_resource(&iomem_resource, &pci_mem); + printk("%s: PCI mem resource requested\n", __FUNCTION__); +} + +static void __init apus_pcibios_fixup_bus(struct pci_bus *bus) +{ + bus->resource[1] = &pci_mem; +} + + +/* + * This is from pm2fb.c again + * + * Check if PCI (B/CVisionPPC) is available, initialize it and set up + * the pcibios_* pointers + */ + + +void __init +apus_setup_pci_ptrs(void) +{ + if (!powerup_PCI_present) { + DPRINTK("no PCI bridge detected\n"); + return; + } + DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n"); + + apus_hose = pcibios_alloc_controller(); + if (!apus_hose) { + printk("apus_pci: Can't allocate PCI controller structure\n"); + return; + } + + if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) { + printk("apus_pci: unable to map PCI config region\n"); + return; + } + + if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) { + printk("apus_pci: unable to map PCI bridge\n"); + return; + } + + writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN); + DEFW(); + + writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0); + DEFW(); + writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1); + DEFW(); + writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2); + DEFW(); + writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS); + DEFW(); + + writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND); + DEFW(); + + apus_hose->first_busno = 0; + apus_hose->last_busno = 0; + apus_hose->ops = &apus_pci_ops; + ppc_md.pcibios_fixup = apus_pcibios_fixup; + ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus; + + return; +} + +#endif /* CONFIG_AMIGA */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/apus_pci.h linux/arch/ppc/kernel/apus_pci.h --- v2.4.4/linux/arch/ppc/kernel/apus_pci.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/apus_pci.h Mon May 21 17:04:46 2001 @@ -0,0 +1,40 @@ +/* + * BK Id: SCCS/s.apus_pci.h 1.4 05/17/01 18:14:21 cort + */ +/* + * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer + * driver. + * + * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) + * -------------------------------------------------------------------------- + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#ifndef APUS_PCI_H +#define APUS_PCI_H + + +#include "pci.h" + + +#define CSPPC_PCI_BRIDGE 0xfffe0000 +#define CSPPC_BRIDGE_ENDIAN 0x0000 +#define CSPPC_BRIDGE_INT 0x0010 + +#define CVPPC_PCI_CONFIG 0xfffc0000 +#define CVPPC_ROM_ADDRESS 0xe2000001 +#define CVPPC_REGS_REGION 0xef000000 +#define CVPPC_FB_APERTURE_ONE 0xe0000000 +#define CVPPC_FB_APERTURE_TWO 0xe1000000 +#define CVPPC_FB_SIZE 0x00800000 + +/* CVPPC_BRIDGE_ENDIAN */ +#define CSPPCF_BRIDGE_BIG_ENDIAN 0x02 + +/* CVPPC_BRIDGE_INT */ +#define CSPPCF_BRIDGE_ACTIVE_INT2 0x01 + + +#endif /* APUS_PCI_H */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.4.4/linux/arch/ppc/kernel/apus_setup.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/apus_setup.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.apus_setup.c 1.11 05/17/01 18:14:21 cort + */ +/* * linux/arch/ppc/kernel/apus_setup.c * * Copyright (C) 1998, 1999 Jesper Skov @@ -1017,6 +1020,59 @@ 0 }; +#define HARDWARE_MAPPED_SIZE (512*1024) +unsigned long __init apus_find_end_of_memory(void) +{ + int shadow = 0; + unsigned long total; + + /* The memory size reported by ADOS excludes the 512KB + reserved for PPC exception registers and possibly 512KB + containing a shadow of the ADOS ROM. */ + { + unsigned long size = memory[0].size; + + /* If 2MB aligned, size was probably user + specified. We can't tell anything about shadowing + in this case so skip shadow assignment. */ + if (0 != (size & 0x1fffff)){ + /* Align to 512KB to ensure correct handling + of both memfile and system specified + sizes. */ + size = ((size+0x0007ffff) & 0xfff80000); + /* If memory is 1MB aligned, assume + shadowing. */ + shadow = !(size & 0x80000); + } + + /* Add the chunk that ADOS does not see. by aligning + the size to the nearest 2MB limit upwards. */ + memory[0].size = ((size+0x001fffff) & 0xffe00000); + } + + total = memory[0].size; + + /* Remove the memory chunks that are controlled by special + Phase5 hardware. */ + + /* Remove the upper 512KB if it contains a shadow of + the ADOS ROM. FIXME: It might be possible to + disable this shadow HW. Check the booter + (ppc_boot.c) */ + if (shadow) + total -= HARDWARE_MAPPED_SIZE; + + /* Remove the upper 512KB where the PPC exception + vectors are mapped. */ + total -= HARDWARE_MAPPED_SIZE; + + /* Linux/APUS only handles one block of memory -- the one on + the PowerUP board. Other system memory is horrible slow in + comparison. The user can use other memory for swapping + using the z2ram device. */ + ram_phys_base = memory[0].addr; + return total; +} __init void apus_init_IRQ(void) @@ -1037,10 +1093,6 @@ amiga_init_IRQ(); - int_control.int_sti = __no_use_sti; - int_control.int_cli = __no_use_cli; - int_control.int_save_flags = __no_use_save_flags; - int_control.int_restore_flags = __no_use_restore_flags; } __init @@ -1072,7 +1124,10 @@ ppc_md.irq_cannonicalize = apus_irq_cannonicalize; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.get_irq = apus_get_irq; - ppc_md.post_irq = apus_post_irq; + +#error Should use the ->end() member of irq_desc[x]. -- Cort + /*ppc_md.post_irq = apus_post_irq;*/ + #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; @@ -1091,6 +1146,8 @@ ppc_md.set_rtc_time = apus_set_rtc_time; ppc_md.get_rtc_time = apus_get_rtc_time; ppc_md.calibrate_decr = apus_calibrate_decr; + + ppc_md.find_end_of_memory = apus_find_end_of_memory; ppc_md.nvram_read_val = NULL; ppc_md.nvram_write_val = NULL; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/bitops.c linux/arch/ppc/kernel/bitops.c --- v2.4.4/linux/arch/ppc/kernel/bitops.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/bitops.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.bitops.c 1.7 05/17/01 18:14:21 cort + */ +/* * Copyright (C) 1996 Paul Mackerras. */ @@ -16,10 +19,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - or %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + or %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -33,10 +36,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - andc %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + andc %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -50,10 +53,10 @@ unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%3 - xor %0,%0,%2 - stwcx. %0,0,%3 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%3 \n\ + xor %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -67,10 +70,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - or %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + or %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -86,10 +89,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - andc %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + andc %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -105,10 +108,10 @@ unsigned int mask = 1 << (nr & 0x1f); volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ -1: lwarx %0,0,%4 - xor %1,%0,%3 - stwcx. %1,0,%4 + __asm__ __volatile__(SMP_WMB "\n\ +1: lwarx %0,0,%4 \n\ + xor %1,%0,%3 \n\ + stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c --- v2.4.4/linux/arch/ppc/kernel/checks.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/kernel/checks.c Mon May 21 17:04:46 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.checks.c 1.6 05/17/01 18:14:21 cort + */ #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.4.4/linux/arch/ppc/kernel/chrp_pci.c Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/kernel/chrp_pci.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.chrp_pci.c 1.16 05/17/01 18:14:21 cort + */ +/* * CHRP pci routines. */ @@ -264,6 +267,7 @@ } } +#if 0 static struct { /* parent is iomem */ struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; @@ -297,62 +301,7 @@ { bus->resource[1] = &gg2_resources.pci_mem; } - -/* this is used by the pmac_pci code too... - paulus */ -void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - unsigned int *ranges; - int rlen = 0; - int memno = 0; - struct resource *res; - - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= 6 * sizeof(unsigned int)) >= 0) { - res = NULL; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[3]; - hose->io_base_virt = ioremap(ranges[3], ranges[5]); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[5] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ - if (primary) - isa_mem_base = ranges[3]; - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[3] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[3]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + ranges[5] - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += 6; - } -} +#endif /* 0 */ /* this is largely modeled and stolen after the pmac_pci code -- tgall */ @@ -366,8 +315,10 @@ volatile unsigned char *cfg; unsigned int *dma; #ifdef CONFIG_POWER3 - unsigned long *opprop = (unsigned long *) - get_property(find_path_device("/"), "platform-open-pic", NULL); + struct device_node *root = find_path_device("/"); + unsigned int *opprop = (unsigned int *) + get_property(root, "platform-open-pic", NULL); + int i; #endif for(; dev != NULL; dev = dev->next, ++index) { @@ -405,10 +356,11 @@ hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; - process_bridge_ranges(hose, dev, index == 0); + pci_process_bridge_OF_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 - openpic_setup_ISU(index, opprop[index+1]); + i = prom_n_addr_cells(root) * (index + 2) - 1; + openpic_setup_ISU(index, opprop[i]); #endif /* CONFIG_POWER3 */ /* check the first bridge for a property that we can @@ -442,7 +394,7 @@ void __init chrp_find_bridges(void) { - struct device_node *py; + struct device_node *py, *dev; char *model, *name; struct pci_controller* hose; @@ -453,7 +405,7 @@ #else /* CONFIG_POWER4 */ model = get_property(find_path_device("/"), "model", NULL); if (!strncmp("MOT", model, 3)) { - struct pci_controller* hose; + struct pci_controller *hose; hose = pcibios_alloc_controller(); if (!hose) @@ -463,8 +415,9 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); setup_grackle(hose, 0x20000); + pci_process_bridge_OF_ranges(hose, dev, 1); return; } @@ -485,25 +438,22 @@ /* Check that please. This must be the root of the OF * PCI tree (the root host bridge */ - hose->arch_data = find_devices("pci"); + hose->arch_data = dev = find_devices("pci"); name = get_property(find_path_device("/"), "name", NULL); if (!strncmp("IBM,7043-150", name, 12) || !strncmp("IBM,7046-155", name, 12) || !strncmp("IBM,7046-B50", name, 12) ) { setup_grackle(hose, 0x01000000); - isa_mem_base = 0x80000000; + pci_process_bridge_OF_ranges(hose, dev, 1); return; } /* LongTrail */ hose->ops = &gg2_pci_ops; pci_dram_offset = 0; - isa_mem_base = 0xf7000000; - hose->io_base_phys = (unsigned long) 0xf8000000; - hose->io_base_virt = ioremap(hose->io_base_phys, 0x10000); - isa_io_base = (unsigned long) hose->io_base_virt; - ppc_md.pcibios_fixup = gg2_pcibios_fixup; - ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; + pci_process_bridge_OF_ranges(hose, find_devices("pci"), 1); +// ppc_md.pcibios_fixup = gg2_pcibios_fixup; +// ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; #endif /* CONFIG_POWER4 */ } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.4/linux/arch/ppc/kernel/chrp_setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.chrp_setup.c 1.17 05/17/01 18:14:21 cort + */ +/* * linux/arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds @@ -67,6 +70,7 @@ void rtas_indicator_progress(char *, unsigned short); void bootx_text_progress(char *, unsigned short); +extern unsigned long pmac_find_end_of_memory(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, @@ -194,37 +198,36 @@ u8 type) { u8 level0, type0, active; - struct device_node *root; - - root = find_path_device("/"); - if (root && - !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13 ) ) - { - /* select logical device */ - sio_write(device, 0x07); - active = sio_read(0x30); - level0 = sio_read(0x70); - type0 = sio_read(0x71); - printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0, - !active ? "in" : ""); - if (level0 == level && type0 == type && active) - printk("OK\n"); - else { - printk("remapping to level %d, type %d, active\n", level, type); - sio_write(0x01, 0x30); - sio_write(level, 0x70); - sio_write(type, 0x71); - } - } + /* select logical device */ + sio_write(device, 0x07); + active = sio_read(0x30); + level0 = sio_read(0x70); + type0 = sio_read(0x71); + printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, + type0, !active ? "in" : ""); + if (level0 == level && type0 == type && active) + printk("OK\n"); + else { + printk("remapping to level %d, type %d, active\n", level, + type); + sio_write(0x01, 0x30); + sio_write(level, 0x70); + sio_write(type, 0x71); + } } static void __init sio_init(void) { - /* logical device 0 (KBC/Keyboard) */ - sio_fixup_irq("keyboard", 0, 1, 2); - /* select logical device 1 (KBC/Mouse) */ - sio_fixup_irq("mouse", 1, 12, 2); + struct device_node *root; + + if ((root = find_path_device("/")) && + !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { + /* logical device 0 (KBC/Keyboard) */ + sio_fixup_irq("keyboard", 0, 1, 2); + /* select logical device 1 (KBC/Mouse) */ + sio_fixup_irq("mouse", 1, 12, 2); + } } @@ -263,16 +266,19 @@ #ifndef CONFIG_POWER4 /* Some IBM machines don't have the hydra -- Cort */ - if ( !OpenPIC_Addr ) - { + if (!OpenPIC_Addr) { + struct device_node *root; unsigned long *opprop; + int n; - opprop = (unsigned long *)get_property(find_path_device("/"), - "platform-open-pic", NULL); + root = find_path_device("/"); + opprop = (unsigned long *) get_property + (root, "platform-open-pic", NULL); + n = prom_n_addr_cells(root); if (opprop != 0) { printk("OpenPIC addrs: %lx %lx %lx\n", - opprop[0], opprop[1], opprop[2]); - OpenPIC_Addr = ioremap(opprop[0], 0x40000); + opprop[n-1], opprop[2*n-1], opprop[3*n-1]); + OpenPIC_Addr = ioremap(opprop[n-1], 0x40000); } } #endif @@ -281,6 +287,10 @@ * Fix the Super I/O configuration */ sio_init(); + + /* + * Setup the console operations + */ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif @@ -356,7 +366,7 @@ { struct device_node *np; int i; - unsigned long *addrp; + unsigned int *addrp; unsigned char* chrp_int_ack_special = 0; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; int nmi_irq = -1; @@ -365,11 +375,12 @@ #endif if (!(np = find_devices("pci")) - || !(addrp = (unsigned long *) + || !(addrp = (unsigned int *) get_property(np, "8259-interrupt-acknowledge", NULL))) printk("Cannot find pci to get ack address\n"); else - chrp_int_ack_special = (unsigned char *)ioremap(*addrp, 1); + chrp_int_ack_special = (unsigned char *) + ioremap(addrp[prom_n_addr_cells(np)-1], 1); /* hydra still sets OpenPIC_InitSenses to a static set of values */ if (OpenPIC_InitSenses == NULL) { prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); @@ -553,11 +564,9 @@ #ifndef CONFIG_POWER4 ppc_md.init_IRQ = chrp_init_IRQ; ppc_md.get_irq = openpic_get_irq; - ppc_md.post_irq = NULL; #else ppc_md.init_IRQ = xics_init_IRQ; ppc_md.get_irq = xics_get_irq; - ppc_md.post_irq = NULL; #endif /* CONFIG_POWER4 */ ppc_md.init = chrp_init2; @@ -570,6 +579,8 @@ ppc_md.set_rtc_time = chrp_set_rtc_time; ppc_md.get_rtc_time = chrp_get_rtc_time; ppc_md.calibrate_decr = chrp_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT /* these are adjusted in chrp_init2 if we have an ADB keyboard */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.4.4/linux/arch/ppc/kernel/chrp_time.c Sun Sep 17 09:48:06 2000 +++ linux/arch/ppc/kernel/chrp_time.c Mon May 21 17:04:46 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.chrp_time.c 1.7 05/17/01 18:14:21 cort + */ +/* * linux/arch/i386/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds @@ -29,6 +32,8 @@ #include #include +extern spinlock_t rtc_lock; + static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; @@ -74,6 +79,7 @@ unsigned char save_control, save_freq_select; struct rtc_time tm; + spin_lock(&rtc_lock); to_tm(nowtime, &tm); save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ @@ -112,6 +118,7 @@ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) ) time_state = TIME_OK; + spin_unlock(&rtc_lock); return 0; } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.4.4/linux/arch/ppc/kernel/entry.S Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/entry.S Mon May 21 17:04:46 2001 @@ -1,8 +1,7 @@ /* - * arch/ppc/kernel/entry.S - * - * $Id: entry.S,v 1.4 1999/09/14 05:18:14 dmalek Exp $ - * + * BK Id: SCCS/s.entry.S 1.12 05/21/01 11:49:59 paulus + */ +/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP @@ -30,7 +29,6 @@ #include #include #include -#include "mol.h" #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -315,21 +313,12 @@ lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f - .globl lost_irq_ret -lost_irq_ret: -3: lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - beq+ 1f - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_IRQ - b 3b -1: lis r4,irq_stat@ha /* &softirq_active for cpu 0 */ + lis r4,irq_stat@ha /* &softirq_active for cpu 0 */ addi r4,r4,irq_stat@l #ifdef CONFIG_SMP /* get processor # */ lwz r3,PROCESSOR(r2) - slwi r3,r3,5 + slwi r3,r3,LG_CACHE_LINE_SIZE add r4,r4,r3 #endif /* CONFIG_SMP */ lwz r5,0(r4) /* softirq_active */ @@ -351,7 +340,6 @@ beq+ do_signal_ret li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD - MOL_HOOK_MMU(8,r8) bl do_signal .globl do_signal_ret do_signal_ret: @@ -373,7 +361,9 @@ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ - + + stwcx. r0,0,r1 /* to clear the reservation */ + /* if returning to user mode, set new sprg2 and save kernel SP */ lwz r0,_MSR(r1) andi. r0,r0,MSR_PR @@ -391,7 +381,6 @@ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ tophys(r8,r1) CLR_TOP32(r8) - MOL_HOOK_MMU(9, r4) /* mod. r0,r2-r7, lr, ctr */ mtspr SPRG2,r8 /* phys exception stack pointer */ 1: lwz r3,_CTR(r1) @@ -412,29 +401,6 @@ lwz r1,GPR1(r1) SYNC RFI - -/* - * Fake an interrupt from kernel mode. - * This is used when enable_irq loses an interrupt. - * We only fill in the stack frame minimally. - */ -_GLOBAL(fake_interrupt) - mflr r0 - stw r0,4(r1) - stwu r1,-INT_FRAME_SIZE(r1) - stw r0,_NIP(r1) - stw r0,_LINK(r1) - mfmsr r3 - stw r3,_MSR(r1) - li r0,0x0fac - stw r0,TRAP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - li r4,1 - bl do_IRQ - addi r1,r1,INT_FRAME_SIZE - lwz r0,4(r1) - mtlr r0 - blr /* diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/error_log.c linux/arch/ppc/kernel/error_log.c --- v2.4.4/linux/arch/ppc/kernel/error_log.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/error_log.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/error_log.c * * Copyright (c) 2000 Tilmann Bitterberg diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/error_log.h linux/arch/ppc/kernel/error_log.h --- v2.4.4/linux/arch/ppc/kernel/error_log.h Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/error_log.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort + */ #ifndef __ERROR_LOG_H__ #define __ERROR_LOG_H__ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.4.4/linux/arch/ppc/kernel/feature.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/feature.c Fri May 25 12:41:46 2001 @@ -1,18 +1,17 @@ /* + * BK Id: SCCS/s.feature.c 1.10 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/feature.c * * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. Herrenschmidt (bh40@calva.net) + * Ben. Herrenschmidt (benh@kernel.crashing.org) * * 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. * - * BenH: Changed implementation to work on multiple registers - * polarity is also taken into account. Removed delay (now - * responsibility of the caller). Added spinlocks. - * */ #include #include @@ -29,11 +28,12 @@ #include #include #include +#include +#include #undef DEBUG_FEATURE #define MAX_FEATURE_CONTROLLERS 2 -#define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) /* Keylargo reg. access. */ @@ -56,9 +56,7 @@ unsigned int mask; /* bit mask */ } fbit; -/* I don't have an OHare machine to test with, so I left those as they - * were. Someone with such a machine chould check out what OF says and - * try too see if they match the heathrow ones and should be changed too +/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500) */ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_null */ @@ -159,11 +157,12 @@ /* * Those bits are from a 1999 G3 PowerBook, with a paddington chip. - * Mostly the same as the heathrow. + * Mostly the same as the heathrow. They are used on both PowerBooks + * and desktop machines using the paddington chip */ static fbit feature_bits_paddington[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ @@ -192,6 +191,7 @@ }; /* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...). + * Note: Different sets may be needed for iBook, especially for sound */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ @@ -201,13 +201,13 @@ {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ - {0x3c,0,0}, /* FEATURE_IDE0_enable */ + {0x3c,0,KL1_EIDE0_ENABLE}, /* FEATURE_IDE0_enable */ {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ - {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ - {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ + {0x34,1,KL_MBCR_MB0_DEV_RESET}, /* FEATURE_Mediabay_reset */ + {0x34,1,KL_MBCR_MB0_DEV_POWER}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ - {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ + {0x3c,0,KL1_EIDE1_ENABLE}, /* FEATURE_IDE1_enable */ {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ @@ -216,10 +216,10 @@ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x3c,0,KL1_UIDE_ENABLE}, /* FEATURE_IDE2_enable */ {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ - {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ - {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ + {0x34,0,KL_MBCR_MB0_DEV_ENABLE},/* FEATURE_Mediabay_IDE_switch */ + {0x34,0,KL_MBCR_MB0_ENABLE}, /* FEATURE_Mediabay_content */ {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; @@ -238,6 +238,8 @@ static struct feature_controller* feature_lookup_controller(struct device_node *device); +static void uninorth_init(void); +static void keylargo_init(void); #ifdef CONFIG_PMAC_PBOOK static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); static void heathrow_wakeup(struct feature_controller* ctrler); @@ -245,32 +247,80 @@ static void core99_wake_up(struct feature_controller* ctrler); #endif /* CONFIG_PMAC_PBOOK */ -static void keylargo_init(void); -static void uninorth_init(void); - /* static variables */ static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; static int controller_count = 0; /* Core99 stuffs */ -static volatile u32* uninorth_base = NULL; -static volatile u32* keylargo_base = NULL; +/*static*/ volatile u32* uninorth_base; +static volatile u32* keylargo_base; +static struct feature_controller* keylargo; static int uninorth_rev; static int keylargo_rev; +static u32 board_features; +static u8 airport_pwr_regs[5]; +static int airport_pwr_state; +static struct device_node* airport_dev; + +#define FTR_NEED_OPENPIC_TWEAK 0x00000001 +#define FTR_CAN_NAP 0x00000002 +#define FTR_HAS_FW_POWER 0x00000004 +#define FTR_CAN_SLEEP 0x00000008 + +static struct board_features_t { + char* compatible; + u32 features; +} board_features_datas[] __initdata = +{ + { "AAPL,PowerMac G3", 0 }, /* Beige G3 */ + { "iMac,1", 0 }, /* First iMac (gossamer) */ + { "PowerMac1,1", 0 }, /* B&W G3 / Yikes */ + { "PowerMac1,2", 0 }, /* B&W G3 / Yikes */ + { "PowerMac2,1", FTR_CAN_SLEEP }, /* r128 based iMac */ + { "PowerMac2,2", FTR_HAS_FW_POWER|FTR_CAN_SLEEP }, /* Summer 2000 iMac */ + { "PowerMac4,1", FTR_CAN_SLEEP }, /* iMac "Flower Power" */ + { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */ + { "PowerMac3,2", 0 }, /* G4/Dual G4 */ + { "PowerMac3,3", FTR_NEED_OPENPIC_TWEAK }, /* G4/Dual G4 */ + { "PowerMac5,1", 0 }, /* Cube */ + { "AAPL,3400/2400", FTR_CAN_SLEEP }, /* 2400/3400 PowerBook */ + { "AAPL,3500", FTR_CAN_SLEEP }, /* 3500 PowerBook (G3) */ + { "AAPL,PowerBook1998", FTR_CAN_SLEEP }, /* Wallstreet PowerBook */ + { "PowerBook1,1", FTR_CAN_SLEEP }, /* 101 (Lombard) PowerBook */ + { "PowerBook2,1", FTR_CAN_SLEEP }, /* iBook */ + { "PowerBook2,2", FTR_CAN_SLEEP /*| FTR_CAN_NAP*/ }, /* iBook FireWire */ + { "PowerBook3,1", FTR_CAN_SLEEP|FTR_CAN_NAP| /* PowerBook 2000 (Pismo) */ + FTR_HAS_FW_POWER }, + { "PowerBook3,2", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* PowerBook Titanium */ + { "PowerBook4,1", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* New polycarbonate iBook */ + { NULL, 0 } +}; + +extern unsigned long powersave_nap; -/* - * WARNING ! This function is called early in setup_arch, neither the IO base - * nor the udelay calibration have been done yet - */ void feature_init(void) { struct device_node *np; u32 *rev; - + int i; + if (_machine != _MACH_Pmac) return; + /* Figure out motherboard type & options */ + for(i=0;board_features_datas[i].compatible;i++) { + if (machine_is_compatible(board_features_datas[i].compatible)) { + board_features = board_features_datas[i].features; + break; + } + } + + /* Set default value of powersave_nap on machines that support it */ + if (board_features & FTR_CAN_NAP) + powersave_nap = 1; + + /* Track those poor mac-io's */ np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, @@ -280,13 +330,25 @@ struct feature_controller* ctrler = feature_add_controller(np, feature_bits_keylargo); if (ctrler) { + keylargo = ctrler; keylargo_base = ctrler->reg; rev = (u32 *)get_property(ctrler->device, "revision-id", NULL); if (rev) keylargo_rev = *rev; + + rev = (u32 *)get_property(ctrler->device, "device-id", NULL); + if (rev && (*rev) == 0x0025) + keylargo_rev |= KL_PANGEA_REV; } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + /* We disable the modem power bit on Yikes as it can + * do bad things (it's the nvram power) + */ + if (machine_is_compatible("PowerMac1,1") || + machine_is_compatible("PowerMac1,2")) { + feature_bits_paddington[FEATURE_Modem_power].mask = 0; + } } else if (machine_is_compatible("AAPL,PowerBook1998")) { feature_add_controller(np, feature_bits_wallstreet); } else { @@ -311,11 +373,12 @@ } } - /* Handle core99 Uni-N */ + /* Locate core99 Uni-N */ np = find_devices("uni-n"); if (np && np->n_addrs > 0) { uninorth_base = ioremap(np->addrs[0].address, 0x1000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + printk("Uninorth at 0x%08x\n", np->addrs[0].address); } if (uninorth_base && keylargo_base) printk("Uni-N revision: %d, KeyLargo revision: %d\n", @@ -360,8 +423,12 @@ return NULL; } + /* We remap the entire mac-io here. Normally, this will just + * give us back our already existing BAT mapping + */ controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address, MAX_FEATURE_OFFSET); + controller_device->addrs[0].address, + controller_device->addrs[0].size); if (bits == NULL) { printk(KERN_INFO "Twiddling the magic ohare bits\n"); @@ -495,6 +562,12 @@ return bit->polarity ? (value == 0) : (value == bit->mask); } +int +feature_can_sleep(void) +{ + return ((board_features & FTR_CAN_SLEEP) != 0); +} + /* * Core99 functions * @@ -506,53 +579,220 @@ void feature_set_gmac_power(struct device_node* device, int power) { - if (!uninorth_base) + unsigned long flags; + + if (!uninorth_base || !keylargo) return; + + /* TODO: Handle save/restore of PCI config space here + */ + + spin_lock_irqsave(&keylargo->lock, flags); if (power) UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); else UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + spin_unlock_irqrestore(&keylargo->lock, flags); udelay(20); } void -feature_set_gmac_phy_reset(struct device_node* device, int reset) +feature_gmac_phy_reset(struct device_node* device) { - if (!keylargo_base) + unsigned long flags; + + if (!keylargo_base || !keylargo) return; - out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), + KEYLARGO_GPIO_OUTPUT_ENABLE); (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); + mdelay(10); + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); + mdelay(10); } /* Pass the node of the correct controller, please */ void feature_set_usb_power(struct device_node* device, int power) { + char* prop; + int number; + u32 reg; + + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + prop = (char *)get_property(device, "AAPL,clock-id", NULL); + if (!prop) + return; + if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + number = 2; + else + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) { + /* Turn ON */ + + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else { + KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } + reg = KL_IN(KEYLARGO_FCR4); + reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); + reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(10); + } else { + /* Turn OFF */ + + reg = KL_IN(KEYLARGO_FCR4); + reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); + reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(1); + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } else { + KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } + udelay(1); + } + spin_unlock_irqrestore(&keylargo->lock, flags); } -/* Not yet implemented */ void feature_set_firewire_power(struct device_node* device, int power) { + unsigned long flags; + + /* TODO: Handle save/restore of PCI config space here + */ + if (!uninorth_base) return; + spin_lock_irqsave(&keylargo->lock, flags); if (power) UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); else UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); udelay(20); + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Warning: will kill the PHY.. */ +void +feature_set_firewire_cable_power(struct device_node* device, int power) +{ + unsigned long flags; + u8 gpioValue = power ? 0 : 4; + + if (!keylargo_base || !(board_features & FTR_HAS_FW_POWER)) + return; + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER), gpioValue); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER)); + spin_unlock_irqrestore(&keylargo->lock, flags); } #ifdef CONFIG_SMP void -feature_core99_kick_cpu1(void) +feature_core99_kick_cpu(int cpu_nr) { - out_8((volatile u8 *)KL_FCR(KL_GPIO_KICK_CPU1), KL_GPIO_KICK_CPU1_UP); +#if 1 /* New way */ + const int reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; + volatile u8* reset_io; + + if (!keylargo_base || cpu_nr > 3) + return; + reset_io = (volatile u8*)KL_FCR(reset_lines[cpu_nr]); + out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + udelay(1); + out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); +#else + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT); udelay(1); - out_8((volatile u8 *)KL_FCR(KL_GPIO_KICK_CPU1), KL_GPIO_KICK_CPU1_DOWN); + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE); +#endif } #endif /* CONFIG_SMP */ +void +feature_set_airport_power(struct device_node* device, int power) +{ + if (!keylargo_base || !airport_dev || airport_dev != device) + return; + if (airport_pwr_state == power) + return; + if (power) { + /* Some if this is from Darwin code, some is from tracing of + * MacOS driver with Macsbug. Some real bit definitions would + * really help here... + */ + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), airport_pwr_regs[0]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), airport_pwr_regs[1]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), airport_pwr_regs[2]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), airport_pwr_regs[3]); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), airport_pwr_regs[4]); + udelay(20); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 5); + udelay(20); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 4); + mdelay(20); + KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + udelay(10); + out_8((volatile u8*)KL_FCR(0x1a3e0), 0x41); + udelay(10); + KL_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + udelay(10); + } else { + airport_pwr_regs[0] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0)); + airport_pwr_regs[1] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1)); + airport_pwr_regs[2] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2)); + airport_pwr_regs[3] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3)); + airport_pwr_regs[4] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4)); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), 0); + out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 0); + } + airport_pwr_state = power; +} + /* Initialize the Core99 UniNorth host bridge and memory controller */ static void @@ -563,51 +803,106 @@ /* Set the arbitrer QAck delay according to what Apple does */ - actrl = in_be32(UN_REG(UNI_N_ARB_CTRL)) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; - actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) - << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; - UN_OUT(UNI_N_ARB_CTRL, actrl); + if (uninorth_rev < 0x10) { + actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : + UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + } - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe */ gmac = find_devices("ethernet"); - while(gmac) { if (device_is_compatible(gmac, "gmac")) break; gmac = gmac->next; } if (gmac) - feature_set_gmac_power(gmac, 0); + feature_set_gmac_power(gmac, 1); - /* Kludge (enable FW before PCI probe) */ + /* Enable FW before PCI probe. Will be disabled later on + */ fw = find_devices("firewire"); if (fw && device_is_compatible(fw, "pci106b,18")) feature_set_firewire_power(fw, 1); } -/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure - * OpenPIC is enabled +/* Initialize the Core99 KeyLargo ASIC. */ static void keylargo_init(void) { + struct device_node* np; + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); + + /* Lookup for an airport card, and disable it if found + * to save power (will be re-enabled by driver if used) + */ + np = find_devices("radio"); + if (np && np->parent == keylargo->device) + airport_dev = np; + + if (airport_dev) { + airport_pwr_state = 1; + feature_set_airport_power(airport_dev, 0); + } + } #ifdef CONFIG_PMAC_PBOOK +void +feature_prepare_for_sleep(void) +{ + /* We assume gatwick is second */ + struct feature_controller* ctrler = &controllers[0]; + + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_prepare_for_sleep(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_prepare_for_sleep(ctrler); + return; + } +} + + +void +feature_wake_up(void) +{ + struct feature_controller* ctrler = &controllers[0]; + + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_wakeup(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_wake_up(ctrler); + return; + } +} static u32 save_fcr[5]; static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; +static u32 save_unin_clock_ctl; +static struct dbdma_regs save_dbdma[13]; + static void heathrow_prepare_for_sleep(struct feature_controller* ctrler) @@ -631,60 +926,226 @@ } static void -core99_prepare_for_sleep(struct feature_controller* ctrler) +turn_off_keylargo(void) { - /* Not yet implemented */ + u32 temp; + + /* For now, suspending the USB ref cause the machine to die on + * wakeup -- BenH + */ +#if 0 + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)KL_IN(KEYLARGO_FCR0); + mdelay(1500); +#endif + + KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | + KL0_IRDA_CLK19_ENABLE); + + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + + KL_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | + KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | + KL1_UIDE_ENABLE); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + + KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); + udelay(10); + temp = KL_IN(KEYLARGO_FCR3); + if (keylargo_rev >= 2) + temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); } static void -core99_wake_up(struct feature_controller* ctrler) +turn_off_pangea(void) { - /* Not yet implemented */ + u32 temp; + + KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + + KL_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_UIDE_ENABLE); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + + KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + temp = KL_IN(KEYLARGO_FCR3); + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); } -void -feature_prepare_for_sleep(void) +static void +core99_prepare_for_sleep(struct feature_controller* ctrler) { - /* We assume gatwick is second */ - struct feature_controller* ctrler = &controllers[0]; + int i; + u8* base8; + + /* + * Save various bits of KeyLargo + */ - if (!ctrler) - return; - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; + /* We power off the wireless slot in case it was not done + * by the driver. We don't power it on automatically however + */ + feature_set_airport_power(airport_dev, 0); - if (ctrler->bits == feature_bits_heathrow || - ctrler->bits == feature_bits_paddington) { - heathrow_prepare_for_sleep(ctrler); - return; + /* We power off the FW cable. Should be done by the driver... */ + feature_set_firewire_cable_power(NULL, 0); + + /* Save the state of the various GPIOs */ + save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i>2)); + save_dbdma[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); + save_dbdma[i].cmdptr = in_le32(&chan->cmdptr); + save_dbdma[i].intr_sel = in_le32(&chan->intr_sel); + save_dbdma[i].br_sel = in_le32(&chan->br_sel); + save_dbdma[i].wait_sel = in_le32(&chan->wait_sel); } - if (ctrler->bits == feature_bits_keylargo) { - core99_prepare_for_sleep(ctrler); - return; + + /* + * Turn off as much as we can + */ + if (keylargo_rev & KL_PANGEA_REV) + turn_off_pangea(); + else + turn_off_keylargo(); + + /* + * Put the host bridge to sleep + */ + + save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & + ~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); + udelay(100); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (board_features & FTR_NEED_OPENPIC_TWEAK) { + KL_BIS(0x506e0, 0x00400000); + KL_BIS(0x506e0, 0x80000000); } } -void -feature_wake_up(void) +static void +core99_wake_up(struct feature_controller* ctrler) { - struct feature_controller* ctrler = &controllers[0]; + int i; + u8* base8; - if (!ctrler) - return; - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); - if (ctrler->bits == feature_bits_heathrow || - ctrler->bits == feature_bits_paddington) { - heathrow_wakeup(ctrler); - return; + /* + * Restore KeyLargo + */ + + KL_OUT(KEYLARGO_MBCR, save_mbcr); + (void)KL_IN(KEYLARGO_MBCR); udelay(10); + KL_OUT(KEYLARGO_FCR0, save_fcr[0]); + (void)KL_IN(KEYLARGO_FCR0); udelay(10); + KL_OUT(KEYLARGO_FCR1, save_fcr[1]); + (void)KL_IN(KEYLARGO_FCR1); udelay(10); + KL_OUT(KEYLARGO_FCR2, save_fcr[2]); + (void)KL_IN(KEYLARGO_FCR2); udelay(10); + KL_OUT(KEYLARGO_FCR3, save_fcr[3]); + (void)KL_IN(KEYLARGO_FCR3); udelay(10); + KL_OUT(KEYLARGO_FCR4, save_fcr[4]); + (void)KL_IN(KEYLARGO_FCR4); udelay(10); + + for (i=0; i<13; i++) { + volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) + (keylargo_base + ((0x8000+i*0x100)>>2)); + out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); + while (in_le32(&chan->status) & ACTIVE) + mb(); + out_le32(&chan->cmdptr_hi, save_dbdma[i].cmdptr_hi); + out_le32(&chan->cmdptr, save_dbdma[i].cmdptr); + out_le32(&chan->intr_sel, save_dbdma[i].intr_sel); + out_le32(&chan->br_sel, save_dbdma[i].br_sel); + out_le32(&chan->wait_sel, save_dbdma[i].wait_sel); } - if (ctrler->bits == feature_bits_keylargo) { - core99_wake_up(ctrler); - return; + + KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/galaxy_pci.c linux/arch/ppc/kernel/galaxy_pci.c --- v2.4.4/linux/arch/ppc/kernel/galaxy_pci.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/galaxy_pci.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.galaxy_pci.c 1.7 05/17/01 18:14:21 cort + */ +/* * * Copyright (c) 2000 Grant Erickson * All rights reserved. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c --- v2.4.4/linux/arch/ppc/kernel/gemini_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_pci.c Mon May 21 17:04:47 2001 @@ -0,0 +1,124 @@ +/* + * BK Id: SCCS/s.gemini_pci.c 1.5 05/17/01 18:14:21 cort + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#define pci_config_addr(bus,dev,offset) \ + (0x80000000 | (bus<<16) | (dev<<8) | offset) + + +int +gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val) +{ + unsigned long reg; + reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val) +{ + *val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val) +{ + unsigned long reg; + int shifts = offset & 0x3; + unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))); + + reg = grackle_read(addr); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write(addr, reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val) +{ + grackle_write(pci_config_addr(dev->bus->number, dev->devfn, + (offset & ~(0x3))), val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gemini_pci_ops = +{ + gemini_pcibios_read_config_byte, + gemini_pcibios_read_config_word, + gemini_pcibios_read_config_dword, + gemini_pcibios_write_config_byte, + gemini_pcibios_write_config_word, + gemini_pcibios_write_config_dword +}; + +void __init gemini_pcibios_fixup(void) +{ + int i; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + for(i = 0; i < 6; i++) { + if (dev->resource[i].flags & IORESOURCE_IO) { + dev->resource[i].start |= (0xfe << 24); + dev->resource[i].end |= (0xfe << 24); + } + } + } +} + + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_find_bridges(void) +{ + struct pci_controller* hose; + + ppc_md.pcibios_fixup = gemini_pcibios_fixup; + + hose = pcibios_alloc_controller(); + if (!hose) + return; + hose->ops = &gemini_pci_ops; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S --- v2.4.4/linux/arch/ppc/kernel/gemini_prom.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_prom.S Mon May 21 17:04:47 2001 @@ -0,0 +1,99 @@ +/* + * BK Id: SCCS/s.gemini_prom.S 1.5 05/17/01 18:14:21 cort + */ +/* + * arch/ppc/kernel/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" +#include +#include +#include +#include + +#define HID0_ABE (1<<3) + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef CONFIG_SMP + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 + isync +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr IBAT0U,r3 + mtspr IBAT0L,r3 + mtspr IBAT1U,r3 + mtspr IBAT1L,r3 + mtspr IBAT2U,r3 + mtspr IBAT2L,r3 + mtspr IBAT3U,r3 + mtspr IBAT3L,r3 + + mtspr DBAT0U,r3 + mtspr DBAT0L,r3 + mtspr DBAT1U,r3 + mtspr DBAT1L,r3 + mtspr DBAT2U,r3 + mtspr DBAT2L,r3 + mtspr DBAT3U,r3 + mtspr DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef CONFIG_SMP + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,HID0 + ori r4,r4,HID0_ABE + mtspr HID0,r4 + sync +#endif /* CONFIG_SMP */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SRR0,r5 + mtspr SRR1,r6 + rfi diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.4.4/linux/arch/ppc/kernel/gemini_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/gemini_setup.c Mon May 21 17:04:47 2001 @@ -0,0 +1,540 @@ +/* + * BK Id: SCCS/s.gemini_setup.c 1.7 05/17/01 18:14:21 cort + */ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local_irq.h" +#include "open_pic.h" + +void gemini_find_bridges(void); +static int gemini_get_clock_speed(void); +extern void gemini_pcibios_fixup(void); + +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" +}; +static int gemini_board_count = sizeof(gemini_board_families) / + sizeof(gemini_board_families[0]); + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + +int chrp_get_irq(struct pt_regs *); +void chrp_post_irq(struct pt_regs* regs, int); + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +/* + * prom_init is the Gemini version of prom.c:prom_init. We only need + * the BSS clearing code, so I copied that out of prom.c. This is a + * lot simpler than hacking prom.c so it will build with Gemini. -VAL + */ + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) + +unsigned long +prom_init(void) +{ + unsigned long offset = reloc_offset(); + unsigned long phys; + extern char __bss_start, _end; + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + + /* Default */ + phys = offset + KERNELBASE; + + gemini_prom_init(); + + return phys; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int len; + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > gemini_board_count) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + len = sprintf(buffer, "board\t\t: Gemini %s", family); + if (type > 9) + len += sprintf(buffer+len, "%c", (type - 10) + 'A'); + else + len += sprintf(buffer+len, "%d", type); + + len += sprintf(buffer+len, ", rev %c, eco %d\n", + (rev + 'A'), (reg & 0xf)); + + len += sprintf(buffer+len, "clock\t\t: %dMhz\n", + gemini_get_clock_speed()); + + return len; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + + OpenPIC_Addr = (volatile struct OpenPIC *) + grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); +} + + +extern unsigned long loops_per_jiffy; +extern int root_mountflags; +extern char cmd_line[]; + +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} + +void __init gemini_setup_arch(void) +{ + extern char cmd_line[]; + + + loops_per_jiffy = 50000000/HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0801); + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + + /* Lookup PCI hosts */ + gemini_find_bridges(); + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + /* start the L2 */ + gemini_init_l2(); +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1, pvr = _get_PVR(); + int clock; + + hid1 = (_get_HID1() >> 28) & 0xf; + if (PVR_VER(pvr) == 8 || + PVR_VER(pvr) == 12) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50); + break; + } + + return clock; +} + +void __init gemini_init_l2(void) +{ + unsigned char reg, brev, fam, creg; + unsigned long cache; + unsigned long pvr = _get_PVR(); + + reg = readb(GEMINI_L2CFG); + brev = readb(GEMINI_BREV); + fam = readb(GEMINI_FEAT); + + switch(PVR_VER(pvr)) { + + case 8: + if (reg & 0xc0) + cache = (((reg >> 6) & 0x3) << 28); + else + cache = 0x3 << 28; + +#ifdef CONFIG_SMP + /* Pre-3.0 processor revs had snooping errata. Leave + their L2's disabled with SMP. -- Dan */ + if (PVR_CFG(pvr) < 3) { + printk("Pre-3.0 750; L2 left disabled!\n"); + return; + } +#endif /* CONFIG_SMP */ + + /* Special case: VGM5-B's came before L2 ratios were set on + the board. Processor speed shouldn't be too high, so + set L2 ratio to 1:1.5. */ + if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) + reg |= 1; + + /* determine best cache ratio based upon what the board + tells us (which sometimes _may_ not be true) and + the processor speed. */ + else { + if (gemini_get_clock_speed() > 250) + reg = 2; + } + break; + case 12: + { + static unsigned long l2_size_val = 0; + + if (!l2_size_val) + l2_size_val = _get_L2CR(); + cache = l2_size_val; + break; + } + case 4: + case 9: + creg = readb(GEMINI_CPUSTAT); + if (((creg & 0xc) >> 2) != 1) + printk("Dual-604 boards don't support the use of L2\n"); + else + writeb(1, GEMINI_L2CFG); + return; + default: + printk("Unknown processor; L2 left disabled\n"); + return; + } + + cache |= ((1<>2)&0x3) { + case 0: + default: + freq = 66667; + break; + case 1: + freq = 83000; + break; + case 2: + freq = 100000; + break; + } + + freq *= 1000; + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); +} + +unsigned long __init gemini_find_end_of_memory(void) +{ + unsigned long total; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + return total; +} + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + int i; + int chrp_get_irq( struct pt_regs * ); + + for(i = 0; i < GEMINI_LEDS; i++) + gemini_led_off(i); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = gemini_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + ppc_md.find_end_of_memory = gemini_find_end_of_memory; + + /* no keyboard/mouse/video stuff yet.. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif + ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; +} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S --- v2.4.4/linux/arch/ppc/kernel/hashtable.S Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/hashtable.S Mon May 21 17:04:47 2001 @@ -1,8 +1,9 @@ /* + * BK Id: SCCS/s.hashtable.S 1.11 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/hashtable.S * - * $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $ - * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP @@ -27,7 +28,6 @@ #include #include #include -#include "mol.h" /* * Load a PTE into the hash table, if possible. @@ -609,11 +609,6 @@ * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) -#ifdef CONFIG_MOL - mflr r10 - MOL_HOOK_MMU(10, r6) - mtlr r10 -#endif lis r6,Hash@ha lwz r6,Hash@l(r6) /* hash table base */ cmpwi 0,r6,0 /* hash table in use? */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.4.4/linux/arch/ppc/kernel/head.S Sat Mar 3 10:52:13 2001 +++ linux/arch/ppc/kernel/head.S Thu May 24 15:03:05 2001 @@ -1,8 +1,7 @@ /* - * arch/ppc/kernel/head.S - * - * $Id: head.S,v 1.154 1999/10/12 00:33:31 cort Exp $ - * + * BK Id: SCCS/s.head.S 1.21 05/23/01 00:38:42 cort + */ +/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * @@ -31,24 +30,11 @@ #include #include #include -#include "mol.h" #ifdef CONFIG_APUS #include #endif -#ifndef CONFIG_PPC64BRIDGE -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 -#else -CACHELINE_BYTES = 128 -LG_CACHELINE_BYTES = 7 -CACHELINE_MASK = 0x7f -CACHELINE_WORDS = 32 -#endif /* CONFIG_PPC64BRIDGE */ - #ifdef CONFIG_PPC64BRIDGE #define LOAD_BAT(n, reg, RA, RB) \ ld RA,(n*32)+0(reg); \ @@ -149,9 +135,12 @@ mr r28,r6 mr r27,r7 li r24,0 /* cpu # */ - /* N.B. prom_init clears the BSS even if it doesn't do - * anything else -- paulus. */ - bl prom_init +/* + * early_init() does the early machine identification and does + * the necessary low-level setup and clears the BSS + * -- Cort + */ + bl early_init #ifdef CONFIG_APUS /* On APUS the __va/__pa constants need to be set to the correct @@ -161,6 +150,7 @@ bl fix_mem_constants #endif /* CONFIG_APUS */ +#ifndef CONFIG_GEMINI /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ @@ -168,6 +158,7 @@ __after_mmu_off: bl clear_bats bl flush_tlbs +#endif #ifndef CONFIG_POWER4 /* POWER4 doesn't have BATs */ @@ -294,21 +285,14 @@ .long hdlr; \ .long ret_from_except -#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ - . = n; \ -label: \ - EXCEPTION_PROLOG; \ - MOL_HOOK(hook); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - li r20,MSR_KERNEL; \ - bl transfer_to_handler; \ -i##n: \ - .long hdlr; \ - .long ret_from_except - /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ +#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ +#ifdef CONFIG_GEMINI + . = 0x100 + b __secondary_start_gemini +#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -325,7 +309,6 @@ DataAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ - MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -369,7 +352,6 @@ InstructionAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ - MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -436,7 +418,6 @@ . = 0x700 ProgramCheck: EXCEPTION_PROLOG - MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ @@ -449,7 +430,6 @@ . = 0x800 FPUnavailable: EXCEPTION_PROLOG - MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -460,7 +440,6 @@ . = 0x900 Decrementer: EXCEPTION_PROLOG - MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler @@ -484,7 +463,7 @@ .long ret_from_except /* Single step - not used on 601 */ - STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) + STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) /* @@ -514,7 +493,6 @@ */ . = 0x1000 InstructionTLBMiss: - MOL_HOOK_TLBMISS( 14 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -586,7 +564,6 @@ */ . = 0x1100 DataLoadTLBMiss: - MOL_HOOK_TLBMISS( 15 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -657,7 +634,6 @@ */ . = 0x1200 DataStoreTLBMiss: - MOL_HOOK_TLBMISS( 16 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -704,7 +680,7 @@ mtcrf 0x80,r3 rfi - STD_MOL_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, 11) + STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -717,7 +693,7 @@ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - STD_MOL_EXCEPTION(0x2000, RunMode, RunModeException, 5) + STD_EXCEPTION(0x2000, RunMode, RunModeException) STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -739,7 +715,6 @@ #ifdef CONFIG_ALTIVEC AltiVecUnavailable: EXCEPTION_PROLOG - MOL_HOOK_RESTORE(12) bne load_up_altivec /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -792,8 +767,6 @@ mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) - li r22,RESULT - stwcx. r22,r22,r21 /* to clear the reservation */ li r22,0 stw r22,RESULT(r21) mtspr SPRG2,r22 /* r1 is now kernel sp */ @@ -805,7 +778,6 @@ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ FIX_SRR1(r20,r22) - MOL_HOOK(6) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 @@ -1016,11 +988,6 @@ .globl giveup_altivec giveup_altivec: -#ifdef CONFIG_MOL - mflr r4 - MOL_HOOK_MMU(13, r5) - mtlr r4 -#endif mfmsr r5 oris r5,r5,MSR_VEC@h SYNC @@ -1057,11 +1024,6 @@ */ .globl giveup_fpu giveup_fpu: -#ifdef CONFIG_MOL - mflr r4 - MOL_HOOK_MMU(7, r5) - mtlr r4 -#endif mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1116,7 +1078,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,CACHELINE_WORDS +4: li r0,CACHE_LINE_SIZE/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 @@ -1127,6 +1089,7 @@ icbi r6,r3 /* flush the icache line */ cmplw 0,r6,r5 blt 4b + sync /* additional sync needed on g4 */ isync addi r5,r5,4 addi r6,r6,4 @@ -1165,6 +1128,7 @@ icbi r0,r14 /* flush the icache line */ cmpw r12,r13 bne 1b + sync /* additional sync needed on g4 */ isync /* @@ -1199,6 +1163,7 @@ cmpw r12,r13 bne 1b + sync /* additional sync needed on g4 */ isync /* No speculative loading until now */ blr @@ -1266,6 +1231,20 @@ #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP +#ifdef CONFIG_GEMINI + .globl __secondary_start_gemini +__secondary_start_gemini: + mfspr r4,HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr HID0,r4 + sync + bl prom_init + b __secondary_start +#endif /* CONFIG_GEMINI */ + .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ @@ -1536,6 +1515,7 @@ * -- Cort */ clear_bats: +#if !defined(CONFIG_GEMINI) li r20,0 mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ @@ -1559,8 +1539,10 @@ mtspr IBAT2L,r20 mtspr IBAT3U,r20 mtspr IBAT3L,r20 +#endif /* !defined(CONFIG_GEMINI) */ blr +#ifndef CONFIG_GEMINI flush_tlbs: lis r20, 0x40 1: addic. r20, r20, -0x1000 @@ -1579,6 +1561,7 @@ mtspr SRR1,r3 sync RFI +#endif #ifndef CONFIG_POWER4 /* @@ -1690,17 +1673,6 @@ blr #endif -#ifdef CONFIG_MOL -/* - * Mac-on-linux hook_table. Don't put this in the data section - - * the base address must be within the first 32KB of RAM. - */ - .globl mol_interface -mol_interface: - .long MOL_INTERFACE_VERSION - .fill 24,4,0 /* space for 24 hooks */ -#endif - /* * We put a few things here that have to be page-aligned. @@ -1728,7 +1700,7 @@ .globl intercept_table intercept_table: - .long 0, i0x100, i0x200, i0x300, i0x400, 0, i0x600, i0x700 + .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700 .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0 .long 0, 0, 0, i0x1300, 0, 0, 0, 0 .long 0, 0, 0, 0, 0, 0, 0, 0 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/head_4xx.S linux/arch/ppc/kernel/head_4xx.S --- v2.4.4/linux/arch/ppc/kernel/head_4xx.S Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/kernel/head_4xx.S Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.head_4xx.S 1.6 05/21/01 11:50:00 paulus + */ +/* * Copyright (c) 1995-1996 Gary Thomas * Initial PowerPC version. * Copyright (c) 1996 Cort Dougan @@ -387,8 +390,6 @@ mflr r23 andi. r24,r23,0x3f00 # Get vector offset stw r24,TRAP(r21) - li r22,RESULT - stwcx. r22,r22,r21 # Clear the reservation li r22,0 stw r22,RESULT(r21) mtspr SPRN_SPRG2,r22 # r1 is now the kernel stack pointer diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S --- v2.4.4/linux/arch/ppc/kernel/head_8xx.S Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/head_8xx.S Mon May 21 17:04:47 2001 @@ -1,8 +1,9 @@ /* + * BK Id: SCCS/s.head_8xx.S 1.11 05/21/01 11:50:00 paulus + */ +/* * arch/ppc/kernel/except_8xx.S * - * $Id: head_8xx.S,v 1.4 1999/09/18 18:43:19 dmalek Exp $ - * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP @@ -30,13 +31,6 @@ #include #include #include - -/* XXX need definitions here for 16 byte cachelines on some/all 8xx - -- paulus */ -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 .text .globl _stext @@ -685,8 +679,6 @@ mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) - li r22,RESULT - stwcx. r22,r22,r21 /* to clear the reservation */ li r22,0 stw r22,RESULT(r21) mtspr SPRG2,r22 /* r1 is now kernel sp */ @@ -757,7 +749,7 @@ copy_and_flush: addi r5,r5,-4 addi r6,r6,-4 -4: li r0,CACHELINE_WORDS +4: li r0,CACHE_LINE_SIZE/4 mtctr r0 3: addi r6,r6,4 /* copy a cache line */ lwzx r0,r6,r4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c --- v2.4.4/linux/arch/ppc/kernel/i8259.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/i8259.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.i8259.c 1.7 05/17/01 18:14:21 cort + */ #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/i8259.h linux/arch/ppc/kernel/i8259.h --- v2.4.4/linux/arch/ppc/kernel/i8259.h Tue May 11 08:24:32 1999 +++ linux/arch/ppc/kernel/i8259.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.i8259.h 1.5 05/17/01 18:14:21 cort + */ #ifndef _PPC_KERNEL_i8259_H #define _PPC_KERNEL_i8259_H diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.4.4/linux/arch/ppc/kernel/idle.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/kernel/idle.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: idle.c,v 1.68 1999/10/15 18:16:03 cort Exp $ - * + * BK Id: SCCS/s.idle.c 1.11 05/17/01 18:14:21 cort + */ +/* * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. * @@ -56,6 +57,7 @@ case 7: /* 603ev */ case 8: /* 750 */ case 12: /* 7400 */ + case 0x800c: /* 7410 */ do_power_save = 1; } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/indirect_pci.c linux/arch/ppc/kernel/indirect_pci.c --- v2.4.4/linux/arch/ppc/kernel/indirect_pci.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/indirect_pci.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.indirect_pci.c 1.7 05/17/01 18:14:21 cort + */ +/* * Support for indirect PCI bridges. * * Copyright (C) 1998 Gabriel Paubert. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.4/linux/arch/ppc/kernel/irq.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/irq.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: irq.c,v 1.113 1999/09/17 17:22:56 cort Exp $ - * + * BK Id: SCCS/s.irq.c 1.23 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/irq.c * * Derived from arch/i386/kernel/irq.c @@ -176,9 +177,19 @@ return 0; } -/* This could be promoted to a real free_irq() ... */ -static int -do_free_irq(int irq, void* dev_id) +#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +/* Name change so we can catch standard drivers that potentially mess up + * the internal interrupt controller on 8xx and 8260. Just bear with me, + * I don't like this either and I am searching a better solution. For + * now, this is what I need. -- Dan + */ +#define request_irq request_8xxirq +#elif defined(CONFIG_APUS) +#define request_irq request_sysirq +#define free_irq sys_free_irq +#endif + +void free_irq(unsigned int irq, void* dev_id) { irq_desc_t *desc; struct irqaction **p; @@ -209,27 +220,15 @@ barrier(); #endif irq_kfree(action); - return 0; + return; } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); break; } - return -ENOENT; + return; } -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) -/* Name change so we can catch standard drivers that potentially mess up - * the internal interrupt controller on 8xx and 8260. Just bear with me, - * I don't like this either and I am searching a better solution. For - * now, this is what I need. -- Dan - */ -#define request_irq request_8xxirq -#elif defined(CONFIG_APUS) -#define request_irq request_sysirq -#define free_irq sys_free_irq -#endif - int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { @@ -239,8 +238,17 @@ if (irq >= NR_IRQS) return -EINVAL; if (!handler) - /* We could implement really free_irq() instead of that... */ - return do_free_irq(irq, dev_id); + { + /* + * free_irq() used to be implemented as a call to + * request_irq() with handler being NULL. Now we have + * a real free_irq() but need to allow the old behavior + * for old code that hasn't caught up yet. + * -- Cort + */ + free_irq(irq, dev_id); + return 0; + } action = (struct irqaction *) irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -266,11 +274,6 @@ return 0; } -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - /* * Generic enable/disable code: this just calls * down into the PIC-specific version for the actual @@ -524,7 +527,7 @@ spin_unlock(&desc->lock); } -int do_IRQ(struct pt_regs *regs, int isfake) +int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); int irq; @@ -546,10 +549,7 @@ goto out; } ppc_irq_dispatch_handler( regs, irq ); - if (ppc_md.post_irq) - ppc_md.post_irq( regs, irq ); - - out: +out: hardirq_exit( cpu ); return 1; /* lets ret_from_int know we can do checks */ } @@ -851,15 +851,18 @@ } #endif /* CONFIG_SMP */ -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; +static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; #ifdef CONFIG_IRQ_ALL_CPUS -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; -#else /* CONFIG_IRQ_ALL_CPUS */ -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000}; -#endif /* CONFIG_IRQ_ALL_CPUS */ +#define DEFAULT_CPU_AFFINITY 0xffffffff +#else +#define DEFAULT_CPU_AFFINITY 0x00000001 +#endif + +unsigned int irq_affinity [NR_IRQS] = + { [0 ... NR_IRQS-1] = DEFAULT_CPU_AFFINITY }; #define HEX_DIGITS 8 @@ -919,16 +922,18 @@ err = parse_hex_value(buffer, count, &new_value); -/* Why is this disabled ? --BenH */ -#if 0/*CONFIG_SMP*/ /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. + * + * We assume a 1-1 logical<->physical cpu mapping here. If + * we assume that the cpu indices in /proc/irq/../smp_affinity + * are actually logical cpu #'s then we have no problem. + * -- Cort */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc[irq].handler->set_affinity(irq, new_value); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h --- v2.4.4/linux/arch/ppc/kernel/local_irq.h Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/local_irq.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.local_irq.h 1.7 05/17/01 18:14:21 cort + */ #ifndef _PPC_KERNEL_LOCAL_IRQ_H #define _PPC_KERNEL_LOCAL_IRQ_H diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.4/linux/arch/ppc/kernel/m8260_setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/ppc/kernel/m8260_setup.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: m8xx_setup.c,v 1.4 1999/09/18 18:40:36 dmalek Exp $ - * + * BK Id: SCCS/s.m8260_setup.c 1.15 05/17/01 18:14:21 cort + */ +/* * linux/arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds @@ -119,7 +120,7 @@ return(0); } -unsigned long __init +unsigned long m8260_get_rtc_time(void) { @@ -206,6 +207,18 @@ } +/* + * Same hack as 8xx + */ +unsigned long __init m8260_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} void __init m8260_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -248,18 +261,8 @@ ppc_md.get_rtc_time = m8260_get_rtc_time; ppc_md.calibrate_decr = m8260_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8260_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -268,7 +271,6 @@ ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; -#endif #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.4/linux/arch/ppc/kernel/m8xx_setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/ppc/kernel/m8xx_setup.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: m8xx_setup.c,v 1.4 1999/09/18 18:40:36 dmalek Exp $ - * + * BK Id: SCCS/s.m8xx_setup.c 1.17 05/18/01 07:54:04 patch + */ +/* * linux/arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds @@ -107,11 +108,17 @@ ide_pio_timings_t ide_pio_clocks[6]; /* Make clock cycles and always round up */ -#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U ) +#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U ) #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + extern char saved_command_line[256]; extern unsigned long find_available_memory(void); @@ -200,7 +207,7 @@ /* Processor frequency is MHz. * The value 'fp' is the number of decrementer ticks per second. */ - fp = (binfo->bi_intfreq * 1000000) / 16; + fp = binfo->bi_intfreq / 16; freq = fp*60; /* try to make freq/1e6 an integer */ divisor = 60; printk("Decrementer Frequency = %d/%d\n", freq, divisor); @@ -308,10 +315,10 @@ bp = (bd_t *)__res; - len += sprintf(len+buffer,"clock\t\t: %ldMHz\n" - "bus clock\t: %ldMHz\n", - bp->bi_intfreq /*/ 1000000*/, - bp->bi_busfreq /*/ 1000000*/); + len += sprintf(len+buffer,"clock\t\t: %dMHz\n" + "bus clock\t: %dMHz\n", + bp->bi_intfreq / 1000000, + bp->bi_busfreq / 1000000); return len; } @@ -358,7 +365,7 @@ #ifdef CONFIG_BLK_DEV_MPC8xx_IDE ide_insw(port, buf, ns); #else - ide_insw(port+_IO_BASE, buf, ns); + _insw_ns((unsigned short *)(port+_IO_BASE), buf, ns); #endif } @@ -368,7 +375,7 @@ #ifdef CONFIG_BLK_DEV_MPC8xx_IDE ide_outsw(port, buf, ns); #else - ide_outsw(port+_IO_BASE, buf, ns); + _outsw_ns((unsigned short *)(port+_IO_BASE), buf, ns); #endif } @@ -381,7 +388,7 @@ return (ioport_dsc[base].irq); #else - return 14; + return 9; #endif } @@ -398,11 +405,7 @@ const char *device, void *dev_id) { -#ifdef CONFIG_BLK_DEV_MPC8xx_IDE return request_8xxirq(irq, handler, flags, device, dev_id); -#else - return request_irq(irq, handler, flags, device, dev_id); -#endif } /* We can use an external IDE controller @@ -413,16 +416,14 @@ void m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - ide_ioreg_t *p = hw->io_ports; int i; #ifdef CONFIG_BLK_DEV_MPC8xx_IDE + ide_ioreg_t *p = hw->io_ports; volatile pcmconf8xx_t *pcmp; static unsigned long pcmcia_base = 0; -#else - ide_ioreg_t port = data_port; /* ??? XXX ??? XXX */ -#endif unsigned long base; +#endif #ifdef CONFIG_BLK_DEV_MPC8xx_IDE *p = 0; @@ -500,12 +501,15 @@ /* Just a regular IDE drive on some I/O port. */ - i = 8; - while (i--) - *p++ = port++; - *p++ = base + 0x206; - if (irq != NULL) - *irq = 0; + if (data_port == 0) + return; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) + hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; + + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + return; + #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ } #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ @@ -523,7 +527,6 @@ #define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */ #endif - /* Calculate PIO timings */ static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio) @@ -581,9 +584,27 @@ #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ - /* -------------------------------------------------------------------- */ +/* + * This is a big hack right now, but it may turn into something real + * someday. + * + * For the 8xx boards (at this time anyway), there is nothing to initialize + * associated the PROM. Rather than include all of the prom.c + * functions in the image just to get prom_init, all we really need right + * now is the initialization of the physical memory region. + */ +unsigned long __init m8xx_find_end_of_memory(void) +{ + bd_t *binfo; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + return binfo->bi_memsize; +} + void __init m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -629,18 +650,8 @@ ppc_md.get_rtc_time = m8xx_get_rtc_time; ppc_md.calibrate_decr = m8xx_calibrate_decr; -#if 0 - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_pretranslate = pckbd_pretranslate; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#else + ppc_md.find_end_of_memory = m8xx_find_end_of_memory; + ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; @@ -648,8 +659,7 @@ ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = NULL; -#endif + ppc_md.ppc_kbd_sysrq_xlate = NULL; #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.4/linux/arch/ppc/kernel/misc.S Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/misc.S Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.misc.S 1.16 05/17/01 18:14:21 cort + */ +/* * This file contains miscellaneous low-level functions. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * @@ -21,20 +24,6 @@ #include #include "ppc_asm.h" -#if defined(CONFIG_4xx) || defined(CONFIG_8xx) -#define CACHE_LINE_SIZE 16 -#define LG_CACHE_LINE_SIZE 4 -#define MAX_COPY_PREFETCH 1 -#elif !defined(CONFIG_PPC64BRIDGE) -#define CACHE_LINE_SIZE 32 -#define LG_CACHE_LINE_SIZE 5 -#define MAX_COPY_PREFETCH 4 -#else -#define CACHE_LINE_SIZE 128 -#define LG_CACHE_LINE_SIZE 7 -#define MAX_COPY_PREFETCH 1 -#endif /* CONFIG_4xx || CONFIG_8xx */ - .text .align 5 @@ -60,14 +49,37 @@ mtlr r0 blr -/* void __no_use_save_flags(unsigned long *flags) */ -_GLOBAL(__no_use_save_flags) +/* void __save_flags_ptr(unsigned long *flags) */ +_GLOBAL(__save_flags_ptr) mfmsr r4 stw r4,0(r3) blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__save_flags_ptr_end) -/* void __no_use_restore_flags(unsigned long flags) */ -_GLOBAL(__no_use_restore_flags) +/* void __restore_flags(unsigned long flags) */ +_GLOBAL(__restore_flags) /* * Just set/clear the MSR_EE bit through restore/flags but do not * change anything else. This is needed by the RT system and makes @@ -82,66 +94,95 @@ /* Check if things are setup the way we want _already_. */ cmpw 0,r3,r4 beqlr - /* are we enabling interrupts? */ - rlwinm. r0,r3,0,16,16 - beq 1f - /* if so, check if there are any lost interrupts */ - lis r7,ppc_n_lost_interrupts@ha - lwz r7,ppc_n_lost_interrupts@l(r7) - cmpi 0,r7,0 /* lost interrupts to process first? */ - bne- do_lost_interrupts 1: SYNC mtmsr r3 SYNC blr - -_GLOBAL(__no_use_cli) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__restore_flags_end) + +_GLOBAL(__cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ blr /* Done */ + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__cli_end) -_GLOBAL(__no_use_sti) - lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) +_GLOBAL(__sti) mfmsr r3 /* Get current state */ ori r3,r3,MSR_EE /* Turn on 'EE' bit */ - cmpi 0,r4,0 /* lost interrupts to process first? */ - bne- do_lost_interrupts SYNC /* Some chip revs have problems here... */ mtmsr r3 /* Update machine state */ blr - -/* - * We were about to enable interrupts but we have to simulate - * some interrupts that were lost by enable_irq first. - */ -_GLOBAL(do_lost_interrupts) - stwu r1,-16(r1) - mflr r0 - stw r0,20(r1) - stw r3,8(r1) -1: bl fake_interrupt - lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - bne- 1b - lwz r3,8(r1) - SYNC - mtmsr r3 - lwz r0,20(r1) - mtlr r0 - addi r1,r1,16 - blr + /* + * Need these nops here for taking over save/restore to + * handle lost intrs + * -- Cort + */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +_GLOBAL(__sti_end) /* * complement mask on the msr then "or" some values on. * _nmask_and_or_msr(nmask, value_to_or) */ - _GLOBAL(_nmask_and_or_msr) +_GLOBAL(_nmask_and_or_msr) mfmsr r0 /* Get current msr */ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ or r0,r0,r4 /* Or on the bits in r4 (second parm) */ @@ -267,6 +308,7 @@ 2: icbi 0,r6 addi r6,r6,CACHE_LINE_SIZE bdnz 2b + sync /* additional sync needed on g4 */ isync blr @@ -1283,7 +1325,7 @@ .long sys_vfork .long sys_getrlimit /* 190 */ .long sys_ni_syscall /* 191 */ /* Unused */ - .long sys_ni_syscall /* 192 - reserved - mmap2 */ + .long sys_mmap2 /* 192 */ .long sys_truncate64 /* 193 */ .long sys_ftruncate64 /* 194 */ .long sys_stat64 /* 195 */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.4.4/linux/arch/ppc/kernel/mk_defs.c Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/mk_defs.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.mk_defs.c 1.5 05/17/01 18:14:21 cort + */ +/* * This program is used to generate definitions needed by * assembly language modules. * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/mol.h linux/arch/ppc/kernel/mol.h --- v2.4.4/linux/arch/ppc/kernel/mol.h Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/mol.h Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -/* - * arch/ppc/kernel/mol.h - * - * - * - * Mac-on-Linux hook macros - * - * - * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se) - * - * 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 - * - */ - -#ifndef _PPC_KERNEL_MOL -#define _PPC_KERNEL_MOL - -#include - -#ifdef CONFIG_MOL -#define MOL_INTERFACE_VERSION 3 - -#define MOL_HOOK(hook_num) \ - lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ - cmpwi cr1,r0,0; \ - beq+ cr1,777f; \ - mtctr r0; \ - bctrl; \ -777: lwz r0,GPR0(r21) - -#define MOL_HOOK_RESTORE(hook_num) \ - mfcr r2; \ - MOL_HOOK(hook_num); \ - mtcrf 0x80,r2; \ - lwz r2,_CTR(r21); \ - mtctr r2; \ - lwz r2,GPR2(r21) - -#define MOL_HOOK_MMU(hook_num, scr) \ - lis scr,(mol_interface + 4 * hook_num + 4)@ha; \ - lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \ - cmpwi cr1,scr,0; \ - beq+ cr1,778f; \ - mtctr scr; \ - bctrl; \ -778: - -#define MOL_HOOK_TLBMISS(hook_num) \ - lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ - cmpwi r0,0; \ - beq+ 779f; \ - mflr r3; \ - mtlr r0; \ - blrl; \ - mtlr r3; \ -779: - -#else -#define MOL_HOOK(num) -#define MOL_HOOK_RESTORE(num) -#define MOL_HOOK_MMU(num, scr) -#define MOL_HOOK_TLBMISS(num) -#endif - - -#endif /* _PPC_KERNEL_MOL */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/oak_setup.c linux/arch/ppc/kernel/oak_setup.c --- v2.4.4/linux/arch/ppc/kernel/oak_setup.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/oak_setup.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.oak_setup.c 1.5 05/17/01 18:14:21 cort + */ +/* * * Copyright (c) 1999-2000 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/oak_setup.h linux/arch/ppc/kernel/oak_setup.h --- v2.4.4/linux/arch/ppc/kernel/oak_setup.h Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/kernel/oak_setup.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort + */ +/* * * Copyright (c) 1999-2000 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.4.4/linux/arch/ppc/kernel/open_pic.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/open_pic.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.open_pic.c 1.20 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling * * Copyright (C) 1997 Geert Uytterhoeven @@ -775,11 +778,17 @@ int openpic_get_irq(struct pt_regs *regs) { +/* + * Clean up needed. -VAL + */ +#ifndef CONFIG_GEMINI extern int i8259_irq(int cpu); - +#endif int irq = openpic_irq(); /* Management of the cascade should be moved out of here */ + + /* Yep - because openpic !=> i8259, for one thing. -VAL */ if (open_pic_irq_offset && irq == open_pic_irq_offset) { /* @@ -787,8 +796,10 @@ */ if ( chrp_int_ack_special ) irq = *chrp_int_ack_special; +#ifndef CONFIG_GEMINI else irq = i8259_irq( smp_processor_id() ); +#endif openpic_eoi(); } if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) { diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h --- v2.4.4/linux/arch/ppc/kernel/open_pic.h Wed Jan 24 15:28:36 2001 +++ linux/arch/ppc/kernel/open_pic.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.open_pic.h 1.8 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling * * Copyright (C) 1997 Geert Uytterhoeven diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/open_pic_defs.h linux/arch/ppc/kernel/open_pic_defs.h --- v2.4.4/linux/arch/ppc/kernel/open_pic_defs.h Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/open_pic_defs.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.open_pic_defs.h 1.7 05/17/01 18:14:21 cort + */ +/* * linux/openpic.h -- OpenPIC definitions * * Copyright (C) 1997 Geert Uytterhoeven diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pci-dma.c linux/arch/ppc/kernel/pci-dma.c --- v2.4.4/linux/arch/ppc/kernel/pci-dma.c Mon Feb 14 15:34:21 2000 +++ linux/arch/ppc/kernel/pci-dma.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pci-dma.c 1.5 05/17/01 18:14:21 cort + */ +/* * Copyright (C) 2000 Ani Joshi * * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.4.4/linux/arch/ppc/kernel/pci.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/pci.c Mon May 21 17:04:47 2001 @@ -1,5 +1,7 @@ /* - * $Id: pci.c,v 1.64 1999/09/17 18:01:53 cort Exp $ + * BK Id: SCCS/s.pci.c 1.21 05/21/01 01:31:30 cort + */ +/* * Common pmac/prep/chrp pci routines. -- Cort */ @@ -385,6 +387,8 @@ return 0; } +static int next_controller_index; + struct pci_controller * __init pcibios_alloc_controller(void) { @@ -396,9 +400,15 @@ *hose_tail = hose; hose_tail = &hose->next; + hose->index = next_controller_index++; + return hose; } +#ifdef CONFIG_ALL_PPC +/* + * Functions below are used on OpenFirmware machines. + */ static void make_one_node_map(struct device_node* node, u8 pci_bus) { @@ -579,6 +589,95 @@ } void __init +pci_process_bridge_OF_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) +{ + unsigned int *ranges, *prev; + int rlen = 0; + int memno = 0; + struct resource *res; + int np, na = prom_n_addr_cells(dev); + np = na + 5; + + /* First we try to merge ranges to fix a problem with some pmacs + * that can have more than 3 ranges, fortunately using contiguous + * addresses -- BenH + */ + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + prev = NULL; + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + if (prev) { + if (prev[0] == ranges[0] && prev[1] == ranges[1] && + (prev[2] + prev[na+4]) == ranges[2] && + (prev[na+2] + prev[na+4]) == ranges[na+2]) { + prev[na+4] += ranges[na+4]; + ranges[0] = 0; + ranges += np; + continue; + } + } + prev = ranges; + ranges += np; + } + + /* + * The ranges property is laid out as an array of elements, + * each of which comprises: + * cells 0 - 2: a PCI address + * cells 3 or 3+4: a CPU physical address + * (size depending on dev->n_addr_cells) + * cells 4+5 or 5+6: the size of the range + */ + rlen = 0; + hose->io_base_phys = 0; + ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + while ((rlen -= np * sizeof(unsigned int)) >= 0) { + res = NULL; + switch (ranges[0] >> 24) { + case 1: /* I/O space */ + if (ranges[2] != 0) + break; + hose->io_base_phys = ranges[na+2]; + hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]); + if (primary) + isa_io_base = (unsigned long) hose->io_base_virt; + res = &hose->io_resource; + res->flags = IORESOURCE_IO; + res->start = ranges[2]; + break; + case 2: /* memory space */ + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[na+4] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ + if (primary) + isa_mem_base = ranges[na+2]; + memno = 1; + } + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) + hose->pci_mem_offset = ranges[na+2] - ranges[2]; + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[na+2]; + } + break; + } + if (res != NULL) { + res->name = dev->full_name; + res->end = res->start + ranges[na+4] - 1; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + ranges += np; + } +} +#endif /* CONFIG_ALL_PPC */ + +void __init pcibios_init(void) { struct pci_controller *hose; @@ -632,9 +731,6 @@ /* OF fails to initialize IDE controllers on macs * (and maybe other machines) * - * This late fixup is done here since I want it to happen after - * resource assignement, and there's no "late-init" arch hook - * * Ideally, this should be moved to the IDE layer, but we need * to check specifically with Andre Hedrick how to do it cleanly * since the common IDE code seem to care about the fact that the @@ -651,6 +747,9 @@ } } #endif /* CONFIG_BLK_DEV_IDE */ + + if (ppc_md.pcibios_after_init) + ppc_md.pcibios_after_init(); } int __init @@ -802,6 +901,143 @@ /* We may want to do something with IOs here... */ return res->start; #endif +} + +/* + * Return the index of the PCI controller for device pdev. + */ +int pci_controller_num(struct pci_dev *dev) +{ + struct pci_controller *hose = (struct pci_controller *) dev->sysdata; + + return hose->index; +} + +/* + * Platform support for /proc/bus/pci/X/Y mmap()s, + * modelled on the sparc64 implementation by Dave Miller. + * -- paulus. + */ + +/* + * Adjust vm_pgoff of VMA such that it is the physical page offset + * corresponding to the 32-bit pci bus offset for DEV requested by the user. + * + * Basically, the user finds the base address for his device which he wishes + * to mmap. They read the 32-bit value from the config space base register, + * add whatever PAGE_SIZE multiple offset they wish, and feed this into the + * offset parameter of mmap on /proc/bus/pci/XXX for that device. + * + * Returns negative error code on failure, zero on success. + */ +static __inline__ int +__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + struct pci_controller *hose = (struct pci_controller *) dev->sysdata; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long io_offset = 0; + int i, res_bit; + + if (hose == 0) + return -EINVAL; /* should never happen */ + + /* If memory, add on the PCI bridge address offset */ + if (mmap_state == pci_mmap_mem) { + offset += hose->pci_mem_offset; + res_bit = IORESOURCE_MEM; + } else { + io_offset = (unsigned long)hose->io_base_virt - isa_io_base; + offset += io_offset; + res_bit = IORESOURCE_IO; + } + + /* + * Check that the offset requested corresponds to one of the + * resources of the device. + */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &dev->resource[i]; + int flags = rp->flags; + + /* treat ROM as memory (should be already) */ + if (i == PCI_ROM_RESOURCE) + flags |= IORESOURCE_MEM; + + /* Active and same type? */ + if ((flags & res_bit) == 0) + continue; + + /* In the range of this resource? */ + if (offset < (rp->start & PAGE_MASK) || offset > rp->end) + continue; + + /* found it! construct the final physical address */ + if (mmap_state == pci_mmap_io) + offset += hose->io_base_phys - io_offset; + + vma->vm_pgoff = offset >> PAGE_SHIFT; + return 0; + } + + return -EINVAL; +} + +/* + * Set vm_flags of VMA, as appropriate for this architecture, for a pci device + * mapping. + */ +static __inline__ void +__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; +} + +/* + * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci + * device mapping. + */ +static __inline__ void +__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + int prot = pgprot_val(vma->vm_page_prot); + + /* XXX would be nice to have a way to ask for write-through */ + prot |= _PAGE_NO_CACHE; + if (!write_combine) + prot |= _PAGE_GUARDED; + vma->vm_page_prot = __pgprot(prot); +} + +/* + * Perform the actual remap of the pages for a PCI device mapping, as + * appropriate for this architecture. The region in the process to map + * is described by vm_start and vm_end members of VMA, the base physical + * address is found in vm_pgoff. + * The pci device structure is provided so that architectures may make mapping + * decisions on a per-device or per-bus basis. + * + * Returns a negative error code on failure, zero on success. + */ +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine) +{ + int ret; + + ret = __pci_mmap_make_offset(dev, vma, mmap_state); + if (ret < 0) + return ret; + + __pci_mmap_set_flags(dev, vma, mmap_state); + __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine); + + ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + + return ret; } /* Obsolete functions. Should be removed once the symbios driver diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pci.h linux/arch/ppc/kernel/pci.h --- v2.4.4/linux/arch/ppc/kernel/pci.h Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/pci.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.pci.h 1.7 05/17/01 18:14:21 cort + */ #ifndef __PPC_KERNEL_PCI_H__ #define __PPC_KERNEL_PCI_H__ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_backlight.c linux/arch/ppc/kernel/pmac_backlight.c --- v2.4.4/linux/arch/ppc/kernel/pmac_backlight.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/pmac_backlight.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pmac_backlight.c 1.5 05/17/01 18:14:21 cort + */ +/* * Miscellaneous procedures for dealing with the PowerMac hardware. * Contains support for the backlight. * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c --- v2.4.4/linux/arch/ppc/kernel/pmac_nvram.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/pmac_nvram.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pmac_nvram.c 1.5 05/17/01 18:14:21 cort + */ +/* * Miscellaneous procedures for dealing with the PowerMac hardware. */ #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.4.4/linux/arch/ppc/kernel/pmac_pci.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/pmac_pci.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pmac_pci.c 1.14 05/17/01 18:14:21 cort + */ +/* * Support for PCI bridges found on Power Macintoshes. * At present the "bandit" and "chaos" bridges are supported. * Fortunately you access configuration space in the same @@ -24,13 +27,12 @@ #include #include #include +#include #include "pci.h" #undef DEBUG -extern void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int primary); static void add_bridges(struct device_node *dev); /* XXX Could be per-controller, but I don't think we risk anything by @@ -382,17 +384,6 @@ hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - /* is 0x10000 enough for io space ? */ - hose->io_base_virt = (void *)ioremap(addr->address, 0x10000); - - /* XXX This is the bridge with the PCI expansion bus. We route - * legacy IOs to it. - */ - if (addr->address == 0xf2000000) - isa_io_base = (unsigned long)hose->io_base_virt; -#endif /* We "know" that the bridge at f2000000 has the PCI slots. */ return addr->address == 0xf2000000; } @@ -405,10 +396,6 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); -#endif init_bandit(hose); } @@ -421,23 +408,12 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = addr->address; - hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); -#endif } void __init setup_grackle(struct pci_controller *hose, unsigned io_space_size) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000); -#if 0 /* done in process_bridge_ranges now - paulus */ - hose->io_base_phys = 0xfe000000; - hose->io_base_virt = (void *) ioremap(0xfe000000, io_space_size); - pci_dram_offset = 0; - isa_mem_base = 0xfd000000; - isa_io_base = (unsigned long) hose->io_base_virt; -#endif if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ @@ -505,7 +481,7 @@ /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ - process_bridge_ranges(hose, dev, primary); + pci_process_bridge_OF_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); @@ -557,19 +533,56 @@ pcibios_fixup_OF_interrupts(); } -/* We don't want to enable USB controllers absent from the OF tree - * (iBook second controller) - */ int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) { + struct device_node* node; + + node = pci_device_to_OF_node(dev); + + /* We don't want to enable USB controllers absent from the OF tree + * (iBook second controller) + */ if (dev->vendor == PCI_VENDOR_ID_APPLE - && dev->device == PCI_DEVICE_ID_APPLE_KL_USB) { - struct device_node* node; - node = pci_device_to_OF_node(dev); - if (!node) - return -EINVAL; + && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node) + return -EINVAL; + + /* Firewire was disabled after PCI probe, the driver is claiming it, + * so we must re-enable it now, at least until the driver can do it + * itself. + */ + if (node && !strcmp(node->name, "firewire") && + device_is_compatible(node, "pci106b,18")) { + feature_set_firewire_cable_power(node, 1); + feature_set_firewire_power(node, 1); } + return 0; +} + +/* We power down some devices after they have been probed. They'll + * be powered back on later on + */ +void +pmac_pcibios_after_init(void) +{ + struct device_node* nd; + + nd = find_devices("firewire"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "pci106b,18") + && device_is_compatible(nd->parent, "uni-north")) { + feature_set_firewire_power(nd, 0); + feature_set_firewire_cable_power(nd, 0); + } + nd = nd->next; + } + nd = find_devices("ethernet"); + while (nd) { + if (nd->parent && device_is_compatible(nd, "gmac") + && device_is_compatible(nd->parent, "uni-north")) + feature_set_gmac_power(nd, 0); + nd = nd->next; + } } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.4.4/linux/arch/ppc/kernel/pmac_pic.c Fri Feb 16 16:02:34 2001 +++ linux/arch/ppc/kernel/pmac_pic.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.pmac_pic.c 1.14 05/17/01 18:14:21 cort + */ #include #include #include @@ -10,6 +13,7 @@ #include #include #include +#include #include "pmac_pic.h" #include "open_pic.h" @@ -44,10 +48,12 @@ * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac __no_use_set_lost(unsigned long irq_nr) +void __pmac __set_lost(unsigned long irq_nr) { - if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { atomic_inc(&ppc_n_lost_interrupts); + set_dec(1); + } } static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) @@ -373,7 +379,6 @@ irqctrler = NULL; } - int_control.int_set_lost = __no_use_set_lost; /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_pic.h linux/arch/ppc/kernel/pmac_pic.h --- v2.4.4/linux/arch/ppc/kernel/pmac_pic.h Thu Oct 7 10:17:08 1999 +++ linux/arch/ppc/kernel/pmac_pic.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.pmac_pic.h 1.5 05/17/01 18:14:21 cort + */ #ifndef _PPC_KERNEL_PMAC_PIC_H #define _PPC_KERNEL_PMAC_PIC_H diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.4.4/linux/arch/ppc/kernel/pmac_setup.c Tue Mar 6 19:28:35 2001 +++ linux/arch/ppc/kernel/pmac_setup.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pmac_setup.c 1.21 05/17/01 18:14:21 cort + */ +/* * linux/arch/ppc/kernel/setup.c * * PowerPC version @@ -66,6 +69,7 @@ #include #include "local_irq.h" #include "pmac_pic.h" +#include "../mm/mem_pieces.h" #undef SHOW_GATWICK_IRQS @@ -102,6 +106,9 @@ extern void pmac_nvram_update(void); extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); +extern void pmac_pcibios_after_init(void); + +struct device_node *memory_node; unsigned char drive_info; @@ -470,7 +477,7 @@ char *p; /* Do nothing if the root has been set already. */ - if ((goodness < current_root_goodness) && + if ((goodness <= current_root_goodness) && (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); @@ -635,6 +642,88 @@ #endif #endif +/* + * Read in a property describing some pieces of memory. + */ + +static void __init get_mem_prop(char *name, struct mem_pieces *mp) +{ + struct reg_property *rp; + int i, s; + unsigned int *ip; + int nac = prom_n_addr_cells(memory_node); + int nsc = prom_n_size_cells(memory_node); + + ip = (unsigned int *) get_property(memory_node, name, &s); + if (ip == NULL) { + printk(KERN_ERR "error: couldn't get %s property on /memory\n", + name); + abort(); + } + s /= (nsc + nac) * 4; + rp = mp->regions; + for (i = 0; i < s; ++i, ip += nac+nsc) { + if (nac >= 2 && ip[nac-2] != 0) + continue; + rp->address = ip[nac-1]; + if (nsc >= 2 && ip[nac+nsc-2] != 0) + rp->size = ~0U; + else + rp->size = ip[nac+nsc-1]; + ++rp; + } + mp->n_regions = rp - mp->regions; + + /* Make sure the pieces are sorted. */ + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); +} + +/* + * On systems with Open Firmware, collect information about + * physical RAM and which pieces are already in use. + * At this point, we have (at least) the first 8MB mapped with a BAT. + * Our text, data, bss use something over 1MB, starting at 0. + * Open Firmware may be using 1MB at the 4MB point. + */ +unsigned long __init pmac_find_end_of_memory(void) +{ + unsigned long a, total; + struct mem_pieces phys_mem; + + memory_node = find_devices("memory"); + if (memory_node == NULL) { + printk(KERN_ERR "can't find memory node\n"); + abort(); + } + + /* + * Find out where physical memory is, and check that it + * starts at 0 and is contiguous. It seems that RAM is + * always physically contiguous on Power Macintoshes. + * + * Supporting discontiguous physical memory isn't hard, + * it just makes the virtual <-> physical mapping functions + * more complicated (or else you end up wasting space + * in mem_map). + */ + get_mem_prop("reg", &phys_mem); + if (phys_mem.n_regions == 0) + panic("No RAM??"); + a = phys_mem.regions[0].address; + if (a != 0) + panic("RAM doesn't start at physical address 0"); + total = phys_mem.regions[0].size; + + if (phys_mem.n_regions > 1) { + printk("RAM starting at 0x%x is not contiguous\n", + phys_mem.regions[1].address); + printk("Using RAM from 0 to 0x%lx\n", total-1); + } + + return total; +} + void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -656,6 +745,7 @@ ppc_md.pcibios_fixup = pmac_pcibios_fixup; ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; + ppc_md.pcibios_after_init = pmac_pcibios_after_init; ppc_md.restart = pmac_restart; ppc_md.power_off = pmac_power_off; @@ -665,6 +755,8 @@ ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.find_end_of_memory = pmac_find_end_of_memory; #ifdef CONFIG_VT #ifdef CONFIG_INPUT diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.4.4/linux/arch/ppc/kernel/pmac_time.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/pmac_time.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.pmac_time.c 1.8 05/17/01 18:14:21 cort + */ +/* * Support for periodic interrupts (100 per second) and for getting * the current time from the RTC on Power Macintoshes. * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.4.4/linux/arch/ppc/kernel/ppc-stub.c Sun Oct 1 20:35:15 2000 +++ linux/arch/ppc/kernel/ppc-stub.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ -/* $Id: ppc-stub.c,v 1.6 1999/08/12 22:18:11 cort Exp $ +/* + * BK Id: SCCS/s.ppc-stub.c 1.6 05/17/01 18:14:21 cort + */ +/* * ppc-stub.c: KGDB support for the Linux kernel. * * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc4xx_pic.c linux/arch/ppc/kernel/ppc4xx_pic.c --- v2.4.4/linux/arch/ppc/kernel/ppc4xx_pic.c Tue Jan 11 21:49:26 2000 +++ linux/arch/ppc/kernel/ppc4xx_pic.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.ppc4xx_pic.c 1.5 05/17/01 18:14:21 cort + */ +/* * * Copyright (c) 1999 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc4xx_pic.h linux/arch/ppc/kernel/ppc4xx_pic.h --- v2.4.4/linux/arch/ppc/kernel/ppc4xx_pic.h Mon Jan 10 18:25:32 2000 +++ linux/arch/ppc/kernel/ppc4xx_pic.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.ppc4xx_pic.h 1.5 05/17/01 18:14:21 cort + */ +/* * * Copyright (c) 1999 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc8260_pic.c linux/arch/ppc/kernel/ppc8260_pic.c --- v2.4.4/linux/arch/ppc/kernel/ppc8260_pic.c Sat Nov 11 18:14:38 2000 +++ linux/arch/ppc/kernel/ppc8260_pic.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc8260_pic.c 1.5 05/17/01 18:14:21 cort + */ #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc8260_pic.h linux/arch/ppc/kernel/ppc8260_pic.h --- v2.4.4/linux/arch/ppc/kernel/ppc8260_pic.h Tue May 2 13:05:40 2000 +++ linux/arch/ppc/kernel/ppc8260_pic.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc8260_pic.h 1.7 05/17/01 18:14:21 cort + */ #ifndef _PPC_KERNEL_PPC8260_H #define _PPC_KERNEL_PPC8260_H @@ -8,8 +11,7 @@ void m8260_pic_init(void); void m8260_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake); + int cpu); int m8260_get_irq(struct pt_regs *regs); #endif /* _PPC_KERNEL_PPC8260_H */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c --- v2.4.4/linux/arch/ppc/kernel/ppc8xx_pic.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/ppc8xx_pic.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc8xx_pic.c 1.10 05/17/01 18:14:21 cort + */ #include #include #include @@ -67,8 +70,7 @@ #if 0 void m8xx_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) + int cpu) { int irq; unsigned long bits = 0; @@ -158,13 +160,15 @@ */ switch (irq) { #ifdef IDE0_INTERRUPT - case IDE0_INTERRUPT: /* fall through */ + case IDE0_INTERRUPT: /* IDE0 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif #ifdef IDE1_INTERRUPT - case IDE1_INTERRUPT: /* fall through */ + case IDE1_INTERRUPT: /* IDE1 */ + return (request_8xxirq(irq, handler, irqflags, devname, + dev_id)); #endif - return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); - default: /* unknown IRQ -> panic */ panic("request_irq"); } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc8xx_pic.h linux/arch/ppc/kernel/ppc8xx_pic.h --- v2.4.4/linux/arch/ppc/kernel/ppc8xx_pic.h Fri Nov 12 04:29:47 1999 +++ linux/arch/ppc/kernel/ppc8xx_pic.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc8xx_pic.h 1.7 05/17/01 18:14:21 cort + */ #ifndef _PPC_KERNEL_PPC8xx_H #define _PPC_KERNEL_PPC8xx_H @@ -8,8 +11,7 @@ void m8xx_pic_init(void); void m8xx_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake); + int cpu); int m8xx_get_irq(struct pt_regs *regs); #ifdef CONFIG_MBX diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h --- v2.4.4/linux/arch/ppc/kernel/ppc_asm.h Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/ppc_asm.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.ppc_asm.h 1.10 05/17/01 18:14:21 cort + */ +/* * arch/ppc/kernel/ppc_asm.h * * Definitions used by various bits of low-level assembly code on PowerPC. @@ -130,3 +133,22 @@ #define MTMSRD(r) mtmsr r #define CLR_TOP32(r) #endif /* CONFIG_PPC64BRIDGE */ + +/* + * Defines for cache-line size etc. + */ +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 + +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 + +#else +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 +#endif /* CONFIG_4xx || CONFIG_8xx */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.4.4/linux/arch/ppc/kernel/ppc_htab.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/ppc_htab.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: ppc_htab.c,v 1.29 1999/09/10 05:05:50 paulus Exp $ - * + * BK Id: SCCS/s.ppc_htab.c 1.8 05/17/01 18:14:21 cort + */ +/* * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.4.4/linux/arch/ppc/kernel/ppc_ksyms.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/ppc_ksyms.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc_ksyms.c 1.31 05/18/01 08:18:10 patch + */ #include #include #include @@ -55,12 +58,11 @@ extern void transfer_to_handler(void); extern void syscall_trace(void); -extern void do_IRQ(struct pt_regs *regs, int isfake); +extern void do_IRQ(struct pt_regs *regs); extern void MachineCheckException(struct pt_regs *regs); extern void AlignmentException(struct pt_regs *regs); extern void ProgramCheckException(struct pt_regs *regs); extern void SingleStepException(struct pt_regs *regs); -extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); extern int pmac_newworld; extern int sys_sigreturn(struct pt_regs *regs); @@ -83,7 +85,6 @@ EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(ppc_lost_interrupts); -EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); @@ -92,20 +93,13 @@ EXPORT_SYMBOL(kernel_flag); #endif /* CONFIG_SMP */ -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -EXPORT_SYMBOL_NOVERS(isa_io_base); -EXPORT_SYMBOL_NOVERS(isa_mem_base); -EXPORT_SYMBOL_NOVERS(pci_dram_offset); -#endif EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -#ifndef CONFIG_8xx #if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); #endif -#endif #if !__INLINE_BITOPS EXPORT_SYMBOL(set_bit); @@ -175,6 +169,9 @@ #endif #ifdef CONFIG_PCI +EXPORT_SYMBOL_NOVERS(isa_io_base); +EXPORT_SYMBOL_NOVERS(isa_mem_base); +EXPORT_SYMBOL_NOVERS(pci_dram_offset); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); #endif /* CONFIG_PCI */ @@ -216,9 +213,6 @@ EXPORT_SYMBOL(synchronize_irq); #endif -#ifndef CONFIG_MACH_SPECIFIC -EXPORT_SYMBOL(_machine); -#endif EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB @@ -249,10 +243,9 @@ EXPORT_SYMBOL(set_backlight_enable); EXPORT_SYMBOL(register_backlight_controller); #endif /* CONFIG_PMAC_BACKLIGHT */ -#ifndef CONFIG_MACH_SPECIFIC -EXPORT_SYMBOL_NOVERS(have_of); -#endif /* CONFIG_MACH_SPECIFIC */ #if defined(CONFIG_ALL_PPC) +EXPORT_SYMBOL(_machine); +EXPORT_SYMBOL_NOVERS(have_of); EXPORT_SYMBOL_NOVERS(sys_ctrler); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); @@ -277,9 +270,11 @@ EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); EXPORT_SYMBOL(feature_set_gmac_power); -EXPORT_SYMBOL(feature_set_gmac_phy_reset); +EXPORT_SYMBOL(feature_gmac_phy_reset); EXPORT_SYMBOL(feature_set_usb_power); EXPORT_SYMBOL(feature_set_firewire_power); +EXPORT_SYMBOL(feature_set_firewire_cable_power); +EXPORT_SYMBOL(feature_set_airport_power); #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(bootx_update_display); @@ -314,7 +309,14 @@ #endif EXPORT_SYMBOL(__delay); -EXPORT_SYMBOL(int_control); +EXPORT_SYMBOL(__sti); +EXPORT_SYMBOL(__sti_end); +EXPORT_SYMBOL(__cli); +EXPORT_SYMBOL(__cli_end); +EXPORT_SYMBOL(__save_flags_ptr); +EXPORT_SYMBOL(__save_flags_ptr_end); +EXPORT_SYMBOL(__restore_flags); +EXPORT_SYMBOL(__restore_flags_end); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(do_IRQ_intercept); @@ -331,9 +333,6 @@ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); -EXPORT_SYMBOL(down_read_failed); -EXPORT_SYMBOL(down_write_failed); #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) extern void (*debugger)(struct pt_regs *regs); @@ -362,6 +361,8 @@ EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); +EXPORT_SYMBOL(flush_hash_page); /* For MOL */ +EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ EXPORT_SYMBOL_NOVERS(disarm_decr); #if !defined(CONFIG_8xx) && !defined(CONFIG_4xx) extern long *intercept_table; @@ -369,17 +370,3 @@ #endif extern long *ret_from_intercept; EXPORT_SYMBOL(ret_from_intercept); - -#ifdef CONFIG_MOL -extern ulong mol_interface[]; -extern PTE *Hash; -extern unsigned long Hash_mask; -extern void (*ret_from_except)(void); -extern struct task_struct *last_task_used_altivec; -EXPORT_SYMBOL_NOVERS(mol_interface); -EXPORT_SYMBOL(Hash); -EXPORT_SYMBOL(Hash_mask); -EXPORT_SYMBOL(handle_mm_fault); -EXPORT_SYMBOL(last_task_used_math); -EXPORT_SYMBOL(ret_from_except); -#endif /* CONFIG_MOL */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c --- v2.4.4/linux/arch/ppc/kernel/prep_nvram.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/kernel/prep_nvram.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.prep_nvram.c 1.9 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/prep_nvram.c * * Copyright (C) 1998 Corey Minyard diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.4.4/linux/arch/ppc/kernel/prep_pci.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/prep_pci.c Mon May 21 17:04:47 2001 @@ -1,5 +1,7 @@ /* - * $Id: prep_pci.c,v 1.40 1999/09/17 17:23:05 cort Exp $ + * BK Id: SCCS/s.prep_pci.c 1.18 05/17/01 18:14:22 cort + */ +/* * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -437,8 +439,8 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { 0, /* Line 0 - unused */ - 13, /* Line 1 */ - 10, /* Line 2 */ + 15, /* Line 1 */ + 15, /* Line 2 */ 15, /* Line 3 */ 15, /* Line 4 */ }; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.4/linux/arch/ppc/kernel/prep_setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/ppc/kernel/prep_setup.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.prep_setup.c 1.20 05/21/01 09:19:50 trini + */ +/* * linux/arch/ppc/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds @@ -103,6 +106,17 @@ extern int probingmem; extern unsigned long loops_per_jiffy; +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +#ifdef CONFIG_SOUND_MODULE +EXPORT_SYMBOL(ppc_cs4232_dma); +EXPORT_SYMBOL(ppc_cs4232_dma2); +#endif + int __prep prep_get_cpuinfo(char *buffer) { @@ -246,7 +260,16 @@ case _PREP_Motorola: /* Enable L2. Assume we don't need to flush -- Cort*/ *(unsigned char *)(0x8000081c) |= 3; - ROOT_DEV = to_kdev_t(0x0802); /* sda2 */ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */ + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */ +#else + ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */ +#endif break; } @@ -313,6 +336,8 @@ vgacon_remap_base = 0xf0000000; /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/ conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; #endif } @@ -504,8 +529,8 @@ __cli(); __asm__ __volatile__("\n\ - mtspr 26, %1 /* SRR0 */ - mtspr 27, %0 /* SRR1 */ + mtspr 26, %1 /* SRR0 */ \n\ + mtspr 27, %0 /* SRR1 */ \n\ rfi" : : "r" (defaultmsr), "r" (jumpaddr)); @@ -575,7 +600,7 @@ #if 0 void __prep -prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake) +prep_do_IRQ(struct pt_regs *regs, int cpu) { int irq; @@ -691,6 +716,35 @@ } #endif +/* + * This finds the amount of physical ram and does necessary + * setup for prep. This is pretty architecture specific so + * this will likely stay separate from the pmac. + * -- Cort + */ +unsigned long __init prep_find_end_of_memory(void) +{ + unsigned long total; +#ifdef CONFIG_PREP_RESIDUAL + total = res->TotalMemory; +#else + total = 0; +#endif + + if (total == 0 ) + { + /* + * I need a way to probe the amount of memory if the residual + * data doesn't contain it. -- Cort + */ + printk("Ramsize from residual data was 0 -- Probing for value\n"); + total = 0x02000000; + printk("Ramsize default to be %ldM\n", total>>20); + } + + return (total); +} + unsigned long *MotSave_SmpIar; unsigned char *MotSave_CpusState[2]; @@ -730,6 +784,14 @@ } #endif +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + /* Copy cmd_line parameters */ if ( r6) { @@ -750,7 +812,8 @@ { if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) _prep_type = _PREP_IBM; - _prep_type = _PREP_Motorola; + else + _prep_type = _PREP_Motorola; } else /* assume motorola if no residual (netboot?) */ #endif @@ -784,6 +847,8 @@ ppc_md.time_init = mk48t59_init; } + ppc_md.find_end_of_memory = prep_find_end_of_memory; + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = prep_ide_insw; ppc_ide_md.outsw = prep_ide_outsw; @@ -810,8 +875,3 @@ #endif #endif } - -#ifdef CONFIG_SOUND_MODULE -EXPORT_SYMBOL(ppc_cs4232_dma); -EXPORT_SYMBOL(ppc_cs4232_dma2); -#endif diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c --- v2.4.4/linux/arch/ppc/kernel/prep_time.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/prep_time.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.prep_time.c 1.7 05/17/01 18:14:22 cort + */ +/* * linux/arch/i386/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds @@ -30,6 +33,8 @@ #include +extern spinlock_t rtc_lock; + /* * The motorola uses the m48t18 rtc (includes DS1643) whose registers * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818 @@ -55,6 +60,7 @@ unsigned char save_control, save_freq_select; struct rtc_time tm; + spin_lock(&rtc_lock); to_tm(nowtime, &tm); /* tell the clock it's being set */ @@ -92,6 +98,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return 0; } @@ -149,7 +156,7 @@ unsigned char save_control; struct rtc_time tm; - + spin_lock(&rtc_lock); to_tm(nowtime, &tm); /* tell the clock it's being written */ @@ -175,6 +182,7 @@ /* Turn off the write bit. */ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + spin_unlock(&rtc_lock); return 0; } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/proc_rtas.c linux/arch/ppc/kernel/proc_rtas.c --- v2.4.4/linux/arch/ppc/kernel/proc_rtas.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/kernel/proc_rtas.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort + */ +/* * arch/ppc/kernel/proc_rtas.c * Copyright (C) 2000 Tilmann Bitterberg * (tilmann@bitterberg.de) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.4/linux/arch/ppc/kernel/process.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/kernel/process.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: process.c,v 1.97 1999/09/14 19:07:42 cort Exp $ - * + * BK Id: SCCS/s.process.c 1.15 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/process.c * * Derived from "arch/i386/kernel/process.c" @@ -378,45 +379,6 @@ } /* - * XXX ld.so expects the auxiliary table to start on - * a 16-byte boundary, so we have to find it and - * move it up. :-( - */ -static inline void shove_aux_table(unsigned long sp) -{ - int argc; - char *p; - unsigned long e; - unsigned long aux_start, offset; - - if (__get_user(argc, (int *)sp)) - return; - sp += sizeof(int) + (argc + 1) * sizeof(char *); - /* skip over the environment pointers */ - do { - if (__get_user(p, (char **)sp)) - return; - sp += sizeof(char *); - } while (p != NULL); - aux_start = sp; - /* skip to the end of the auxiliary table */ - do { - if (__get_user(e, (unsigned long *)sp)) - return; - sp += 2 * sizeof(unsigned long); - } while (e != AT_NULL); - offset = ((aux_start + 15) & ~15) - aux_start; - if (offset != 0) { - do { - sp -= sizeof(unsigned long); - if (__get_user(e, (unsigned long *)sp) - || __put_user(e, (unsigned long *)(sp + offset))) - return; - } while (sp > aux_start); - } -} - -/* * Set up a thread for executing a new program */ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) @@ -425,7 +387,6 @@ regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; - shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; if (last_task_used_altivec == current) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.4.4/linux/arch/ppc/kernel/prom.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/prom.c Thu May 24 15:03:05 2001 @@ -1,6 +1,7 @@ /* - * $Id: prom.c,v 1.79 1999/10/08 01:56:32 paulus Exp $ - * + * BK Id: SCCS/s.prom.c 1.20 05/23/01 00:38:42 cort + */ +/* * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. * @@ -31,7 +32,7 @@ #include #include #include -/* for openpic_to_irq */ +#include #include "open_pic.h" #ifdef CONFIG_FB @@ -182,26 +183,6 @@ #endif unsigned long dev_tree_size; -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - */ -#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) -#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) -#define RELOC(x) (*PTRRELOC(&(x))) - #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) /* Is boot-info compatible ? */ @@ -616,30 +597,10 @@ char *p, *d; int prom_version = 0; unsigned long phys; - extern char __bss_start, _end; - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); /* Default */ phys = offset + KERNELBASE; - /* check if we're apus, return if we are */ - if ( r3 == 0x61707573 ) - return phys; - - /* If we came here from BootX, clear the screen, - * set up some pointers and return. */ - if (r3 == 0x426f6f58 && pp == NULL) { - bootx_init(r4, phys); - return phys; - } - - /* check if we're prep, return if we are */ - if ( *(unsigned long *)(0) == 0xdeadc0de ) - return phys; - /* First get a handle for the stdout device */ RELOC(prom) = pp; RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1, @@ -757,14 +718,9 @@ setup_disp_fake_bi(RELOC(prom_disp_node)); #endif - /* If pmac, then use quiesce call. We can't rely on prom_version - * since some old iMacs appear to have an incorrect /openprom/model - * entry in the device tree - */ - if (!chrp) { - prom_print(RELOC("Calling quiesce ...\n")); - call_prom(RELOC("quiesce"), 0, 0); - } + /* Use quiesce call to get OF to shut down any devices it's using */ + prom_print(RELOC("Calling quiesce ...\n")); + call_prom(RELOC("quiesce"), 0, 0); #ifdef CONFIG_BOOTX_TEXT if (!chrp && RELOC(disp_bi)) { @@ -839,7 +795,7 @@ __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); prom_drawhex(flags); } - if (pvr == 8 || pvr == 12) { + if (pvr == 8 || pvr == 12 || pvr == 0x800c) { prom_drawstring(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); prom_drawhex(flags); @@ -986,9 +942,11 @@ prom_print(RELOC("... failed\n")); } else { prom_print(RELOC("... ok\n")); - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ + /* + * Setup a usable color table when the appropriate + * method is available. + * Should update this to use set-colors. + */ for (i = 0; i < 32; i++) if (prom_set_color(ih, i, RELOC(default_colors)[i*3], RELOC(default_colors)[i*3+1], @@ -1267,7 +1225,10 @@ np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); - +#if 0 + np->n_addr_cells = naddrc; + np->n_size_cells = nsizec; +#endif /* get the device addresses and interrupts */ if (ifunc != NULL) { mem_start = ifunc(np, mem_start, naddrc, nsizec); @@ -1283,6 +1244,16 @@ ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) nsizec = *ip; +#if 0 + if (np->parent == NULL) { + /* + * Set the n_addr/size_cells on the root to its + * own values, rather than 0. + */ + np->n_addr_cells = naddrc; + np->n_size_cells = nsizec; + } +#endif /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort @@ -1497,6 +1468,34 @@ } } +int +prom_n_addr_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#address-cells", 0); + if (ip != NULL) + return *ip; + } while(np->parent); + return 0; +} + +int +prom_n_size_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#size-cells", 0); + if (ip != NULL) + return *ip; + } while(np->parent); + return 0; +} + __init static unsigned long interpret_pci_props(struct device_node *np, unsigned long mem_start, @@ -1566,6 +1565,8 @@ } ip = (int *) get_property(np, "AAPL,interrupts", &l); + if (ip == 0 && np->parent) + ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { @@ -1761,7 +1762,7 @@ i = 0; adr = (struct address_range *) mem_start; while ((l -= rpsize) >= 0) { - adr[i].space = 0; + adr[i].space = (naddrc >= 2? rp[naddrc-2]: 0); adr[i].address = rp[naddrc - 1]; adr[i].size = rp[naddrc + nsizec - 1]; ++i; @@ -1978,12 +1979,13 @@ { struct property *pp; - for (pp = np->properties; pp != 0; pp = pp->next) - if (strcmp(pp->name, name) == 0) { + for (pp = np->properties; pp != 0; pp = pp->next) { + if (name && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; } + } return 0; } @@ -2161,9 +2163,10 @@ { if (disp_bi == 0) return; - /* check it's the same frame buffer (within 16MB) */ - if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xff000000) + /* check it's the same frame buffer (within 64MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) { return; + } disp_bi->dispDeviceBase = (__u8 *) phys; disp_bi->dispDeviceRect[0] = 0; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.4.4/linux/arch/ppc/kernel/ptrace.c Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/ptrace.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.ptrace.c 1.5 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/ptrace.c * * PowerPC version diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/qspan_pci.c linux/arch/ppc/kernel/qspan_pci.c --- v2.4.4/linux/arch/ppc/kernel/qspan_pci.c Tue May 2 13:05:40 2000 +++ linux/arch/ppc/kernel/qspan_pci.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.qspan_pci.c 1.5 05/17/01 18:14:22 cort + */ +/* * QSpan pci routines. * Most 8xx boards use the QSpan PCI bridge. The config address register * is located 0x500 from the base of the bridge control/status registers. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.4.4/linux/arch/ppc/kernel/residual.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ppc/kernel/residual.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: residual.c,v 1.17 1999/09/27 18:40:23 cort Exp $ - * + * BK Id: SCCS/s.residual.c 1.7 05/17/01 18:14:22 cort + */ +/* * Code to deal with the PReP residual data. * * Written by: Cort Dougan (cort@cs.nmt.edu) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/semaphore.c linux/arch/ppc/kernel/semaphore.c --- v2.4.4/linux/arch/ppc/kernel/semaphore.c Tue Apr 17 17:19:25 2001 +++ linux/arch/ppc/kernel/semaphore.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: semaphore.c,v 1.1 1999/08/31 15:11:44 cort Exp $ - * + * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort + */ +/* * PowerPC-specific semaphore code. * * Copyright (C) 1999 Cort Dougan @@ -9,131 +10,122 @@ * 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. + * + * April 2001 - Reworked by Paul Mackerras + * to eliminate the SMP races in the old version between the updates + * of `count' and `waking'. Now we use negative `count' values to + * indicate that some process(es) are waiting for the semaphore. */ #include - +#include #include -#include /* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. + * Atomically update sem->count. + * This does the equivalent of the following: * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. + * old_count = sem->count; + * tmp = MAX(old_count, 0) + incr; + * sem->count = tmp; + * return old_count; */ +static inline int __sem_update_count(struct semaphore *sem, int incr) +{ + int old_count, tmp; + + __asm__ __volatile__("\n" +"1: lwarx %0,0,%3\n" +" srawi %1,%0,31\n" +" andc %1,%0,%1\n" +" add %1,%1,%4\n" +" stwcx. %1,0,%3\n" +" bne 1b" + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (&sem->count), "r" (incr), "m" (sem->count) + : "cc"); + + return old_count; +} + void __up(struct semaphore *sem) { - wake_one_more(sem); + /* + * Note that we incremented count in up() before we came here, + * but that was ineffective since the result was <= 0, and + * any negative value of count is equivalent to 0. + * This ends up setting count to 1, unless count is now > 0 + * (i.e. because some other cpu has called up() in the meantime), + * in which case we just increment count. + */ + __sem_update_count(sem, 1); wake_up(&sem->wait); } /* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * + * Note that when we come in to __down or __down_interruptible, + * we have already decremented count, but that decrement was + * ineffective since the result was < 0, and any negative value + * of count is equivalent to 0. + * Thus it is only when we decrement count from some value > 0 + * that we have actually got the semaphore. */ +void __down(struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + /* + * Try to get the semaphore. If the count is > 0, then we've + * got the semaphore; we decrement count and exit the loop. + * If the count is 0 or negative, we set it to -1, indicating + * that we are asleep, and then sleep. + */ + while (__sem_update_count(sem, -1) <= 0) { + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + } remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; -void __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) + /* + * If there are any more sleepers, wake one of them up so + * that it can either get the semaphore, or set count to -1 + * indicating that there are still processes sleeping. + */ + wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) { - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + while (__sem_update_count(sem, -1) <= 0) { + if (signal_pending(current)) { + /* + * A signal is pending - give up trying. + * Set sem->count to 0 if it is negative, + * since we are no longer sleeping. + */ + __sem_update_count(sem, 0); + retval = -EINTR; + break; + } + schedule(); + tsk->state = TASK_INTERRUPTIBLE; } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.4.4/linux/arch/ppc/kernel/setup.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/setup.c Thu May 24 15:03:05 2001 @@ -1,5 +1,7 @@ /* - * $Id: setup.c,v 1.160 1999/10/08 01:56:38 paulus Exp $ + * BK Id: SCCS/s.setup.c 1.32 05/23/01 00:38:42 cort + */ +/* * Common prep/pmac/chrp boot and setup code. */ @@ -73,6 +75,16 @@ unsigned long r6, unsigned long r7); +extern void gemini_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + + +extern void bootx_init(unsigned long r4, unsigned long phys); +extern unsigned long reloc_offset(void); + #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -80,23 +92,16 @@ extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; -struct int_control_struct int_control = -{ - __no_use_cli, - __no_use_sti, - __no_use_restore_flags, - __no_use_save_flags -}; struct ide_machdep_calls ppc_ide_md; int parse_bootinfo(void); unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC int _machine = 0; int have_of = 0; -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; @@ -412,7 +417,7 @@ return len; } -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC void __init intuit_machine_type(void) { @@ -434,7 +439,80 @@ } } } -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ + +#ifdef CONFIG_6xx +/* + * We're called here very early in the boot. We determine the machine + * type and call the appropriate low-level setup functions. + * -- Cort + */ +__init +unsigned long +early_init(int r3, int r4, int r5) +{ + extern char __bss_start, _end; + unsigned long phys; + unsigned long offset = reloc_offset(); + unsigned long local_have_of = 1, local_machine; + struct bi_record *rec; + + /* Default */ + phys = offset + KERNELBASE; + +#if defined(CONFIG_APUS) + return phys; +#endif + + /* First zero the BSS -- use memset, some arches don't have + * caches on yet */ + memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_GEMINI) + /* If we came here from BootX, clear the screen, + * set up some pointers and return. */ +#if defined(CONFIG_ALL_PPC) + if ((r3 == 0x426f6f58) && (r5 == 0)) { + bootx_init(r4, phys); + return phys; + } +#endif + + /* check if we're prep, return if we are */ + if ( *(unsigned long *)(0) == 0xdeadc0de ) + return phys; + + /* + * See if we have any bootloader info passed along. If we do, + * get the machine type and find out if we have OF. + * + * The strategy here is to assume that we want to call prom_init() + * unless the bootinfo data passed to us tell us that we don't + * have OF. + * -- Cort + */ + rec = (struct bi_record *)_ALIGN((ulong)PTRRELOC(&__bss_start)+(1<<20)-1,(1<<20)); + if ( rec->tag == BI_FIRST ) + { + for ( ; rec->tag != BI_LAST ; + rec = (struct bi_record *)((ulong)rec + rec->size) ) + { + ulong *data = rec->data; + if ( rec->tag == BI_MACHTYPE ) + { + local_machine = data[0]; + local_have_of = data[1]; + } + } + } + + if ( local_have_of ) + phys = prom_init( r3, r4, (prom_entry)r5); +#endif + + return phys; +} +#endif /* CONFIG_6xx */ /* * Find out what kind of machine we're on and save any data we need @@ -448,36 +526,26 @@ if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260) -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC /* if we didn't get any bootinfo telling us what we are... */ if ( _machine == 0 ) { - /* boot loader will tell us if we're APUS */ - if ( r3 == 0x61707573 ) - { - _machine = _MACH_apus; - r3 = 0; - } /* prep boot loader tells us if we're prep or not */ - else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) + if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { _machine = _MACH_prep; } else have_of = 1; } -#endif /* CONFIG_MACH_SPECIFIC */ if ( have_of ) { /* prom_init has already been called from __start */ if (boot_infos) relocate_nodes(); -#ifndef CONFIG_MACH_SPECIFIC /* we need to set _machine before calling finish_device_tree */ if (_machine == 0) intuit_machine_type(); -#endif /* CONFIG_MACH_SPECIFIC */ finish_device_tree(); /* * If we were booted via quik, r3 points to the physical @@ -489,13 +557,12 @@ * are used for initrd_start and initrd_size, * otherwise they contain 0xdeadbeef. */ - cmd_line[0] = 0; if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { strncpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); } else if (boot_infos != 0) { /* booted by BootX - check for ramdisk */ - if (boot_infos->kernelParamsOffset != 0) + if (boot_infos->kernelParamsOffset != 0) strncpy(cmd_line, (char *) boot_infos + boot_infos->kernelParamsOffset, sizeof(cmd_line)); @@ -526,13 +593,17 @@ chosen = find_devices("chosen"); if (chosen != NULL) { p = get_property(chosen, "bootargs", NULL); - if (p != NULL) + if (p && *p) { + cmd_line[0] = 0; strncpy(cmd_line, p, sizeof(cmd_line)); + } } } cmd_line[sizeof(cmd_line) - 1] = 0; } +#endif /* CONFIG_ALL_PPC */ +#if defined(CONFIG_ALL_PPC) switch (_machine) { case _MACH_Pmac: @@ -544,22 +615,14 @@ case _MACH_chrp: chrp_init(r3, r4, r5, r6, r7); break; -#ifdef CONFIG_APUS - case _MACH_apus: - apus_init(r3, r4, r5, r6, r7); - break; -#endif default: printk("Unknown machine type in identify_machine!\n"); } - - /* Check for nobats option (used in mapin_ram). */ - if (strstr(cmd_line, "nobats")) { - extern int __map_without_bats; - __map_without_bats = 1; - } -#else -#if defined(CONFIG_4xx) +#elif defined(CONFIG_APUS) + apus_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_GEMINI) + gemini_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_4xx) oak_init(r3, r4, r5, r6, r7); #elif defined(CONFIG_8xx) m8xx_init(r3, r4, r5, r6, r7); @@ -567,8 +630,15 @@ m8260_init(r3, r4, r5, r6, r7); #else #error "No board type has been defined for identify_machine()!" -#endif /* CONFIG_4xx */ -#endif /* !CONFIG_4xx && !CONFIG_8xx */ +#endif + +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260) + /* Check for nobats option (used in mapin_ram). */ + if (strstr(cmd_line, "nobats")) { + extern int __map_without_bats; + __map_without_bats = 1; + } +#endif /* !CONFIG_4xx && !CONFIG_8xx && !CONFIG_8260 */ /* Look for mem= option on command line */ if (strstr(cmd_line, "mem=")) { @@ -639,12 +709,12 @@ initrd_end = data[0] + rec->size; break; #endif /* CONFIG_BLK_DEV_INITRD */ -#ifndef CONFIG_MACH_SPECIFIC +#ifdef CONFIG_ALL_PPC case BI_MACHTYPE: _machine = data[0]; have_of = data[1]; break; -#endif /* CONFIG_MACH_SPECIFIC */ +#endif /* CONFIG_ALL_PPC */ } } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.4.4/linux/arch/ppc/kernel/signal.c Wed Jan 24 15:21:19 2001 +++ linux/arch/ppc/kernel/signal.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.signal.c 1.7 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/signal.c * * PowerPC version diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S --- v2.4.4/linux/arch/ppc/kernel/sleep.S Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/kernel/sleep.S Mon May 21 17:04:47 2001 @@ -1,6 +1,9 @@ /* + * BK Id: SCCS/s.sleep.S 1.7 05/17/01 18:14:22 cort + */ +/* * This file contains sleep low-level functions for PowerBook G3. - * Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net) + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) * and Paul Mackerras (paulus@cs.anu.edu.au). * * This program is free software; you can redistribute it and/or diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.4.4/linux/arch/ppc/kernel/smp.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/smp.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.smp.c 1.23 05/17/01 18:14:22 cort + */ +/* * Smp support for ppc. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great @@ -40,6 +43,7 @@ #include #include #include +#include #include "open_pic.h" int smp_threads_ready; @@ -55,7 +59,7 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; static int max_cpus __initdata = NR_CPUS; - +unsigned long cpu_online_map; int smp_hw_index[NR_CPUS]; /* all cpu mappings are 1-1 -- Cort */ @@ -452,32 +456,48 @@ static void smp_core99_kick_cpu(int nr) { - unsigned long save_int; + unsigned long save_vector, new_vector; unsigned long flags; +#if 1 /* New way... */ + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x100)); + if (nr < 1 || nr > 3) + return; +#else volatile unsigned long *vector = ((volatile unsigned long *)(KERNELBASE+0x500)); - if (nr != 1) return; +#endif if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); local_irq_save(flags); local_irq_disable(); - /* Save EE vector */ - save_int = *vector; + /* Save reset vector */ + save_vector = *vector; - /* Setup fake EE vector that does + /* Setup fake reset vector that does * b __secondary_start_psurge - KERNELBASE - */ - *vector = 0x48000002 + - ((unsigned long)__secondary_start_psurge - KERNELBASE); + */ + switch(nr) { + case 1: + new_vector = (unsigned long)__secondary_start_psurge; + break; + case 2: + new_vector = (unsigned long)__secondary_start_psurge2; + break; + case 3: + new_vector = (unsigned long)__secondary_start_psurge3; + break; + } + *vector = 0x48000002 + new_vector - KERNELBASE; /* flush data cache and inval instruction cache */ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); /* Put some life in our friend */ - feature_core99_kick_cpu1(); + feature_core99_kick_cpu(nr); /* FIXME: We wait a bit for the CPU to take the exception, I should * instead wait for the entry code to set something for me. Well, @@ -487,11 +507,11 @@ mdelay(1); /* Restore our exception vector */ - *vector = save_int; + *vector = save_vector; flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); local_irq_restore(flags); - if (ppc_md.progress) ppc_md.progress("smp_core99_probe done", 0x347); + if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); } static void @@ -628,6 +648,43 @@ do_openpic_setup_cpu(); } +#ifdef CONFIG_GEMINI +static int +smp_gemini_probe(void) +{ + int i, nr; + + nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; + if (nr == 0) + nr = 4; + + if (nr > 1) { + openpic_request_IPIs(); + for (i = 1; i < nr; ++i) + smp_hw_index[i] = i; + } + + return nr; +} + +static void +smp_gemini_kick_cpu(int nr) +{ + openpic_init_processor( 1< 0) + gemini_init_l2(); +} +#endif /* CONFIG_GEMINI */ + + static struct smp_ops_t { void (*message_pass)(int target, int msg, unsigned long data, int wait); int (*probe)(void); @@ -685,6 +742,16 @@ smp_prep_setup_cpu, }; +#ifdef CONFIG_GEMINI +/* Gemini */ +static struct smp_ops_t gemini_smp_ops = { + smp_openpic_message_pass, + smp_gemini_probe, + smp_gemini_kick_cpu, + smp_gemini_setup_cpu, +}; +#endif /* CONFIG_GEMINI */ + /* * Common functions */ @@ -925,6 +992,11 @@ case _MACH_prep: smp_ops = &prep_smp_ops; break; +#ifdef CONFIG_GEMINI + case _MACH_gemini: + smp_ops = &gemini_smp_ops; + break; +#endif /* CONFIG_GEMINI */ default: printk("SMP not supported on this machine.\n"); return; @@ -946,6 +1018,19 @@ /* create a process for the processor */ /* we don't care about the values in regs since we'll never reschedule the forked task. */ + /* We DO care about one bit in the pt_regs we + pass to do_fork. That is the MSR_FP bit in + regs.msr. If that bit is on, then do_fork + (via copy_thread) will call giveup_fpu. + giveup_fpu will get a pointer to our (current's) + last register savearea via current->thread.regs + and using that pointer will turn off the MSR_FP, + MSR_FE0 and MSR_FE1 bits. At this point, this + pointer is pointing to some arbitrary point within + our stack. */ + + 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; @@ -1114,8 +1199,18 @@ init_idle(); + /* + * This cpu is now "online". Only set them online + * before they enter the loop below since write access + * to the below variable is _not_ guaranteed to be + * atomic. + * -- Cort + */ + cpu_online_map |= 1UL << smp_processor_id(); + while(!smp_commenced) barrier(); + /* see smp_commence for more info */ if (!smp_tb_synchronized && smp_num_cpus == 2) { smp_software_tb_sync(cpu); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c --- v2.4.4/linux/arch/ppc/kernel/softemu8xx.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/softemu8xx.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.softemu8xx.c 1.8 05/17/01 18:14:22 cort + */ +/* * Software emulation of some PPC instructions for the 8xx core. * * Copyright (C) 1998 Dan Malek (dmalek@jlc.net) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.4.4/linux/arch/ppc/kernel/syscalls.c Mon Mar 19 12:35:09 2001 +++ linux/arch/ppc/kernel/syscalls.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.syscalls.c 1.8 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/sys_ppc.c * * PowerPC version @@ -185,9 +188,10 @@ return error; } -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +static inline unsigned long +do_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) { struct file * file = NULL; int ret = -EBADF; @@ -199,12 +203,33 @@ } down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, offset); + ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); if (file) fput(file); out: return ret; +} + +unsigned long sys_mmap2(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + int err = -EINVAL; + + if (offset & ~PAGE_MASK) + goto out; + + err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +out: + return err; } extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.4.4/linux/arch/ppc/kernel/time.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/time.c Mon May 21 17:04:47 2001 @@ -1,5 +1,7 @@ /* - * $Id: time.c,v 1.57 1999/10/21 03:08:16 cort Exp $ + * BK Id: SCCS/s.time.c 1.15 05/17/01 18:14:22 cort + */ +/* * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -50,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +94,10 @@ static long time_offset; +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +EXPORT_SYMBOL(rtc_lock); + /* Timer interrupt helper function */ static inline int tb_delta(unsigned *jiffy_stamp) { int delta; @@ -144,14 +151,20 @@ int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); + extern void do_IRQ(struct pt_regs *); + + if (atomic_read(&ppc_n_lost_interrupts) != 0) + do_IRQ(regs); hardirq_enter(cpu); - if (!user_mode(regs)) - ppc_do_profile(instruction_pointer(regs)); - do { + while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { jiffy_stamp += tb_ticks_per_jiffy; - if (smp_processor_id()) continue; + if (!user_mode(regs)) + ppc_do_profile(instruction_pointer(regs)); + if (smp_processor_id()) + continue; + /* We are in an interrupt, no need to save/restore flags */ write_lock(&xtime_lock); tb_last_stamp = jiffy_stamp; @@ -184,7 +197,7 @@ last_rtc_update += 60; } write_unlock(&xtime_lock); - } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); + } if ( !disarm_decr[smp_processor_id()] ) set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; @@ -337,6 +350,8 @@ tz.tz_dsttime = 0; do_sys_settimeofday(NULL, &tz); } + + do_get_fast_time = do_gettimeofday; } #define TICK_SIZE tick diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.4.4/linux/arch/ppc/kernel/traps.c Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/kernel/traps.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.traps.c 1.11 05/17/01 18:14:22 cort + */ +/* * linux/arch/ppc/kernel/traps.c * * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/walnut_setup.c linux/arch/ppc/kernel/walnut_setup.c --- v2.4.4/linux/arch/ppc/kernel/walnut_setup.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/walnut_setup.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.walnut_setup.c 1.5 05/17/01 18:14:22 cort + */ +/* * * Copyright (c) 1999-2000 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/walnut_setup.h linux/arch/ppc/kernel/walnut_setup.h --- v2.4.4/linux/arch/ppc/kernel/walnut_setup.h Thu Feb 10 12:37:51 2000 +++ linux/arch/ppc/kernel/walnut_setup.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort + */ +/* * * Copyright (c) 1999-2000 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/xics.c linux/arch/ppc/kernel/xics.c --- v2.4.4/linux/arch/ppc/kernel/xics.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/xics.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.xics.c 1.5 05/17/01 18:14:22 cort + */ +/* * arch/ppc/kernel/xics.c * * Copyright 2000 IBM Corporation. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/kernel/xics.h linux/arch/ppc/kernel/xics.h --- v2.4.4/linux/arch/ppc/kernel/xics.h Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/xics.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort + */ +/* * arch/ppc/kernel/xics.h * * Copyright 2000 IBM Corporation. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile --- v2.4.4/linux/arch/ppc/lib/Makefile Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/lib/Makefile Mon May 21 17:04:47 2001 @@ -1,9 +1,10 @@ +# BK Id: SCCS/s.Makefile 1.7 05/17/01 18:14:22 cort +# # # Makefile for ppc-specific library files.. # -.S.o: - $(CC) $(AFLAGS) -c $< -o $*.o +USE_STANDARD_AS_RULE := true O_TARGET := lib.o diff -u --recursive --new-file v2.4.4/linux/arch/ppc/lib/checksum.S linux/arch/ppc/lib/checksum.S --- v2.4.4/linux/arch/ppc/lib/checksum.S Thu Dec 2 14:37:34 1999 +++ linux/arch/ppc/lib/checksum.S Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.checksum.S 1.5 05/17/01 18:14:22 cort + */ +/* * This file contains assembly-language implementations * of IP-style 1's complement checksum routines. * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c --- v2.4.4/linux/arch/ppc/lib/locks.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/lib/locks.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: locks.c,v 1.25 1999/09/10 10:40:13 davem Exp $ - * + * BK Id: SCCS/s.locks.c 1.8 05/17/01 18:14:22 cort + */ +/* * Locks for smp ppc * * Written by Cort Dougan (cort@cs.nmt.edu) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/lib/strcase.c linux/arch/ppc/lib/strcase.c --- v2.4.4/linux/arch/ppc/lib/strcase.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/lib/strcase.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort + */ #include int strcasecmp(const char *s1, const char *s2) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S --- v2.4.4/linux/arch/ppc/lib/string.S Tue Sep 19 08:31:53 2000 +++ linux/arch/ppc/lib/string.S Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.string.S 1.5 05/17/01 18:14:22 cort + */ +/* * String handling functions for PowerPC. * * Copyright (C) 1996 Paul Mackerras. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/Makefile linux/arch/ppc/math-emu/Makefile --- v2.4.4/linux/arch/ppc/math-emu/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/math-emu/Makefile Mon May 21 17:04:47 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort +# # # # diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/double.h linux/arch/ppc/math-emu/double.h --- v2.4.4/linux/arch/ppc/math-emu/double.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/double.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort + */ +/* * Definitions for IEEE Double Precision */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fabs.c linux/arch/ppc/math-emu/fabs.c --- v2.4.4/linux/arch/ppc/math-emu/fabs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fabs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fabs.c,v 1.1 1999/08/23 18:59:21 cort Exp $ +/* + * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fadd.c linux/arch/ppc/math-emu/fadd.c --- v2.4.4/linux/arch/ppc/math-emu/fadd.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fadd.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fadd.c,v 1.1 1999/08/23 18:59:22 cort Exp $ +/* + * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fadds.c linux/arch/ppc/math-emu/fadds.c --- v2.4.4/linux/arch/ppc/math-emu/fadds.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fadds.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fadds.c,v 1.1 1999/08/23 18:59:25 cort Exp $ +/* + * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fcmpo.c linux/arch/ppc/math-emu/fcmpo.c --- v2.4.4/linux/arch/ppc/math-emu/fcmpo.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fcmpo.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fcmpo.c,v 1.1 1999/08/23 18:59:26 cort Exp $ +/* + * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fcmpu.c linux/arch/ppc/math-emu/fcmpu.c --- v2.4.4/linux/arch/ppc/math-emu/fcmpu.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fcmpu.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fcmpu.c,v 1.1 1999/08/23 18:59:28 cort Exp $ +/* + * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fctiw.c linux/arch/ppc/math-emu/fctiw.c --- v2.4.4/linux/arch/ppc/math-emu/fctiw.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fctiw.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fctiw.c,v 1.1 1999/08/23 18:59:30 cort Exp $ +/* + * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fctiwz.c linux/arch/ppc/math-emu/fctiwz.c --- v2.4.4/linux/arch/ppc/math-emu/fctiwz.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fctiwz.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fctiwz.c,v 1.1 1999/08/23 18:59:31 cort Exp $ +/* + * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fdiv.c linux/arch/ppc/math-emu/fdiv.c --- v2.4.4/linux/arch/ppc/math-emu/fdiv.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fdiv.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fdiv.c,v 1.1 1999/08/23 18:59:33 cort Exp $ +/* + * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fdivs.c linux/arch/ppc/math-emu/fdivs.c --- v2.4.4/linux/arch/ppc/math-emu/fdivs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fdivs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fdivs.c,v 1.1 1999/08/23 18:59:35 cort Exp $ +/* + * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmadd.c linux/arch/ppc/math-emu/fmadd.c --- v2.4.4/linux/arch/ppc/math-emu/fmadd.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmadd.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmadd.c,v 1.1 1999/08/23 18:59:36 cort Exp $ +/* + * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmadds.c linux/arch/ppc/math-emu/fmadds.c --- v2.4.4/linux/arch/ppc/math-emu/fmadds.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmadds.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmadds.c,v 1.1 1999/08/23 18:59:38 cort Exp $ +/* + * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmr.c linux/arch/ppc/math-emu/fmr.c --- v2.4.4/linux/arch/ppc/math-emu/fmr.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmr.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmr.c,v 1.1 1999/08/23 18:59:40 cort Exp $ +/* + * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmsub.c linux/arch/ppc/math-emu/fmsub.c --- v2.4.4/linux/arch/ppc/math-emu/fmsub.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmsub.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmsub.c,v 1.1 1999/08/23 18:59:41 cort Exp $ +/* + * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmsubs.c linux/arch/ppc/math-emu/fmsubs.c --- v2.4.4/linux/arch/ppc/math-emu/fmsubs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmsubs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmsubs.c,v 1.1 1999/08/23 18:59:42 cort Exp $ +/* + * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmul.c linux/arch/ppc/math-emu/fmul.c --- v2.4.4/linux/arch/ppc/math-emu/fmul.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmul.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmul.c,v 1.1 1999/08/23 18:59:44 cort Exp $ +/* + * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fmuls.c linux/arch/ppc/math-emu/fmuls.c --- v2.4.4/linux/arch/ppc/math-emu/fmuls.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fmuls.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fmuls.c,v 1.1 1999/08/23 18:59:45 cort Exp $ +/* + * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fnabs.c linux/arch/ppc/math-emu/fnabs.c --- v2.4.4/linux/arch/ppc/math-emu/fnabs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fnabs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fnabs.c,v 1.1 1999/08/23 18:59:47 cort Exp $ +/* + * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fneg.c linux/arch/ppc/math-emu/fneg.c --- v2.4.4/linux/arch/ppc/math-emu/fneg.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fneg.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fneg.c,v 1.1 1999/08/23 18:59:48 cort Exp $ +/* + * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fnmadd.c linux/arch/ppc/math-emu/fnmadd.c --- v2.4.4/linux/arch/ppc/math-emu/fnmadd.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fnmadd.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fnmadd.c,v 1.1 1999/08/23 18:59:50 cort Exp $ +/* + * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fnmadds.c linux/arch/ppc/math-emu/fnmadds.c --- v2.4.4/linux/arch/ppc/math-emu/fnmadds.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fnmadds.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fnmadds.c,v 1.1 1999/08/23 18:59:51 cort Exp $ +/* + * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fnmsub.c linux/arch/ppc/math-emu/fnmsub.c --- v2.4.4/linux/arch/ppc/math-emu/fnmsub.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fnmsub.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fnmsub.c,v 1.1 1999/08/23 18:59:53 cort Exp $ +/* + * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fnmsubs.c linux/arch/ppc/math-emu/fnmsubs.c --- v2.4.4/linux/arch/ppc/math-emu/fnmsubs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fnmsubs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fnmsubs.c,v 1.1 1999/08/23 18:59:54 cort Exp $ +/* + * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fres.c linux/arch/ppc/math-emu/fres.c --- v2.4.4/linux/arch/ppc/math-emu/fres.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fres.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fres.c,v 1.1 1999/08/23 18:59:56 cort Exp $ +/* + * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/frsp.c linux/arch/ppc/math-emu/frsp.c --- v2.4.4/linux/arch/ppc/math-emu/frsp.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/frsp.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: frsp.c,v 1.1 1999/08/23 18:59:57 cort Exp $ +/* + * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/frsqrte.c linux/arch/ppc/math-emu/frsqrte.c --- v2.4.4/linux/arch/ppc/math-emu/frsqrte.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/frsqrte.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: frsqrte.c,v 1.1 1999/08/23 18:59:58 cort Exp $ +/* + * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fsel.c linux/arch/ppc/math-emu/fsel.c --- v2.4.4/linux/arch/ppc/math-emu/fsel.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fsel.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fsel.c,v 1.1 1999/08/23 18:59:59 cort Exp $ +/* + * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fsqrt.c linux/arch/ppc/math-emu/fsqrt.c --- v2.4.4/linux/arch/ppc/math-emu/fsqrt.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fsqrt.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fsqrt.c,v 1.1 1999/08/23 19:00:01 cort Exp $ +/* + * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fsqrts.c linux/arch/ppc/math-emu/fsqrts.c --- v2.4.4/linux/arch/ppc/math-emu/fsqrts.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fsqrts.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fsqrts.c,v 1.1 1999/08/23 19:00:03 cort Exp $ +/* + * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fsub.c linux/arch/ppc/math-emu/fsub.c --- v2.4.4/linux/arch/ppc/math-emu/fsub.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fsub.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fsub.c,v 1.1 1999/08/23 19:00:05 cort Exp $ +/* + * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/fsubs.c linux/arch/ppc/math-emu/fsubs.c --- v2.4.4/linux/arch/ppc/math-emu/fsubs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/fsubs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: fsubs.c,v 1.1 1999/08/23 19:00:07 cort Exp $ +/* + * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/lfd.c linux/arch/ppc/math-emu/lfd.c --- v2.4.4/linux/arch/ppc/math-emu/lfd.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/lfd.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: lfd.c,v 1.1 1999/08/23 19:00:08 cort Exp $ +/* + * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/lfs.c linux/arch/ppc/math-emu/lfs.c --- v2.4.4/linux/arch/ppc/math-emu/lfs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/lfs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: lfs.c,v 1.1 1999/08/23 19:00:10 cort Exp $ +/* + * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/math.c linux/arch/ppc/math-emu/math.c --- v2.4.4/linux/arch/ppc/math-emu/math.c Mon Mar 27 22:30:30 2000 +++ linux/arch/ppc/math-emu/math.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ -/* $Id: math.c,v 1.1 1999/08/23 19:00:11 cort Exp $ +/* + * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort + */ +/* * arch/ppc/math-emu/math.c * * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mcrfs.c linux/arch/ppc/math-emu/mcrfs.c --- v2.4.4/linux/arch/ppc/math-emu/mcrfs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mcrfs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mcrfs.c,v 1.1 1999/08/23 19:00:13 cort Exp $ +/* + * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mffs.c linux/arch/ppc/math-emu/mffs.c --- v2.4.4/linux/arch/ppc/math-emu/mffs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mffs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mffs.c,v 1.1 1999/08/23 19:00:14 cort Exp $ +/* + * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mtfsb0.c linux/arch/ppc/math-emu/mtfsb0.c --- v2.4.4/linux/arch/ppc/math-emu/mtfsb0.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mtfsb0.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mtfsb0.c,v 1.1 1999/08/23 19:00:16 cort Exp $ +/* + * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mtfsb1.c linux/arch/ppc/math-emu/mtfsb1.c --- v2.4.4/linux/arch/ppc/math-emu/mtfsb1.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mtfsb1.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mtfsb1.c,v 1.1 1999/08/23 19:00:17 cort Exp $ +/* + * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mtfsf.c linux/arch/ppc/math-emu/mtfsf.c --- v2.4.4/linux/arch/ppc/math-emu/mtfsf.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mtfsf.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mtfsf.c,v 1.1 1999/08/23 19:00:19 cort Exp $ +/* + * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/mtfsfi.c linux/arch/ppc/math-emu/mtfsfi.c --- v2.4.4/linux/arch/ppc/math-emu/mtfsfi.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/mtfsfi.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: mtfsfi.c,v 1.1 1999/08/23 19:00:20 cort Exp $ +/* + * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/op-1.h linux/arch/ppc/math-emu/op-1.h --- v2.4.4/linux/arch/ppc/math-emu/op-1.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/op-1.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort + */ +/* * Basic one-word fraction declaration and manipulation. */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/op-2.h linux/arch/ppc/math-emu/op-2.h --- v2.4.4/linux/arch/ppc/math-emu/op-2.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/op-2.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort + */ +/* * Basic two-word fraction declaration and manipulation. */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/op-4.h linux/arch/ppc/math-emu/op-4.h --- v2.4.4/linux/arch/ppc/math-emu/op-4.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/op-4.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort + */ +/* * Basic four-word fraction declaration and manipulation. * * When adding quadword support for 32 bit machines, we need diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/op-common.h linux/arch/ppc/math-emu/op-common.h --- v2.4.4/linux/arch/ppc/math-emu/op-common.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/op-common.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort + */ #define _FP_DECL(wc, X) \ _FP_I_TYPE X##_c, X##_s, X##_e; \ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/sfp-machine.h linux/arch/ppc/math-emu/sfp-machine.h --- v2.4.4/linux/arch/ppc/math-emu/sfp-machine.h Mon Mar 27 22:30:29 2000 +++ linux/arch/ppc/math-emu/sfp-machine.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort + */ /* Machine-dependent software floating-point definitions. PPC version. Copyright (C) 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/single.h linux/arch/ppc/math-emu/single.h --- v2.4.4/linux/arch/ppc/math-emu/single.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/single.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort + */ +/* * Definitions for IEEE Single Precision */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/soft-fp.h linux/arch/ppc/math-emu/soft-fp.h --- v2.4.4/linux/arch/ppc/math-emu/soft-fp.h Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/soft-fp.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort + */ #ifndef SOFT_FP_H #define SOFT_FP_H diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/stfd.c linux/arch/ppc/math-emu/stfd.c --- v2.4.4/linux/arch/ppc/math-emu/stfd.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/stfd.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: stfd.c,v 1.1 1999/08/23 19:00:33 cort Exp $ +/* + * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/stfiwx.c linux/arch/ppc/math-emu/stfiwx.c --- v2.4.4/linux/arch/ppc/math-emu/stfiwx.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/stfiwx.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: stfiwx.c,v 1.1 1999/08/23 19:00:34 cort Exp $ +/* + * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/stfs.c linux/arch/ppc/math-emu/stfs.c --- v2.4.4/linux/arch/ppc/math-emu/stfs.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/stfs.c Mon May 21 17:04:47 2001 @@ -1,6 +1,6 @@ -/* $Id: stfs.c,v 1.1 1999/08/23 19:00:35 cort Exp $ +/* + * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort */ - #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/types.c linux/arch/ppc/math-emu/types.c --- v2.4.4/linux/arch/ppc/math-emu/types.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/types.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort + */ #include "soft-fp.h" #include "double.h" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/math-emu/udivmodti4.c linux/arch/ppc/math-emu/udivmodti4.c --- v2.4.4/linux/arch/ppc/math-emu/udivmodti4.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/math-emu/udivmodti4.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort + */ /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ #include "soft-fp.h" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/Makefile linux/arch/ppc/mbxboot/Makefile --- v2.4.4/linux/arch/ppc/mbxboot/Makefile Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/mbxboot/Makefile Wed Dec 31 16:00:00 1969 @@ -1,124 +0,0 @@ -# -# arch/ppc/mbxboot/Makefile -# -# 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) 1994 by Linus Torvalds -# Adapted for PowerPC by Gary Thomas -# modified by Cort (cort@cs.nmt.edu) -# -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -ZOFF = 0 -ZSZ = 0 -IOFF = 0 -ISZ = 0 - -TFTPIMAGE=/tftpboot/zImage.embedded - -ifdef CONFIG_8xx -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000 -OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx -endif - -ifdef CONFIG_8260 -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000 -OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260 -endif - -OBJCOPY_ARGS = -O elf32-powerpc - -ifeq ($(CONFIG_MBX),y) -OBJECTS += pci.o qspan_pci.o -CFLAGS += -DCONFIG_MBX -endif -ifeq ($(CONFIG_RPXLITE),y) -CFLAGS += -DCONFIG_RPXLITE -OBJECTS += iic.o embed_config.o -endif -ifeq ($(CONFIG_RPXCLASSIC),y) -CFLAGS += -DCONFIG_RPXCLASSIC -OBJECTS += iic.o embed_config.o pci.o qspan_pci.o -endif -ifeq ($(CONFIG_BSEIP),y) -CFLAGS += -DCONFIG_BSEIP -OBJECTS += iic.o embed_config.o -endif - -all: zImage - -zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp1 zvmlinux.initrd1 - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ - -zImage: zvmlinux - ln -sf zvmlinux zImage - -zImage.initrd: zvmlinux.initrd - ln -sf zvmlinux.initrd zImage.initrd - -zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp - -znetboot : zImage - cp zImage $(TFTPIMAGE) - -znetboot.initrd : zImage.initrd - cp zImage.initrd $(TFTPIMAGE) - -clean: - rm -f vmlinux* zvmlinux* zImage* - -fastdep: - $(TOPDIR)/scripts/mkdep *.[Sch] > .depend - -dep: - $(CPP) $(CPPFLAGS) -M *.S *.c > .depend - -# just here to match coffboot/Makefile -vmlinux.coff: - -vmlinux.coff.initrd: diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/embed_config.c linux/arch/ppc/mbxboot/embed_config.c --- v2.4.4/linux/arch/ppc/mbxboot/embed_config.c Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/mbxboot/embed_config.c Wed Dec 31 16:00:00 1969 @@ -1,253 +0,0 @@ - -/* Board specific functions for those embedded 8xx boards that do - * not have boot monitor support for board information. - */ -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#endif - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); -extern u_char aschex_to_byte(u_char *cp); - -/* Supply a default Ethernet address for those eval boards that don't - * ship with one. This is an address from the MBX board I have, so - * it is unlikely you will find it on your network. - */ -static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - -static void rpx_eth(bd_t *bd, u_char *cp); -static void rpx_brate(bd_t *bd, u_char *cp); -static void rpx_memsize(bd_t *bd, u_char *cp); -static void rpx_cpuspeed(bd_t *bd, u_char *cp); - -/* Read the EEPROM on the RPX-Lite board. -*/ -void -rpx_cfg(bd_t *bd) -{ - u_char eebuf[256], *cp; - - /* Read the first 256 bytes of the EEPROM. I think this - * is really all there is, and I hope if it gets bigger the - * info we want is still up front. - */ -#if 1 - iic_read(0xa8, eebuf, 0, 128); - iic_read(0xa8, &eebuf[128], 128, 128); - { - int i; - cp = (u_char *)0xfa000000; - - for (i=0; i<256; i++) - *cp++ = eebuf[i]; - } - - /* We look for two things, the Ethernet address and the - * serial baud rate. The records are separated by - * newlines. - */ - cp = eebuf; - for (;;) { - if (*cp == 'E') { - cp++; - if (*cp == 'A') { - cp += 2; - rpx_eth(bd, cp); - } - } - if (*cp == 'S') { - cp++; - if (*cp == 'B') { - cp += 2; - rpx_brate(bd, cp); - } - } - if (*cp == 'D') { - cp++; - if (*cp == '1') { - cp += 2; - rpx_memsize(bd, cp); - } - } - if (*cp == 'H') { - cp++; - if (*cp == 'Z') { - cp += 2; - rpx_cpuspeed(bd, cp); - } - } - - /* Scan to the end of the record. - */ - while ((*cp != '\n') && (*cp != 0xff)) - cp++; - - /* If the next character is a 0 or ff, we are done. - */ - cp++; - if ((*cp == 0) || (*cp == 0xff)) - break; - } - bd->bi_memstart = 0; - -#else - /* For boards without initialized EEPROM. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (8 * 1024 * 1024); - bd->bi_intfreq = 48; - bd->bi_busfreq = 48; - bd->bi_baudrate = 9600; -#endif -} - -static void -rpx_eth(bd_t *bd, u_char *cp) -{ - int i; - - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = aschex_to_byte(cp); - cp += 2; - } -} - -static void -rpx_brate(bd_t *bd, u_char *cp) -{ - uint rate; - - rate = 0; - - while (*cp != '\n') { - rate *= 10; - rate += (*cp) - '0'; - cp++; - } - - bd->bi_baudrate = rate * 100; -} - -static void -rpx_memsize(bd_t *bd, u_char *cp) -{ - uint size; - - size = 0; - - while (*cp != '\n') { - size *= 10; - size += (*cp) - '0'; - cp++; - } - - bd->bi_memsize = size * 1024 * 1024; -} - -static void -rpx_cpuspeed(bd_t *bd, u_char *cp) -{ - uint num, den; - - num = den = 0; - - while (*cp != '\n') { - num *= 10; - num += (*cp) - '0'; - cp++; - if (*cp == '/') { - cp++; - den = (*cp) - '0'; - break; - } - } - - /* I don't know why the RPX just can't state the actual - * CPU speed..... - */ - if (den) { - num /= den; - num *= den; - } - bd->bi_intfreq = bd->bi_busfreq = num; - - /* The 8xx can only run a maximum 50 MHz bus speed (until - * Motorola changes this :-). Greater than 50 MHz parts - * run internal/2 for bus speed. - */ - if (num > 50) - bd->bi_busfreq /= 2; -} -#endif /* RPXLITE || RPXCLASSIC */ - -#ifdef CONFIG_BSEIP -/* Build a board information structure for the BSE ip-Engine. - * There is more to come since we will add some environment - * variables and a function to read them. - */ -void -bseip_cfg(bd_t *bd) -{ - u_char *cp; - int i; - - /* Baud rate and processor speed will eventually come - * from the environment variables. - */ - bd->bi_baudrate = 9600; - - /* Get the Ethernet station address from the Flash ROM. - */ - cp = (u_char *)0xfe003ffa; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } - - /* The rest of this should come from the environment as well. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (16 * 1024 * 1024); - bd->bi_intfreq = 48; - bd->bi_busfreq = 48; -} -#endif /* BSEIP */ - -#ifdef CONFIG_EST8260 -void -embed_config(bd_t *bd) -{ - u_char *cp; - int i; - -#if 0 - /* This is actually provided by my boot rom. I have it - * here for those people that may load the kernel with - * a JTAG/COP tool and not the rom monitor. - */ - bd->bi_baudrate = 115200; - bd->bi_intfreq = 200; - bd->bi_busfreq = 66; - bd->bi_cpmfreq = 66; - bd->bi_brgfreq = 33; - bd->bi_memsize = 16 * 1024 * 1024; -#endif - - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } -} -#endif /* EST8260 */ - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/gzimage.c linux/arch/ppc/mbxboot/gzimage.c --- v2.4.4/linux/arch/ppc/mbxboot/gzimage.c Mon May 15 14:53:30 2000 +++ linux/arch/ppc/mbxboot/gzimage.c Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * gzimage.c - * - * Dummy file to allow a compressed zImage to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_gzimage; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/head.S linux/arch/ppc/mbxboot/head.S --- v2.4.4/linux/arch/ppc/mbxboot/head.S Thu Oct 7 10:17:08 1999 +++ linux/arch/ppc/mbxboot/head.S Wed Dec 31 16:00:00 1969 @@ -1,249 +0,0 @@ -#include -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.6 1999/09/15 00:02:25 dmalek Exp $ - * - * This code is loaded by the ROM loader at some arbitrary location. - * Move it to high memory so that it can load the kernel at 0x0000. - * - * This is a three step process that will also work when booting from - * a Flash PROM normally located in high memory. - * - * First, the entire image is loaded into some high memory address. - * This is usually at or above 0x02000000. This is done by a network - * boot function supported by the board or a debugger over BDM port. - * - * Second, the start up function here will relocate the decompress - * function to run at the link address of 0x01000000. - * - * Last, the decompression function will reloate the initrd, zImage, and - * the residual data to locations under 8 Meg. This is necessary because - * the embedded kernel start up uses 8 Meg translations to access physical - * space before the MMU is enabled. Finally, the zImage is uncompressed - * to location 0 and we jump to it. - * - * On the MBX, - * R1 - Stack pointer at a high memory address. - * R3 - Pointer to Board Information Block. - * R4 - Pointer to argument string. - * Interrupts masked, cache and MMU disabled. - * - * ...and the first and second functions listed above are - * done for us (it knows ELF images). - * - * For other embedded boards we build the Board Information Block. - */ - - .globl start -start: - bl start_ -start_: -#ifndef CONFIG_MBX - lis r11, local_bd_info@h - ori r11, r11, local_bd_info@l -#else - mr r11, r3 -#endif - - mfmsr r3 /* Turn off interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r3,r3,r4 - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 -#if 0 - cmp 0,r3,r4 - beq start_ldr /* Branch if loaded OK */ -#endif - -/* - * no matter where we're loaded, move ourselves to -Ttext address - * This computes the sizes we need to determine other things. - */ - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr - -start_ldr: -/* Most 8xx boards don't boot up with the I-cache enabled. Do that - * now because the decompress runs much faster that way. - */ - lis r3, IDC_INVALL@h - mtspr IC_CST, r3 - lis r3, IDC_ENABLE@h - mtspr IC_CST, r3 - -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b - - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Perform configuration of the various boards. This is done - * by reading some configuration data from EEPROM and building - * the board information structure. - */ - mr r3, r11 - mr r21, r11 - mr r22, r8 - mr r23, r7 - mr r24, r6 - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - bl rpx_cfg - mr r3, r21 -#endif -#ifdef CONFIG_BSEIP - bl bseip_cfg - mr r3, r21 -#endif - bl serial_init /* Init MBX serial port */ - - mr r11, r21 - mr r8, r22 - mr r7, r23 - mr r6, r24 - -#ifdef CONFIG_MBX - lis r18, 0xfa200000@h /* Disable Ethernet SCC */ - li r0, 0 - stw r0, 0x0a00(r18) - - /* On the MBX (or anything that will TFTP load an ELF image), - * we have to find the intermediate address. The ELF loader - * only moves the Linux boostrap/decompress, not the zImage. - */ -#define ILAP_ADDRESS 0xfa000020 - lis r8, ILAP_ADDRESS@h - lwz r8, ILAP_ADDRESS@l(r8) - addis r8, r8, 1 /* Add 64K */ -#endif - - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - - /* The world starts from the beginning. - */ - li r9,0x0 - mtlr r9 - - /* Invalidate the instruction cache because we just copied a - * bunch of kernel instructions. - */ - lis r9, IDC_INVALL@h - mtspr IC_CST, r9 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - - .comm .stack,4096*2,4 -#ifndef CONFIG_MBX -local_bd_info: - .long 0 - .long 0x01000000 - .long 64 - .long 64 - .long 0 - .long 0 - .long 0 -#endif diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/head_8260.S linux/arch/ppc/mbxboot/head_8260.S --- v2.4.4/linux/arch/ppc/mbxboot/head_8260.S Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/mbxboot/head_8260.S Wed Dec 31 16:00:00 1969 @@ -1,258 +0,0 @@ -#include "../kernel/ppc_defs.h" -#include "../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ - * - * Boot loader philosophy: - * - * ROM loads us to some arbitrary location - * ROM loads these registers: - * - * R3 = Pointer to the board configuration data - * R5 = Pointer to Open Firmware data - * - * ROM jumps to start/start_ - * Move the boot code to the link address (4 MB) - * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 4 MB - * Decompress the kernel to 0 - * Jump to the kernel entry - * -- Cort - */ - .globl start -start: - bl start_ -start_: - mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* round up */ - sub r5,r5,r4 - srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* - * no matter where we're loaded, move ourselves to -Ttext address - */ -relocate: - mflr r3 /* Compute code bias */ - subi r3,r3,4 - mr r8,r3 - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr -start_ldr: -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Speed us up a little. - */ - bl flush_instruction_cache - -/* Run loader */ - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ - li r9,0x4 - mtlr r9 - lis r10,0xdeadc0de@h - ori r10,r10,0xdeadc0de@l - li r9,0 - stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 -00: li r0,86 /* Instructions / microsecond? */ - mtctr r0 -10: addi r0,r0,0 /* NOP */ - bdnz 10b - subic. r3,r3,1 - bne 00b - blr - -.udelay_not_601: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr - .comm .stack,4096*2,4 diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/iic.c linux/arch/ppc/mbxboot/iic.c --- v2.4.4/linux/arch/ppc/mbxboot/iic.c Tue May 2 13:05:40 2000 +++ linux/arch/ppc/mbxboot/iic.c Wed Dec 31 16:00:00 1969 @@ -1,259 +0,0 @@ - -/* Minimal support functions to read configuration from IIC EEPROMS - * on MPC8xx boards. Originally written for RPGC RPX-Lite. - * Dan Malek (dmalek@jlc.net). - */ -#include -#include -#include "asm/mpc8xx.h" -#include "../8xx_io/commproc.h" - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -void iic_read(uint devaddr, u_char *buf, uint offset, uint count); -u_char aschex_to_byte(u_char *cp); - -static int iic_init_done; - -static void -iic_init() -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - uint dpaddr; - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - /* Reset the CPM. This is necessary on the 860 processors - * that may have started the SCC1 ethernet without relocating - * the IIC. - * This also stops the Ethernet in case we were loaded by a - * BOOTP rom monitor. - */ - cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); - - /* Wait for it. - */ - while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); - - /* Remove any microcode patches. We will install our own - * later. - */ - cp->cp_cpmcr1 = 0; - cp->cp_cpmcr2 = 0; - cp->cp_cpmcr3 = 0; - cp->cp_cpmcr4 = 0; - cp->cp_rccr = 0; - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - /* Initialize Port B IIC pins. - */ - cp->cp_pbpar |= 0x00000030; - cp->cp_pbdir |= 0x00000030; - cp->cp_pbodr |= 0x00000030; - - /* Initialize the parameter ram. - */ - - /* Allocate space for a two transmit and one receive buffer - * descriptor in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0840; - - /* Set up the IIC parameters in the parameter ram. - */ - iip->iic_tbase = dpaddr; - iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); - - iip->iic_tfcr = SMC_EB; - iip->iic_rfcr = SMC_EB; - - /* This should really be done by the reader/writer. - */ - iip->iic_mrblr = 128; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Select an arbitrary address. Just make sure it is unique. - */ - i2c->i2c_i2add = 0x34; - - /* Make clock run maximum slow. - */ - i2c->i2c_i2brg = 7; - - /* Disable interrupts. - */ - i2c->i2c_i2cmr = 0; - i2c->i2c_i2cer = 0xff; - - /* Enable SDMA. - */ - immap->im_siu_conf.sc_sdcr = 1; - - iic_init_done = 1; -} - -/* Read from IIC. - * Caller provides device address, memory buffer, and byte count. - */ -static u_char iitemp[32]; - -void -iic_read(uint devaddr, u_char *buf, uint offset, uint count) -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - u_char *tb; - uint dpaddr, temp; - - /* If the interface has not been initialized, do that now. - */ - if (!iic_init_done) - iic_init(); - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; - - /* Send a "dummy write" operation. This is a write request with - * only the offset sent, followed by another start condition. - * This will ensure we start reading from the first location - * of the EEPROM. - */ - tb = iitemp; - tb = (u_char *)(((uint)tb + 15) & ~15); - tbdf->cbd_bufaddr = tb; - *tb = devaddr & 0xfe; /* Device address */ - *(tb+1) = offset; /* Offset */ - tbdf->cbd_datlen = 2; /* Length */ - tbdf->cbd_sc = - BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 3) == 0); - - if (tbdf->cbd_sc & BD_SC_READY) - printf("IIC ra complete but tbuf ready\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#if 0 - /* We can't do this...there is no serial port yet! - */ - if (temp == 0) { - printf("Timeout reading EEPROM\n"); - return; - } -#endif -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; - - /* To read, we need an empty buffer of the proper length. - * All that is used is the first byte for address, the remainder - * is just used for timing (and doesn't really have to exist). - */ - tbdf->cbd_bufaddr = tb; - *tb = devaddr | 1; /* Device address */ - rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ - tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ - tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; - - /* Chip bug, set enable here. - */ - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 1) == 0); - - if (rbdf->cbd_sc & BD_SC_EMPTY) - printf("IIC read complete but rbuf empty\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; -} - -/* Because I didn't find anything that would do this....... -*/ -u_char -aschex_to_byte(u_char *cp) -{ - u_char byte, c; - - c = *cp++; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte = c * 16; - - c = *cp; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte += c; - - return(byte); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/m8260_tty.c linux/arch/ppc/mbxboot/m8260_tty.c --- v2.4.4/linux/arch/ppc/mbxboot/m8260_tty.c Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/mbxboot/m8260_tty.c Wed Dec 31 16:00:00 1969 @@ -1,201 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on SMC1. - */ -#include -#include "asm/mpc8260.h" -#include "asm/cpm_8260.h" - -uint no_print; -extern char *params[]; -extern int nparams; -static u_char cons_hold[128], *sgptr; -static int cons_hold_cnt; - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile immap_t *ip; - volatile iop8260_t *io; - volatile cpm8260_t *cp; - uint dpaddr, memaddr; - - ip = (immap_t *)IMAP_ADDR; - - sp = (smc_t*)&(ip->im_smc[0]); - *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; - up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; - - cp = &ip->im_cpm; - io = &ip->im_ioport; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - - /* Use Port D for SMC1 instead of other functions. - */ - io->iop_ppard |= 0x00c00000; - io->iop_pdird |= 0x00400000; - io->iop_pdird &= ~0x00800000; - io->iop_psord &= ~0x00c00000; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. - */ -#if 1 - memaddr = (bd->bi_memsize - 256) & ~15; -#else - memaddr = 0x0f002c00; -#endif - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+128; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = CPMFCR_EB; - up->smc_tfcr = CPMFCR_EB; - up->smc_brklen = 0; - up->smc_brkec = 0; - up->smc_brkcr = 0; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - */ - ip->im_clkrst.car_sccr = 0; /* DIV 4 BRG */ - ip->im_cpmux.cmx_smr = 0; - ip->im_brgc1 = - ((((bd->bi_brgfreq * 1000000)/16) / bd->bi_baudrate) << 1) | - CPM_BRG_EN; - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - -#if 0 - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; -#else - up->smc_mrblr = 128; - up->smc_maxidl = 8; -#endif - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile immap_t *ip; - extern bd_t *board_info; - - ip = (immap_t *)IMAP_ADDR; - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - char c; - - if (cons_hold_cnt <= 0) { - cons_hold_cnt = serial_readbuf(cons_hold); - sgptr = cons_hold; - } - c = *sgptr++; - cons_hold_cnt--; - - return(c); -} - -int -serial_readbuf(u_char *cbuf) -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile immap_t *ip; - int i, nc; - - ip = (immap_t *)IMAP_ADDR; - - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - nc = rbdf->cbd_datlen; - for (i=0; icbd_sc |= BD_SC_EMPTY; - - return(nc); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - volatile immap_t *ip; - - ip = (immap_t *)IMAP_ADDR; - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/m8xx_tty.c linux/arch/ppc/mbxboot/m8xx_tty.c --- v2.4.4/linux/arch/ppc/mbxboot/m8xx_tty.c Thu Jul 13 09:42:51 2000 +++ linux/arch/ppc/mbxboot/m8xx_tty.c Wed Dec 31 16:00:00 1969 @@ -1,276 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on the MBX console. - * - * The MBX uxes SMC1 for the serial port. We reset the port and use - * only the first BD that EPPC-Bug set up as a character FIFO. - * - * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug - * use COM1 instead of SMC1 as the console port. This kinda sucks - * for the rest of the kernel, so here we force the use of SMC1 again. - */ -#include -#include -#include -#include -#include "../8xx_io/commproc.h" - -#ifdef CONFIG_MBX -#define MBX_CSR1 ((volatile u_char *)0xfa100000) -#define CSR1_COMEN (u_char)0x02 -#endif - -#ifdef TQM_SMC2_CONSOLE -#define PROFF_CONS PROFF_SMC2 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 -#define SMC_INDEX 1 -static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); -#else -#define PROFF_CONS PROFF_SMC1 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 -#define SMC_INDEX 0 -#endif - -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - uint dpaddr, memaddr; - - cp = cpmp; - sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); - up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - -#ifndef CONFIG_MBX - { - /* Initialize SMCx and use it for the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - -#ifdef TQM_SMC2_CONSOLE - /* Use Port A for SMC2 instead of other functions. - */ - iopp->iop_papar |= 0x00c0; - iopp->iop_padir &= ~0x00c0; - iopp->iop_paodr &= ~0x00c0; -#else - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; -#endif - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory for SMC FIFOs. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - * This wires BRG1 to SMC1 and BRG2 to SMC2; - */ - cp->cp_simode = 0x10000000; -#ifdef TQM_SMC2_CONSOLE - cp->cp_brgc2 = -#else - cp->cp_brgc1 = -#endif - ((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN; - -#else /* CONFIG_MBX */ - if (*MBX_CSR1 & CSR1_COMEN) { - /* COM1 is enabled. Initialize SMC1 and use it for - * the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. EPPC-Bug isn't - * running any more, so we can do this. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - */ - cp->cp_simode = 0x10000000; - cp->cp_brgc1 = - ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; - - /* Enable SMC1 for console output. - */ - *MBX_CSR1 &= ~CSR1_COMEN; - } - else { -#endif /* ndef CONFIG_MBX */ - /* SMCx is used as console port. - */ - tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; - - /* Issue a stop transmit, and wait for it. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, - CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - } - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - char c; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - c = *buf; - rbdf->cbd_sc |= BD_SC_EMPTY; - - return(c); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/misc.c linux/arch/ppc/mbxboot/misc.c --- v2.4.4/linux/arch/ppc/mbxboot/misc.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/mbxboot/misc.c Wed Dec 31 16:00:00 1969 @@ -1,476 +0,0 @@ -/* - * misc.c - * - * $Id: misc.c,v 1.2 1999/09/14 05:55:29 dmalek Exp $ - * - * Adapted for PowerPC by Gary Thomas - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) - * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort - */ - -#include -#include "../coffboot/zlib.h" -#include "asm/residual.h" -#include -#include -#include -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#endif - -/* - * The following references are needed to cause the linker to pull in the - * gzimage.o and rdimage.o files. These object files are special, - * since they get placed into the .gzimage and .rdimage ELF sections - * of the zvmlinux and zvmlinux.initrd files. - */ -extern char dummy_for_gzimage; -extern char dummy_for_rdimage; - -/* - * Please send me load/board info and such data for hardware not - * listed here so I can keep track since things are getting tricky - * with the different load addrs with different firmware. This will - * help to avoid breaking the load/boot process. - * -- Cort - */ -char *avail_ram; -char *end_avail; - -/* See comment below..... -*/ -unsigned int initrd_offset, initrd_size; - -/* Because of the limited amount of memory on embedded, it presents - * loading problems. The biggest is that we load this boot program - * into a relatively low memory address, and the Linux kernel Bss often - * extends into this space when it get loaded. When the kernel starts - * and zeros the BSS space, it also writes over the information we - * save here and pass to the kernel (command line and board info). - * On these boards, we grab some known memory holes to hold this information. - */ -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -char *root_string = "root=/dev/nfs rw"; -char *nfsaddrs_string = "nfsaddrs="; -char *nfsroot_string = "nfsroot="; -char *defroot_string = "/sys/mbxroot"; -char *ramroot_string = "root=/dev/ram"; -int do_ipaddrs(char **cmd_cp, int echo); -void do_nfsroot(char **cmd_cp, char *dp); -int strncmp(const char * cs,const char * ct,size_t count); -char *strrchr(const char * s, int c); - -bd_t hold_resid_buf; -bd_t *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; -char *zimage_start; -int zimage_size; - -void puts(const char *); -void putc(const char c); -void puthex(unsigned long val); -void _bcopy(char *src, char *dst, int len); -void * memcpy(void * __dest, __const void * __src, - int __n); -void gunzip(void *, int, unsigned char *, int *); - -void pause() -{ - puts("pause\n"); -} - -void exit() -{ - puts("exit\n"); - while(1); -} - -/* The MPC8xx is just the serial port. -*/ -tstc(void) -{ - return (serial_tstc()); -} - -getc(void) -{ - while (1) { - if (serial_tstc()) return (serial_getc()); - } -} - -void -putc(const char c) -{ - serial_putchar(c); -} - -void puts(const char *s) -{ - char c; - - while ( ( c = *s++ ) != '\0' ) { - serial_putchar(c); - if ( c == '\n' ) - serial_putchar('\r'); - } -} - -void * memcpy(void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++) d[i] = s[i]; -} - -int memcmp(__const void * __dest, __const void * __src, - int __n) -{ - int i; - char *d = (char *)__dest, *s = (char *)__src; - - for (i=0;i<__n;i++, d++, s++) - { - if (*d != *s) - { - return (*s - *d); - } - } - return (0); -} - -void error(char *x) -{ - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); - - while(1); /* Halt */ -} - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p = avail_ram; - - size *= items; - size = (size + 7) & -8; - avail_ram += size; - if (avail_ram > end_avail) { - puts("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - puts("bad gzipped data\n"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - puts("gunzip: ran out of data in header\n"); - exit(); - } - - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - puts("inflateInit2 returned %d\n"); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - puts("inflate returned "); - puthex(r); - puts("\n"); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - inflateEnd(&s); -} - -unsigned char sanity[0x2000]; - -unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) -{ - int timer; - extern unsigned long start; - char *cp, ch; - unsigned long i; - char *dp; - -#ifdef CONFIG_8260 - /* I don't know why I didn't do it this way on the 8xx....... - */ - embed_config(bp); - serial_init(bp); -#endif - - /* These values must be variables. If not, the compiler optimizer - * will remove some code, causing the size of the code to vary - * when these values are zero. This is bad because we first - * compile with these zero to determine the size and offsets - * in an image, than compile again with these set to the proper - * discovered value.....Ya know, we used to read these from the - * header a long time ago..... - */ - initrd_offset = INITRD_OFFSET; - initrd_size = INITRD_SIZE; - - /* Grab some space for the command line and board info. Since - * we no longer use the ELF header, but it was loaded, grab - * that space. - */ -#ifdef CONFIG_MBX - cmd_line = (char *)(load_addr - 0x10000); - - /* To be like everyone else, we need one too, although this - * board information is passed from the boot rom. - */ - bp->bi_baudrate = 9600; -#else - cmd_line = (char *)(0x200000); -#endif - hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); - /* copy board data */ - if (bp) - memcpy(hold_residual,bp,sizeof(bd_t)); - - /* Set end of memory available to us. It is always the highest - * memory address provided by the board information. - */ - end_avail = (char *)(bp->bi_memsize); - - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( bp ) - { - puts("board data at: "); puthex((unsigned long)bp); - puts(" "); - puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); - puts("\n"); - } - - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - - if ( initrd_offset ) - initrd_start = load_addr - 0x10000 + initrd_offset; - else - initrd_start = 0; - initrd_end = initrd_size + initrd_start; - - /* - * setup avail_ram - this is the first part of ram usable - * by the uncompress code. -- Cort - */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); - if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)(load_addr+(num_words*4)); - if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)((unsigned long)&start+(num_words*4)); - - /* relocate zimage */ - puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - /* - * There is no reason (yet) to relocate zImage for embedded boards. - * To support boot from flash rom on 8xx embedded boards, I - * assume if zimage start is over 16M we are booting from flash. - * In this case, avilable ram will start just above the space we - * have allocated for the command buffer and board information. - */ - if ((unsigned long)zimage_start > 0x01000000) - avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); - - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - - /* We only have to relocate initrd if we find it is in Flash - * rom. This is because the kernel thinks it can toss the - * pages into the free memory pool after it is done. Use - * the same 16M test. - */ - if ((unsigned long)initrd_start > 0x01000000) { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), - (void *)initrd_start, - initrd_size ); - initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); - initrd_end = initrd_start + initrd_size; - end_avail = (char *)initrd_start; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - else { - avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); - } - } - - - puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); - puthex((unsigned long)end_avail); puts("\n"); - - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - - /* If the command line is not filled in, we will automatically - * create the default boot. - */ - if (cmd_line[0] == 0) { - - /* An initrd on these boards means we booted from Flash - * ROM and want to use the ramdisk as the root file system. - * Otherwise, we perform a diskless NFS boot. - */ - if (initrd_start) - dp = ramroot_string; - else - dp = root_string; - while (*dp != 0) - *cp++ = *dp++; - *cp = 0; - } - - puts("\n"); - - puts("Uncompressing Linux..."); - - gunzip(0, 0x400000, zimage_start, &zimage_size); - puts("done.\n"); - puts("Now booting the kernel\n"); - return (unsigned long)hold_residual; -} - -void puthex(unsigned long val) -{ - unsigned char buf[10]; - int i; - for (i = 7; i >= 0; i--) - { - buf[i] = "0123456789ABCDEF"[val & 0x0F]; - val >>= 4; - } - buf[8] = '\0'; - puts(buf); -} - -/* - * PCI/ISA I/O support - */ - -volatile unsigned char *ISA_io = (unsigned char *)0x80000000; -volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; - -void -outb(int port, char val) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - ISA_io[port] = val; -} - -unsigned char -inb(int port) -{ - /* Ensure I/O operations complete */ - __asm__ volatile("eieio"); - return (ISA_io[port]); -} - -unsigned long -local_to_PCI(unsigned long addr) -{ - return ((addr & 0x7FFFFFFF) | 0x80000000); -} - -void -_bcopy(char *src, char *dst, int len) -{ - while (len--) *dst++ = *src++; -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/offset linux/arch/ppc/mbxboot/offset --- v2.4.4/linux/arch/ppc/mbxboot/offset Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/mbxboot/offset Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` -echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/pci.c linux/arch/ppc/mbxboot/pci.c --- v2.4.4/linux/arch/ppc/mbxboot/pci.c Tue May 2 13:05:40 2000 +++ linux/arch/ppc/mbxboot/pci.c Wed Dec 31 16:00:00 1969 @@ -1,252 +0,0 @@ -/* Stand alone funtions for QSpan Tundra support. - */ -#include -#include -#include -#include - -/* To map PCI devices, you first write 0xffffffff into the device - * base address registers. When the register is read back, the - * number of most significant '1' bits describes the amount of address - * space needed for mapping. If the most significant bit is not set, - * either the device does not use that address register, or it has - * a fixed address that we can't change. After the address is assigned, - * the command register has to be written to enable the card. - */ -typedef struct { - u_char pci_bus; - u_char pci_devfn; - ushort pci_command; - uint pci_addrs[6]; -} pci_map_t; - -/* We should probably dynamically allocate these structures. -*/ -#define MAX_PCI_DEVS 32 -int pci_dev_cnt; -pci_map_t pci_map[MAX_PCI_DEVS]; - -void pci_conf_write(int bus, int device, int func, int reg, uint writeval); -void pci_conf_read(int bus, int device, int func, int reg, void *readval); -void probe_addresses(int bus, int devfn); -void map_pci_addrs(void); - -/* This is a really stripped version of PCI bus scan. All we are - * looking for are devices that exist. - */ -pci_scanner(int addr_probe) -{ - unsigned int devfn, l, max, class, bus_number; - unsigned char cmd, irq, tmp, hdr_type, is_multi; - int reg; - - is_multi = 0; - bus_number = 0; - for (devfn = 0; devfn < 0xff; ++devfn) { - /* The device numbers are comprised of upper 5 bits of - * device number and lower 3 bits of multi-function number. - */ - if ((devfn & 7) && !is_multi) { - /* Don't scan multifunction addresses if this is - * not a multifunction device. - */ - continue; - } - - /* Read the header to determine card type. - */ - qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, - &hdr_type); - - /* If this is a base device number, check the header to - * determine if it is mulifunction. - */ - if ((devfn & 7) == 0) - is_multi = hdr_type & 0x80; - - /* Check to see if the board is really in the slot. - */ - qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); - /* some broken boards return 0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || - l == 0xffff0000) { - /* Nothing there. - */ - is_multi = 0; - continue; - } - - /* If we are not performing an address probe, - * just simply print out some information. - */ - if (!addr_probe) { - qs_pci_read_config_dword(bus_number, devfn, - PCI_CLASS_REVISION, &class); - - class >>= 8; /* upper 3 bytes */ - -#if 0 - printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", - (devfn >> 3), (devfn & 7), - (l & 0xffff), (l >> 16) & 0xffff, class); -#else - puts("Found ("); puthex(devfn >> 3); - puts(":"); puthex(devfn & 7); - puts("): vendor "); puthex(l & 0xffff); - puts(", device "); puthex((l >> 16) & 0xffff); - puts(", class "); puthex(class); puts("\n"); -#endif - } - else { - /* If this is a "normal" device, build address list. - */ - if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) - probe_addresses(bus_number, devfn); - } - } - - /* Now map the boards. - */ - if (addr_probe) - map_pci_addrs(); -} - -/* Probe addresses for the specified device. This is a destructive - * operation because it writes the registers. - */ -void -probe_addresses(bus, devfn) -{ - int i; - uint pciaddr; - ushort pcicmd; - pci_map_t *pm; - - if (pci_dev_cnt >= MAX_PCI_DEVS) { - puts("Too many PCI devices\n"); - return; - } - - pm = &pci_map[pci_dev_cnt++]; - - pm->pci_bus = bus; - pm->pci_devfn = devfn; - - for (i=0; i<6; i++) { - qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); - qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), - &pciaddr); - pm->pci_addrs[i] = pciaddr; - qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); - pm->pci_command = pcicmd; - } -} - -/* Map the cards into the PCI space. The PCI has separate memory - * and I/O spaces. In addition, some memory devices require mapping - * below 1M. The least significant 4 bits of the address register - * provide information. If this is an I/O device, only the LS bit - * is used to indicate that, so I/O devices can be mapped to a two byte - * boundard. Memory addresses can be mapped to a 32 byte boundary. - * The QSpan implementations usually have a 1Gbyte space for each - * memory and I/O spaces. - * - * This isn't a terribly fancy algorithm. I just map the spaces from - * the top starting with the largest address space. When finished, - * the registers are written and the card enabled. - * - * While the Tundra can map a large address space on most boards, we - * need to be careful because it may overlap other devices (like IMMR). - */ -#define MEMORY_SPACE_SIZE 0x20000000 -#define IO_SPACE_SIZE 0x20000000 - -void -map_pci_addrs() -{ - uint pci_mem_top, pci_mem_low; - uint pci_io_top; - uint addr_mask, reg_addr, space; - int i, j; - pci_map_t *pm; - - pci_mem_top = MEMORY_SPACE_SIZE; - pci_io_top = IO_SPACE_SIZE; - pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ - - /* We can't map anything more than the maximum space, but test - * for it anyway to catch devices out of range. - */ - addr_mask = 0x80000000; - - do { - space = (~addr_mask) + 1; /* Size of the space */ - for (i=0; ipci_addrs[j]; - if ((reg_addr & 0x80000000) == 0) - continue; - if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { - if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) - continue; - if (pci_io_top < space) { - puts("Out of PCI I/O space\n"); - } - else { - pci_io_top -= space; - pm->pci_addrs[j] = pci_io_top; - pm->pci_command |= PCI_COMMAND_IO; - } - } - else { - if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) - continue; - - /* Memory space. Test if below 1M. - */ - if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { - if (pci_mem_low < space) { - puts("Out of PCI 1M space\n"); - } - else { - pci_mem_low -= space; - pm->pci_addrs[j] = pci_mem_low; - } - } - else { - if (pci_mem_top < space) { - puts("Out of PCI Mem space\n"); - } - else { - pci_mem_top -= space; - pm->pci_addrs[j] = pci_mem_top; - } - } - pm->pci_command |= PCI_COMMAND_MEMORY; - } - } - } - addr_mask >>= 1; - addr_mask |= 0x80000000; - } while (addr_mask != 0xfffffffe); - - /* Now, run the list one more time and map everything. - */ - for (i=0; ipci_bus, pm->pci_devfn, - PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); - } - - /* Enable memory or address mapping. - */ - qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, - pm->pci_command); - } -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/qspan_pci.c linux/arch/ppc/mbxboot/qspan_pci.c --- v2.4.4/linux/arch/ppc/mbxboot/qspan_pci.c Tue May 2 13:05:40 2000 +++ linux/arch/ppc/mbxboot/qspan_pci.c Wed Dec 31 16:00:00 1969 @@ -1,268 +0,0 @@ -/* - * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) - * - * QSpan Motorola bus to PCI bridge. The config address register - * is located 0x500 from the base of the bridge control/status registers. - * The data register is located at 0x504. - * This is a two step operation. First, the address register is written, - * then the data register is read/written as required. - * I don't know what to do about interrupts (yet). - */ - -#include -#include -#include -#include - -/* - * When reading the configuration space, if something does not respond - * the bus times out and we get a machine check interrupt. So, the - * good ol' exception tables come to mind to trap it and return some - * value. - * - * On an error we just return a -1, since that is what the caller wants - * returned if nothing is present. I copied this from __get_user_asm, - * with the only difference of returning -1 instead of EFAULT. - * There is an associated hack in the machine check trap code. - * - * The QSPAN is also a big endian device, that is it makes the PCI - * look big endian to us. This presents a problem for the Linux PCI - * functions, which assume little endian. For example, we see the - * first 32-bit word like this: - * ------------------------ - * | Device ID | Vendor ID | - * ------------------------ - * If we read/write as a double word, that's OK. But in our world, - * when read as a word, device ID is at location 0, not location 2 as - * the little endian PCI would believe. We have to switch bits in - * the PCI addresses given to us to get the data to/from the correct - * byte lanes. - * - * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. - * It always forces the MS bit to zero. Therefore, dev_fn values - * greater than 128 are returned as "no device found" errors. - * - * The QSPAN can only perform long word (32-bit) configuration cycles. - * The "offset" must have the two LS bits set to zero. Read operations - * require we read the entire word and then sort out what should be - * returned. Write operations other than long word require that we - * read the long word, update the proper word or byte, then write the - * entire long word back. - * - * PCI Bridge hack. We assume (correctly) that bus 0 is the primary - * PCI bus from the QSPAN. If we are called with a bus number other - * than zero, we create a Type 1 configuration access that a downstream - * PCI bridge will interpret. - */ - -#define __get_pci_config(x, addr, op) \ - __asm__ __volatile__( \ - "1: "op" %0,0(%1)\n" \ - " eieio\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: li %0,-1\n" \ - " b 2b\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".text" \ - : "=r"(x) : "r"(addr)) - -#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) -#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) - -#define mk_config_addr(bus, dev, offset) \ - (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) - -#define mk_config_type1(bus, dev, offset) \ - mk_config_addr(bus, dev, offset) | 1; - -/* Initialize the QSpan device registers after power up. -*/ -qspan_init() -{ - uint *qptr; - - - - qptr = (uint *)PCI_CSR_ADDR; - - /* PCI Configuration/status. Upper bits written to clear - * pending interrupt or status. Lower bits enable QSPAN as - * PCI master, enable memory and I/O cycles, and enable PCI - * parity error checking. - * IMPORTANT: The last two bits of this word enable PCI - * master cycles into the QBus. The QSpan is broken and can't - * meet the timing specs of the PQ bus for this to work. Therefore, - * if you don't have external bus arbitration, you can't use - * this function. - */ -#ifdef EXTERNAL_PQ_ARB - qptr[1] = 0xf9000147; -#else - qptr[1] = 0xf9000144; -#endif - - /* PCI Misc configuration. Set PCI latency timer resolution - * of 8 cycles, set cache size to 4 x 32. - */ - qptr[3] = 0; - - /* Set up PCI Target address mapping. Enable, Posted writes, - * 2Gbyte space (processor memory controller determines actual size). - */ - qptr[64] = 0x8f000080; - - /* Map processor 0x80000000 to PCI 0x00000000. - * Processor address bit 1 determines I/O type access (0x80000000) - * or memory type access (0xc0000000). - */ - qptr[65] = 0x80000000; - - /* Enable error logging and clear any pending error status. - */ - qptr[80] = 0x90000000; - - qptr[512] = 0x000c0003; - - /* Set up Qbus slave image. - */ - qptr[960] = 0x01000000; - qptr[961] = 0x000000d1; - qptr[964] = 0x00000000; - qptr[965] = 0x000000d1; - -} - -/* Functions to support PCI bios-like features to read/write configuration - * space. If the function fails for any reason, a -1 (0xffffffff) value - * must be returned. - */ -#define DEVICE_NOT_FOUND (-1) -#define SUCCESSFUL 0 - -int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *val = *cp; - return SUCCESSFUL; -} - -int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - offset ^= 0x02; - - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *val = *sp; - return SUCCESSFUL; -} - -int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) -{ - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffffffff; - return DEVICE_NOT_FOUND; - } - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); - return SUCCESSFUL; -} - -int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *cp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x02; - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *sp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) -{ - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *(unsigned int *)QS_CONFIG_DATA = val; - - return SUCCESSFUL; -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/rdimage.c linux/arch/ppc/mbxboot/rdimage.c --- v2.4.4/linux/arch/ppc/mbxboot/rdimage.c Mon May 15 14:53:30 2000 +++ linux/arch/ppc/mbxboot/rdimage.c Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * rdimage.c - * - * Dummy file to allow a compressed initrd to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_rdimage; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mbxboot/size linux/arch/ppc/mbxboot/size --- v2.4.4/linux/arch/ppc/mbxboot/size Fri Mar 19 10:50:03 1999 +++ linux/arch/ppc/mbxboot/size Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -#!/bin/bash - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` -echo "0x"$OFFSET diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/4xx_tlb.c linux/arch/ppc/mm/4xx_tlb.c --- v2.4.4/linux/arch/ppc/mm/4xx_tlb.c Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/mm/4xx_tlb.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.4xx_tlb.c 1.5 05/17/01 18:14:23 cort + */ +/* * * Copyright (c) 1998-1999 TiVo, Inc. * Original implementation. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/4xx_tlb.h linux/arch/ppc/mm/4xx_tlb.h --- v2.4.4/linux/arch/ppc/mm/4xx_tlb.h Mon Jan 10 18:25:32 2000 +++ linux/arch/ppc/mm/4xx_tlb.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.4xx_tlb.h 1.5 05/17/01 18:14:23 cort + */ +/* * * Copyright (c) 1999 Grant Erickson * diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/Makefile linux/arch/ppc/mm/Makefile --- v2.4.4/linux/arch/ppc/mm/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/mm/Makefile Mon May 21 17:04:47 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:23 cort +# # # Makefile for the linux ppc-specific parts of the memory manager. # diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c --- v2.4.4/linux/arch/ppc/mm/extable.c Tue Sep 19 08:31:53 2000 +++ linux/arch/ppc/mm/extable.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort + */ +/* * linux/arch/ppc/mm/extable.c * * from linux/arch/i386/mm/extable.c diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.4.4/linux/arch/ppc/mm/fault.c Mon Mar 19 12:35:09 2001 +++ linux/arch/ppc/mm/fault.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.fault.c 1.10 05/17/01 18:14:23 cort + */ +/* * arch/ppc/mm/fault.c * * PowerPC version diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.4.4/linux/arch/ppc/mm/init.c Mon Mar 26 15:29:44 2001 +++ linux/arch/ppc/mm/init.c Mon May 21 17:04:47 2001 @@ -1,6 +1,7 @@ /* - * $Id: init.c,v 1.195 1999/10/15 16:39:39 cort Exp $ - * + * BK Id: SCCS/s.init.c 1.22 05/17/01 18:14:23 cort + */ +/* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * @@ -46,7 +47,6 @@ #include #include #include -#include #include #ifdef CONFIG_8xx #include @@ -61,6 +61,7 @@ #include #include #include +#include #include "mem_pieces.h" @@ -93,7 +94,6 @@ extern char __pmac_begin, __pmac_end; extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; -struct device_node *memory_node; unsigned long ioremap_base; unsigned long ioremap_bot; unsigned long avail_start; @@ -111,19 +111,6 @@ void MMU_init(void); void *early_get_page(void); -unsigned long prep_find_end_of_memory(void); -unsigned long pmac_find_end_of_memory(void); -unsigned long apus_find_end_of_memory(void); -extern unsigned long find_end_of_memory(void); -#ifdef CONFIG_8xx -unsigned long m8xx_find_end_of_memory(void); -#endif /* CONFIG_8xx */ -#ifdef CONFIG_4xx -unsigned long oak_find_end_of_memory(void); -#endif -#ifdef CONFIG_8260 -unsigned long m8260_find_end_of_memory(void); -#endif /* CONFIG_8260 */ static void mapin_ram(void); int map_page(unsigned long va, unsigned long pa, int flags); void set_phys_avail(unsigned long total_ram); @@ -436,11 +423,9 @@ * Should check if it is a candidate for a BAT mapping */ - spin_lock(&init_mm.page_table_lock); err = 0; for (i = 0; i < size && err == 0; i += PAGE_SIZE) err = map_page(v+i, p+i, flags); - spin_unlock(&init_mm.page_table_lock); if (err) { if (mem_init_done) vfree((void *)v); @@ -487,17 +472,21 @@ { pmd_t *pd; pte_t *pg; + int err = -ENOMEM; + spin_lock(&init_mm.page_table_lock); /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); /* Use middle 10 bits of VA to index the second-level map */ pg = pte_alloc(&init_mm, pd, va); - if (pg == 0) - return -ENOMEM; - set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); - if (mem_init_done) - flush_hash_page(0, va); - return 0; + if (pg != 0) { + err = 0; + set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); + if (mem_init_done) + flush_hash_page(0, va); + } + spin_unlock(&init_mm.page_table_lock); + return err; } #ifndef CONFIG_8xx @@ -668,33 +657,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -static void get_mem_prop(char *, struct mem_pieces *); - -#if defined(CONFIG_ALL_PPC) -/* - * Read in a property describing some pieces of memory. - */ - -static void __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int s; - - rp = (struct reg_property *) get_property(memory_node, name, &s); - if (rp == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - abort(); - } - mp->n_regions = s / sizeof(mp->regions[0]); - memcpy(mp->regions, rp, s); - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); -} -#endif /* CONFIG_ALL_PPC */ - /* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power @@ -877,14 +839,13 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif @@ -904,27 +865,28 @@ /* * The Zone Protection Register (ZPR) defines how protection will * be applied to every page which is a member of a given zone. At - * present, we utilize only two of the 4xx's zones. The first, zone - * 0, is set at '00b and only allows access in supervisor-mode based - * on the EX and WR bits. No user-mode access is allowed. The second, - * zone 1, is set at '10b and in supervisor-mode allows access - * without regard to the EX and WR bits. In user-mode, access is - * allowed based on the EX and WR bits. + * present, we utilize only two of the 4xx's zones. + * The zone index bits (of ZSEL) in the PTE are used for software + * indicators, except the LSB. For user access, zone 15 is used, + * for kernel access, zone 14 is used. We set all but zone 15 + * to zero, allowing only kernel access as indicated in the PTE. + * For zone 15, we set a 10 binary (I guess a 01 would work too) + * to allow user access as indicated in the PTE. This also allows + * kernel access as indicated in the PTE. */ - mtspr(SPRN_ZPR, 0x2aaaaaaa); - - /* Hardwire any TLB entries necessary here. */ + mtspr(SPRN_ZPR, 0x00000002); - PPC4xx_tlb_pin(KERNELBASE, 0, TLB_PAGESZ(PAGESZ_16M), 1); + flush_instruction_cache(); /* * Find the top of physical memory and map all of it in starting * at KERNELBASE. */ - total_memory = total_lowmem = oak_find_end_of_memory(); - end_of_DRAM = __va(total_memory); + total_memory = total_lowmem = ppc_md.find_end_of_memory(); + end_of_DRAM = __va(total_lowmem); + set_phys_avail(total_lowmem); mapin_ram(); /* @@ -943,70 +905,13 @@ mtspr(SPRN_ICCR, 0x80000000); /* 128 MB of instr. space at 0x0. */ } -#elif defined(CONFIG_8xx) +#else /* !CONFIG_4xx */ void __init MMU_init(void) { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); - total_memory = total_lowmem = m8xx_find_end_of_memory(); -#ifdef CONFIG_HIGHMEM - if (total_lowmem > MAX_LOW_MEM) { - total_lowmem = MAX_LOW_MEM; - mem_pieces_remove(&phys_avail, total_lowmem, - total_memory - total_lowmem, 0); - } -#endif /* CONFIG_HIGHMEM */ - end_of_DRAM = __va(total_lowmem); - set_phys_avail(total_lowmem); - - /* Map in all of RAM starting at KERNELBASE */ - mapin_ram(); - - /* Now map in some of the I/O space that is generically needed - * or shared with multiple devices. - * All of this fits into the same 4Mbyte region, so it only - * requires one page table page. - */ - ioremap(IMAP_ADDR, IMAP_SIZE); -#ifdef CONFIG_MBX - ioremap(NVRAM_ADDR, NVRAM_SIZE); - ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); - ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); - - /* Map some of the PCI/ISA I/O space to get the IDE interface. - */ - ioremap(PCI_ISA_IO_ADDR, 0x4000); - ioremap(PCI_IDE_ADDR, 0x4000); -#endif -#ifdef CONFIG_RPXLITE - ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); - ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE); -#endif -#ifdef CONFIG_RPXCLASSIC - ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); - ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); -#endif - if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); -} - -#else /* not 4xx or 8xx */ -void __init MMU_init(void) -{ - if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); + total_memory = ppc_md.find_end_of_memory(); - if (have_of) - total_memory = pmac_find_end_of_memory(); -#ifdef CONFIG_APUS - else if (_machine == _MACH_apus ) - total_memory = apus_find_end_of_memory(); -#endif -#if defined(CONFIG_8260) - else - total_memory = m8260_find_end_of_memory(); -#else - else /* prep */ - total_memory = prep_find_end_of_memory(); -#endif if (__max_memory && total_memory > __max_memory) total_memory = __max_memory; total_lowmem = total_memory; @@ -1019,6 +924,7 @@ end_of_DRAM = __va(total_lowmem); set_phys_avail(total_lowmem); +#if !defined(CONFIG_8xx) if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -1026,16 +932,49 @@ #endif ioremap_base = 0xf8000000; +#endif /* CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); -#ifdef CONFIG_POWER4 +#if defined(CONFIG_POWER4) ioremap_base = ioremap_bot = 0xfffff000; isa_io_base = (unsigned long) ioremap(0xffd00000, 0x200000) + 0x100000; -#else /* CONFIG_POWER4 */ +#elif defined(CONFIG_8xx) + /* Now map in some of the I/O space that is generically needed + * or shared with multiple devices. + * All of this fits into the same 4Mbyte region, so it only + * requires one page table page. + */ + ioremap(IMAP_ADDR, IMAP_SIZE); +#ifdef CONFIG_MBX + ioremap(NVRAM_ADDR, NVRAM_SIZE); + ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); + ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); + + /* Map some of the PCI/ISA I/O space to get the IDE interface. + */ + ioremap(PCI_ISA_IO_ADDR, 0x4000); + ioremap(PCI_IDE_ADDR, 0x4000); +#endif +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); +#if !defined(CONFIG_PCI) + ioremap(_IO_BASE,_IO_BASE_SIZE); +#endif +#endif +#ifdef CONFIG_HTDMSOUND + ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE); +#endif +#ifdef CONFIG_FADS + ioremap(BCSR_ADDR, BCSR_SIZE); +#endif +#ifdef CONFIG_PCI + ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); +#endif +#else /* !CONFIG_POWER4 && !CONFIG_8xx */ /* * Setup the bat mappings we're going to load that cover * the io areas. RAM was mapped by mapin_ram(). @@ -1069,6 +1008,10 @@ /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; case _MACH_8260: /* Map the IMMR, plus anything else we can cover * in that upper space according to the memory controller @@ -1081,7 +1024,7 @@ break; } ioremap_bot = ioremap_base; -#endif /* CONFIG_POWER4 */ +#endif /* CONFIG_POWER4 || CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT @@ -1257,155 +1200,6 @@ } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_ALL_PPC) -/* - * On systems with Open Firmware, collect information about - * physical RAM and which pieces are already in use. - * At this point, we have (at least) the first 8MB mapped with a BAT. - * Our text, data, bss use something over 1MB, starting at 0. - * Open Firmware may be using 1MB at the 4MB point. - */ -unsigned long __init pmac_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} -#endif /* CONFIG_ALL_PPC */ - -#if defined(CONFIG_ALL_PPC) -/* - * This finds the amount of physical ram and does necessary - * setup for prep. This is pretty architecture specific so - * this will likely stay separate from the pmac. - * -- Cort - */ -unsigned long __init prep_find_end_of_memory(void) -{ - unsigned long total; -#ifdef CONFIG_PREP_RESIDUAL - total = res->TotalMemory; -#else - total = 0; -#endif - - if (total == 0 ) - { - /* - * I need a way to probe the amount of memory if the residual - * data doesn't contain it. -- Cort - */ - printk("Ramsize from residual data was 0 -- Probing for value\n"); - total = 0x02000000; - printk("Ramsize default to be %ldM\n", total>>20); - } - - return (total); -} -#endif /* defined(CONFIG_ALL_PPC) */ - -#ifdef CONFIG_8260 -/* - * Same hack as 8xx. - */ -unsigned long __init m8260_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} -#endif /* CONFIG_8260 */ - -#ifdef CONFIG_APUS -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - ram_phys_base = memory[0].addr; - return total; -} -#endif /* CONFIG_APUS */ - /* * Initialize the hash table and patch the instructions in head.S. */ @@ -1514,43 +1308,7 @@ } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } -#elif defined(CONFIG_8xx) -/* - * This is a big hack right now, but it may turn into something real - * someday. - * - * For the 8xx boards (at this time anyway), there is nothing to initialize - * associated the PROM. Rather than include all of the prom.c - * functions in the image just to get prom_init, all we really need right - * now is the initialization of the physical memory region. - */ -unsigned long __init m8xx_find_end_of_memory(void) -{ - bd_t *binfo; - extern unsigned char __res[]; - - binfo = (bd_t *)__res; - - return binfo->bi_memsize; -} #endif /* !CONFIG_4xx && !CONFIG_8xx */ - -#ifdef CONFIG_OAK -/* - * Return the virtual address representing the top of physical RAM - * on the Oak board. - */ -unsigned long __init -oak_find_end_of_memory(void) -{ - extern unsigned char __res[]; - - unsigned long *ret; - bd_t *bip = (bd_t *)__res; - - return bip->bi_memsize; -} -#endif /* * Set phys_avail to the amount of physical memory, diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/mem_pieces.c linux/arch/ppc/mm/mem_pieces.c --- v2.4.4/linux/arch/ppc/mm/mem_pieces.c Mon Jun 19 17:59:37 2000 +++ linux/arch/ppc/mm/mem_pieces.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.mem_pieces.c 1.5 05/17/01 18:14:23 cort + */ +/* * Copyright (c) 1996 Paul Mackerras * Changes to accomodate Power Macintoshes. * Cort Dougan diff -u --recursive --new-file v2.4.4/linux/arch/ppc/mm/mem_pieces.h linux/arch/ppc/mm/mem_pieces.h --- v2.4.4/linux/arch/ppc/mm/mem_pieces.h Mon Jun 19 17:59:37 2000 +++ linux/arch/ppc/mm/mem_pieces.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort + */ +/* * Copyright (c) 1996 Paul Mackerras * Changes to accomodate Power Macintoshes. * Cort Dougan diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/Makefile linux/arch/ppc/treeboot/Makefile --- v2.4.4/linux/arch/ppc/treeboot/Makefile Wed Mar 8 09:18:02 2000 +++ linux/arch/ppc/treeboot/Makefile Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -# -# Copyright (c) 1999 Grant Erickson -# -# Module name: Makefile -# -# Description: -# Makefile for the IBM "tree" evaluation board Linux kernel -# boot loaders. -# - -HOSTCFLAGS = -O -I$(TOPDIR)/include - -GZIP = gzip -vf9 -RM = rm -f -MKEVIMG = mkevimg -l -MKIRIMG = mkirimg - -CFLAGS = -O -fno-builtin -I$(TOPDIR)/include -LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic - -OBJS = crt0.o main.o misc.o irSect.o ../coffboot/string.o ../coffboot/zlib.o -LIBS = - -treeboot: $(OBJS) ld.script - $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) - -zImage: vmlinux.img - -zImage.initrd: vmlinux.initrd.img - -treeboot.image: treeboot vmlinux.gz - $(OBJCOPY) --add-section=image=vmlinux.gz treeboot $@ - -treeboot.initrd: treeboot.image ramdisk.image.gz - $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ - -vmlinux.img: treeboot.image - $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt - $(MKEVIMG) treeboot.image.out $@ - $(RM) treeboot.image treeboot.image.out irSectStart.txt - -vmlinux.initrd.img: treeboot.initrd - $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt - $(MKEVIMG) treeboot.initrd.out $@ - $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt - -vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux - $(GZIP) vmlinux - -clean: - rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* *.o - -fastdep: - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/crt0.S linux/arch/ppc/treeboot/crt0.S --- v2.4.4/linux/arch/ppc/treeboot/crt0.S Mon Jan 10 18:25:32 2000 +++ linux/arch/ppc/treeboot/crt0.S Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1997 Paul Mackerras - * Initial Power Macintosh COFF version. - * Copyright (c) 1999 Grant Erickson - * Modifications for IBM PowerPC 400-class processor evaluation - * boards. - * - * Module name: crt0.S - * - * Description: - * Boot loader execution entry point. Clears out .bss section as per - * ANSI C requirements. Invalidates and flushes the caches over the - * range covered by the boot loader's .text section. Sets up a stack - * below the .text section entry point. - * - * 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. - * - */ - -#include "../kernel/ppc_asm.tmpl" - - .text - - .globl _start -_start: - ## Clear out the BSS as per ANSI C requirements - - lis r7,_end@ha # - addi r7,r7,_end@l # r7 = &_end - lis r8,__bss_start@ha # - addi r8,r8,__bss_start@l # r8 = &_bss_start - - ## Determine how large an area, in number of words, to clear - - subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 - addi r7,r7,3 # r7 += 3 - srwi. r7,r7,2 # r7 = size in words. - beq 2f # If the size is zero, do not bother - addi r8,r8,-4 # r8 -= 4 - mtctr r7 # SPRN_CTR = number of words to clear - li r0,0 # r0 = 0 -1: stwu r0,4(r8) # Clear out a word - bdnz 1b # If we are not done yet, keep clearing - - ## Flush and invalidate the caches for the range in memory covering - ## the .text section of the boot loader - -2: lis r9,_start@h # r9 = &_start - lis r8,_etext@ha # - addi r8,r8,_etext@l # r8 = &_etext -3: dcbf r0,r9 # Flush the data cache - icbi r0,r9 # Invalidate the instruction cache - addi r9,r9,0x10 # Increment by one cache line - cmplwi cr0,r9,r8 # Are we at the end yet? - blt 3b # No, keep flushing and invalidating - - ## Set up the stack - - lis r9,_start@h # r9 = &_start (text section entry) - addi r9,r9,_start@l - subi r1,r9,64 # Start the stack 64 bytes below _start - clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. - li r0,0 - stwu r0,-16(r1) - mtlr r9 - - b start # All done, start the real work. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/elf.pl linux/arch/ppc/treeboot/elf.pl --- v2.4.4/linux/arch/ppc/treeboot/elf.pl Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/treeboot/elf.pl Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -# -# ELF header field numbers -# - -$e_ident = 0; # Identification bytes / magic number -$e_type = 1; # ELF file type -$e_machine = 2; # Target machine type -$e_version = 3; # File version -$e_entry = 4; # Start address -$e_phoff = 5; # Program header file offset -$e_shoff = 6; # Section header file offset -$e_flags = 7; # File flags -$e_ehsize = 8; # Size of ELF header -$e_phentsize = 9; # Size of program header -$e_phnum = 10; # Number of program header entries -$e_shentsize = 11; # Size of section header -$e_shnum = 12; # Number of section header entries -$e_shstrndx = 13; # Section header table string index - -# -# Section header field numbers -# - -$sh_name = 0; # Section name -$sh_type = 1; # Section header type -$sh_flags = 2; # Section header flags -$sh_addr = 3; # Virtual address -$sh_offset = 4; # File offset -$sh_size = 5; # Section size -$sh_link = 6; # Miscellaneous info -$sh_info = 7; # More miscellaneous info -$sh_addralign = 8; # Memory alignment -$sh_entsize = 9; # Entry size if this is a table diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/irSect.c linux/arch/ppc/treeboot/irSect.c --- v2.4.4/linux/arch/ppc/treeboot/irSect.c Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/treeboot/irSect.c Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.c - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#include "irSect.h" - - -/* - * The order of globals below must not change. If more globals are added, - * you must change the script 'mkirimg' accordingly. - * - */ - -/* - * irSectStart must be at beginning of file - */ -unsigned int irSectStart = 0xdeadbeaf; - -unsigned int imageSect_start = 0; -unsigned int imageSect_size = 0; -unsigned int initrdSect_start = 0; -unsigned int initrdSect_size = 0; - -/* - * irSectEnd must be at end of file - */ -unsigned int irSectEnd = 0xdeadbeaf; diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/irSect.h linux/arch/ppc/treeboot/irSect.h --- v2.4.4/linux/arch/ppc/treeboot/irSect.h Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/treeboot/irSect.h Wed Dec 31 16:00:00 1969 @@ -1,32 +0,0 @@ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.h - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#ifndef __IRSECT_H__ -#define __IRSECT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned int imageSect_start; -extern unsigned int imageSect_size; - -extern unsigned int initrdSect_start; -extern unsigned int initrdSect_size; - - -#ifdef __cplusplus -} -#endif - -#endif /* __IRSECT_H__ */ diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/ld.script linux/arch/ppc/treeboot/ld.script --- v2.4.4/linux/arch/ppc/treeboot/ld.script Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/treeboot/ld.script Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0 - .plt : { *(.plt) } - .text : - { - *(.text) - *(.rodata) - *(.rodata1) - *(.got1) - } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - _etext = .; - PROVIDE (etext = .); - /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/main.c linux/arch/ppc/treeboot/main.c --- v2.4.4/linux/arch/ppc/treeboot/main.c Mon Jan 10 18:25:32 2000 +++ linux/arch/ppc/treeboot/main.c Wed Dec 31 16:00:00 1969 @@ -1,240 +0,0 @@ -/* - * Copyright (c) 1997 Paul Mackerras - * Initial Power Macintosh COFF version. - * Copyright (c) 1999 Grant Erickson - * Modifications for an ELF-based IBM evaluation board version. - * - * Module name: main.c - * - * Description: - * This module does most of the real work for the boot loader. It - * checks the variables holding the absolute start address and size - * of the Linux kernel "image" and initial RAM disk "initrd" sections - * and if they are present, moves them to their "proper" locations. - * - * For the Linux kernel, "proper" is physical address 0x00000000. - * For the RAM disk, "proper" is the image's size below the top - * of physical memory. The Linux kernel may be in either raw - * binary form or compressed with GNU zip (aka gzip). - * - * 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. - * - */ - -#include - -#include "../coffboot/nonstdio.h" -#include "../coffboot/zlib.h" -#include "irSect.h" - - -/* Preprocessor Defines */ - -/* - * Location of the IBM boot ROM function pointer address for retrieving - * the board information structure. - */ - -#define BOARD_INFO_VECTOR 0xFFFE0B50 - -#define RAM_SIZE (4 * 1024 * 1024) - -#define RAM_PBASE 0x00000000 -#define RAM_PEND (RAM_PBASE + RAM_SIZE) - -#define RAM_VBASE 0xC0000000 -#define RAM_VEND (RAM_VBASE + RAM_SIZE) - -#define RAM_START RAM_PBASE -#define RAM_END RAM_PEND -#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) - -#define PROG_START RAM_START - - -/* Function Macros */ - -#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) - - -/* Global Variables */ - -/* Needed by zalloc and zfree for allocating memory */ - -char *avail_ram; /* Indicates start of RAM available for heap */ -char *end_avail; /* Indicates end of RAM available for heap */ - -bd_t board_info; - -/* - * XXX - Until either the IBM boot ROM provides a way of passing arguments to - * the program it launches or until I/O is working in the boot loader, - * this is a good spot to pass in command line arguments to the kernel - * (e.g. console=tty0). - */ - -static char *cmdline = ""; - - -/* Function Prototypes */ - -void *zalloc(void *x, unsigned items, unsigned size); -void zfree(void *x, void *addr, unsigned nb); - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); - -void printf () {} -void pause () {} -void exit () {} - - -void start(void) -{ - void *options; - int ns, oh, i; - unsigned long sa, len; - void *dst; - unsigned char *im; - unsigned long initrd_start, initrd_size; - bd_t *(*get_board_info)(void) = - (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); - bd_t *bip = NULL; - - if ((bip = get_board_info()) != NULL) - memcpy(&board_info, bip, sizeof(bd_t)); - - /* setup_bats(RAM_START); */ - - /* Init RAM disk (initrd) section */ - - if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - - printf("Initial RAM disk at 0x%08x (%u bytes)\n", - initrd_start, initrd_size); - - memcpy((char *)initrd_start, - (char *)(initrdSect_start), - initrdSect_size); - - end_avail = (char *)initrd_start; - } else { - initrd_start = initrd_size = 0; - end_avail = (char *)RAM_END; - } - - /* Linux kernel image section */ - - im = (unsigned char *)(imageSect_start); - len = imageSect_size; - dst = (void *)PROG_START; - - /* Check for the gzip archive magic numbers */ - - if (im[0] == 0x1f && im[1] == 0x8b) { - - /* The gunzip routine needs everything nice and aligned */ - - void *cp = (void *)ALIGN_UP(RAM_FREE, 8); - avail_ram = (void *)(cp + ALIGN_UP(len, 8)); - memcpy(cp, im, len); - - /* I'm not sure what the 0x200000 parameter is for, but it works. */ - - gunzip(dst, 0x200000, cp, (int *)&len); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - - sa = (unsigned long)dst; - - (*(void (*)())sa)(&board_info, - initrd_start, - initrd_start + initrd_size, - cmdline, - cmdline + strlen(cmdline)); - - pause(); -} - -void *zalloc(void *x, unsigned items, unsigned size) -{ - void *p = avail_ram; - - size *= items; - size = ALIGN_UP(size, 8); - avail_ram += size; - if (avail_ram > end_avail) { - printf("oops... out of memory\n"); - pause(); - } - return p; -} - -void zfree(void *x, void *addr, unsigned nb) -{ - -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -#define DEFLATED 8 - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n"); - exit(); - } - printf("done 1\n"); - s.zalloc = zalloc; - s.zfree = zfree; - r = inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("inflateInit2 returned %d\n", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - printf("doing inflate\n"); - r = inflate(&s, Z_FINISH); - printf("done inflate\n"); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d\n", r); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - printf("doing end\n"); - inflateEnd(&s); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/misc.S linux/arch/ppc/treeboot/misc.S --- v2.4.4/linux/arch/ppc/treeboot/misc.S Mon Jan 10 18:25:05 2000 +++ linux/arch/ppc/treeboot/misc.S Wed Dec 31 16:00:00 1969 @@ -1,40 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - -#include "../kernel/ppc_asm.tmpl" - - .text - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - mfpvr r5 # Get processor version register - extrwi r5,r5,16,0 # Get the version bits - cmpwi cr0,r5,0x0020 # Is this a 403-based processor? - beq 1f # Yes, it is - li r5,32 # It is not a 403, set to 32 bytes - addi r4,r4,32-1 # len += line_size - 1 - srwi. r4,r4,5 # Convert from bytes to lines - b 2f -1: li r5,16 # It is a 403, set to 16 bytes - addi r4,r4,16-1 # len += line_size - 1 - srwi. r4,r4,4 # Convert from bytes to lines -2: mtctr r4 # Set-up the counter register - beqlr # If it is 0, we are done -3: dcbf r0,r3 # Flush and invalidate the data line - icbi r0,r3 # Invalidate the instruction line - add r3,r3,r5 # Move to the next line - bdnz 3b # Are we done yet? - sync - isync - blr # Return to the caller diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/mkevimg linux/arch/ppc/treeboot/mkevimg --- v2.4.4/linux/arch/ppc/treeboot/mkevimg Sat Mar 3 10:52:14 2001 +++ linux/arch/ppc/treeboot/mkevimg Wed Dec 31 16:00:00 1969 @@ -1,437 +0,0 @@ -#!/usr/bin/perl - -# -# Copyright (c) 1998-1999 TiVo, Inc. -# All rights reserved. -# -# Copyright (c) 1999 Grant Erickson -# Major syntactic and usability rework. -# -# Module name: mkevimg -# -# Description: -# Converts an ELF output file from the linker into the format used by -# the IBM evaluation board ROM Monitor to load programs from a host -# onto the evaluation board. The ELF file must be an otherwise execut- -# able file (with the text and data addresses bound at link time) and -# have space reserved after the entry point for the load information -# block: -# -# typedef struct boot_block { -# unsigned long magic; 0x0052504F -# unsigned long dest; Target address of the image -# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks -# unsigned long debug_flag; Run the debugger or image after load -# unsigned long entry_point; The image address to jump to after load -# unsigned long reserved[3]; -# } boot_block_t; -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hlvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -h Print out this message and exit.\n"); - print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkevimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("hlvV")) { - usage(1); - } - - if ($opt_h) { - usage(0); - } - - if ($opt_l) { - $linux = 1; - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ifile = shift(@ARGV))) { - usage(1); - } - - if (!($ofile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ifile)) { - exit(1); - } - -} - -# -# ELF file and section header field numbers -# - -require 'elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - - decode_options(); - - open(ELF, "<$ifile") || die "Cannot open input file"; - - $ifilesize = (-s $ifile); - - if ($verbose) { - print("Output file: $ofile\n"); - print("Input file: $ifile, $ifilesize bytes.\n"); - } - - if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { - print("Failed to read input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ifile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); - exit (1); - } - - if ($verbose) { - print("File header:\n"); - printf(" Identifier: %s\n", $eh[$e_ident]); - printf(" Type: %d\n", $eh[$e_type]); - printf(" Machine: %d\n", $eh[$e_machine]); - printf(" Version: %d\n", $eh[$e_version]); - printf(" Entry point: 0x%08x\n", $eh[$e_entry]); - printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); - printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); - printf(" Flags: 0x%08x\n", $eh[$e_flags]); - printf(" Header size: %d\n", $eh[$e_ehsize]); - printf(" Program entry size: %d\n", $eh[$e_phentsize]); - printf(" Program table entries: %d\n", $eh[$e_phnum]); - printf(" Section header size: %d\n", $eh[$e_shentsize]); - printf(" Section table entries: %d\n", $eh[$e_shnum]); - printf(" String table section: %d\n", $eh[$e_shstrndx]); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.text' and '.bss' sections in - # particular. - - if ($verbose) { - print("Section headers:\n"); - print("Idx Name Size Address File off Algn\n"); - print("--- ------------------------ -------- -------- -------- ----\n"); - } - - $off = $eh[$e_shoff]; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - if ($verbose) { - printf("%3d %-24s %8x %08x %08x %4d\n", - $i, $name, $sh[$sh_size], $sh[$sh_addr], - $sh[$sh_offset], $sh[$sh_addralign]); - } - - # Attempt to find the .text and .bss sections - - if ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.text$/) { - ($text_addr, $text_offset, $text_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\image$/)) { - $image_found = 1; - - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\initrd$/)) { - $initrd_found = 1; - - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - printf("Text section - Address: 0x%08x, Size: 0x%08x\n", - $text_addr, $text_size); - printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", - $bss_addr, $bss_size); - - if ($linux) { - if ($image_found) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } - - if ($initrd_found) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } - } - - # - # Open output file - # - - open(BOOT, ">$ofile") || die "Cannot open output file"; - - # - # Compute image size - # - - $output_size = $bss_offset - $text_offset + $bss_size; - - if ($linux && $image_found) { - $output_size += $image_size; - } - - if ($linux && $initrd_found) { - $output_size += $initrd_size; - } - - $num_blocks = $output_size / 512 + 1; - - # - # Write IBM PowerPC evaluation board boot_block_t header - # - - $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, - $text_addr, 0, 0, 0); - - $bytes = length($header); - - if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { - die("Could not write boot image header to output file."); - } - - printf("Entry point = 0x%08x\n", $text_addr); - printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", - $output_size, $output_size, $num_blocks); - - # - # Write image starting after ELF and program headers and - # continuing to beginning of bss - # - - $bytes = $bss_offset - $text_offset + $bss_size; - - if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - - # - # If configured, write out the image and initrd sections as well - # - - if ($linux) { - if ($image_found) { - $bytes = $image_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - - if ($initrd_found) { - $bytes = $initrd_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - } - - # - # Pad to a multiple of 512 bytes - # - - $pad_size = 512 - (length($header) + $output_size) % 512; - - if ($verbose) { - print("Padding boot image by an additional $pad_size bytes.\n"); - } - - $pad_string = pack(("H8","deadbeef") x 128); - - syswrite(BOOT, $pad_string, $pad_size) or - die "Could not pad boot image in output file.\n"; - - # - # Clean-up and leave - # - - close(BOOT); - - print("\nBoot image file \"$ofile\" built successfully.\n\n"); - - exit(0); -} diff -u --recursive --new-file v2.4.4/linux/arch/ppc/treeboot/mkirimg linux/arch/ppc/treeboot/mkirimg --- v2.4.4/linux/arch/ppc/treeboot/mkirimg Mon May 15 14:53:30 2000 +++ linux/arch/ppc/treeboot/mkirimg Wed Dec 31 16:00:00 1969 @@ -1,367 +0,0 @@ -#!/usr/bin/perl -# -# Copyright (c) 1998-1999 TiVo, Inc. -# Original ELF parsing code. -# -# Copyright (c) 1999 Grant Erickson -# Original code from 'mkevimg'. -# -# Module name: mkirimg -# -# Description: -# Reads an ELF file and assigns global variables 'imageSect_start', -# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from -# the "image" and "initrd" section header information. It then -# rewrites the input ELF file with assigned globals to an output -# file. -# -# An input file, "irSectStart.txt" has the memory address of -# 'irSectStart'. The irSectStart memory address is used to find -# the global variables in the ".data" section of the ELF file. -# The 'irSectStart' and the above global variables are defined -# in "irSect.c". -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -h Print out this message and exit.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkirimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("hvV")) { - usage(1); - } - - if ($opt_h) { - usage(0); - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ElfFile = shift(@ARGV))) { - usage(1); - } - - if (!($OutputFile = shift(@ARGV))) { - usage (1); - } - - if (!($IrFile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ElfFile)) { - exit(1); - } - - if (file_check($IrFile)) { - exit(1); - } -} - -# -# ELF file and section header field numbers -# - -require 'elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - decode_options(); - - open(ELF, "<$ElfFile") || die "Cannot open input file"; - open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; - open(IR, "$IrFile") || die "Cannot open input file"; - - $ElfFilesize = (-s $ElfFile); - - if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { - print("Failed to read ELF input file!\n"); - exit(1); - } - - if (read(IR, $irbuf, 8) != 8) { - print("Failed to read Ir input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ElfFile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); - exit (1); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.data', 'image', and - # 'initrd' sections in particular. - - $off = $eh[$e_shoff]; - $imageFound = 0; - $initrdFound = 0; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - # Attempt to find the .data, image, and initrd sections - - if ($name =~ /^\image$/) { - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $imageFound = 1; - - } elsif ($name =~ /^\initrd$/) { - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $initrdFound = 1; - - } elsif ($name =~ /^\.data$/) { - ($data_addr, $data_offset, $data_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - if ($verbose) { - printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $data_addr, $data_size, $data_offset); - printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $bss_addr, $bss_size, $bss_offset); - } - - if ($verbose) { - if ($imageFound) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } else { - printf("Image section not found in file: $ElfFile\n"); - } - - if ($initrdFound) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } else { - printf("Initrd section not found in file: $ElfFile\n"); - } - } - - # get file offset of irSectStart - - $irSectStartoffset = hex ($irbuf); - - if ($verbose) { - printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); - } - - # get the offset of global variables - - $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; - - # write modified values to OUTPUT file - - syswrite(OUTPUT, $ibuf, $initialOffset); - - if ($imageFound) { - $testN = pack ("N2", $bss_addr + $bss_size, $image_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"imageSect_start\" to 0x%08x\n", - $bss_addr + $bss_size); - printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); - } else { - syswrite(OUTPUT, $ibuf, 8, $initialOffset); - } - - if ($initrdFound) { - $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", - $bss_addr + $bss_size + $image_size); - printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); - } else { - syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); - } - - syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), - $initialOffset + 16); - - # - # Clean-up and leave - # - - close (ELF); - close (OUTPUT); - close (IR); - - exit (0); -} - diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/Makefile linux/arch/ppc/xmon/Makefile --- v2.4.4/linux/arch/ppc/xmon/Makefile Fri Dec 29 14:07:20 2000 +++ linux/arch/ppc/xmon/Makefile Mon May 21 17:04:47 2001 @@ -1,3 +1,5 @@ +# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:23 cort +# # Makefile for xmon O_TARGET := x.o diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/adb.c linux/arch/ppc/xmon/adb.c --- v2.4.4/linux/arch/ppc/xmon/adb.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/adb.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort + */ +/* * Copyright (C) 1996 Paul Mackerras. */ #include "nonstdio.h" diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/ansidecl.h linux/arch/ppc/xmon/ansidecl.h --- v2.4.4/linux/arch/ppc/xmon/ansidecl.h Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/ansidecl.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort + */ /* ANSI and traditional C compatability macros Copyright 1991, 1992 Free Software Foundation, Inc. This file is part of the GNU C Library. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/nonstdio.h linux/arch/ppc/xmon/nonstdio.h --- v2.4.4/linux/arch/ppc/xmon/nonstdio.h Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/nonstdio.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.nonstdio.h 1.5 05/17/01 18:14:23 cort + */ typedef int FILE; extern FILE *xmon_stdin, *xmon_stdout; #define EOF (-1) diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/ppc-dis.c linux/arch/ppc/xmon/ppc-dis.c --- v2.4.4/linux/arch/ppc/xmon/ppc-dis.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/ppc-dis.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort + */ /* ppc-dis.c -- Disassemble PowerPC instructions Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/ppc-opc.c linux/arch/ppc/xmon/ppc-opc.c --- v2.4.4/linux/arch/ppc/xmon/ppc-opc.c Sat Nov 27 15:41:59 1999 +++ linux/arch/ppc/xmon/ppc-opc.c Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort + */ /* ppc-opc.c -- PowerPC opcode list Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/ppc.h linux/arch/ppc/xmon/ppc.h --- v2.4.4/linux/arch/ppc/xmon/ppc.h Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/ppc.h Mon May 21 17:04:47 2001 @@ -1,3 +1,6 @@ +/* + * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort + */ /* ppc.h -- Header file for PowerPC opcode table Copyright 1994 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/privinst.h linux/arch/ppc/xmon/privinst.h --- v2.4.4/linux/arch/ppc/xmon/privinst.h Wed May 3 01:47:57 2000 +++ linux/arch/ppc/xmon/privinst.h Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort + */ +/* * Copyright (C) 1996 Paul Mackerras. */ #include diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/setjmp.c linux/arch/ppc/xmon/setjmp.c --- v2.4.4/linux/arch/ppc/xmon/setjmp.c Sat May 22 13:03:00 1999 +++ linux/arch/ppc/xmon/setjmp.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort + */ +/* * Copyright (C) 1996 Paul Mackerras. * * NB this file must be compiled with -O2. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.4.4/linux/arch/ppc/xmon/start.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/xmon/start.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.start.c 1.12 05/21/01 21:39:13 paulus + */ +/* * Copyright (C) 1996 Paul Mackerras. */ #include @@ -28,7 +31,7 @@ static int console; static int use_screen; -static int via_modem = 1; +static int via_modem; static int xmon_use_sccb; static struct device_node *macio_node; @@ -61,27 +64,37 @@ struct device_node *np; unsigned long addr; #ifdef CONFIG_BOOTX_TEXT - extern boot_infos_t *disp_bi; + if (!machine_is_compatible("iMac")) { + extern boot_infos_t *disp_bi; - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - for (np = find_devices("keyboard"); np; np = np->next) - if (np->parent && np->parent->type - && strcmp(np->parent->type, "adb") == 0) - break; + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (np = find_devices("keyboard"); np; np = np->next) + if (np->parent && np->parent->type + && strcmp(np->parent->type, "adb") == 0) + break; - /* needs to be hacked if xmon_printk is to be used - from within find_via_pmu() */ + /* needs to be hacked if xmon_printk is to be used + from within find_via_pmu() */ #ifdef CONFIG_ADB_PMU - if (np != NULL && disp_bi && find_via_pmu()) - use_screen = 1; + if (np != NULL && disp_bi && find_via_pmu()) + use_screen = 1; #endif #ifdef CONFIG_ADB_CUDA - if (np != NULL && disp_bi && find_via_cuda()) - use_screen = 1; + if (np != NULL && disp_bi && find_via_cuda()) + use_screen = 1; #endif + } + prom_drawstring("xmon uses "); if (use_screen) - prom_drawstring("xmon uses screen and keyboard\n"); + prom_drawstring("screen and keyboard\n"); + else { + if (via_modem) + prom_drawstring("modem on "); + prom_drawstring(xmon_use_sccb? "printer": "modem"); + prom_drawstring(" port\n"); + } + #endif /* CONFIG_BOOTX_TEXT */ #ifdef CHRP_ESCC @@ -100,6 +113,15 @@ base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); sccc = base + (addr & ~PAGE_MASK); sccd = sccc + 0x10; + } + else if ( _machine & _MACH_gemini ) + { + /* should already be mapped by the kernel boot */ + sccc = (volatile unsigned char *) 0xffeffb0d; + sccd = (volatile unsigned char *) 0xffeffb08; + TXRDY = 0x20; + RXRDY = 1; + console = 1; } else { diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/start_8xx.c linux/arch/ppc/xmon/start_8xx.c --- v2.4.4/linux/arch/ppc/xmon/start_8xx.c Wed May 3 01:47:57 2000 +++ linux/arch/ppc/xmon/start_8xx.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.start_8xx.c 1.7 05/17/01 18:14:23 cort + */ +/* * Copyright (C) 1996 Paul Mackerras. * Copyright (C) 2000 Dan Malek. * Quick hack of Paul's code to make XMON work on 8xx processors. Lots @@ -15,7 +18,7 @@ #include #include #include -#include "commproc.h" +#include "../8xx_io/commproc.h" extern void xmon_printf(const char *fmt, ...); extern int xmon_8xx_write(char *str, int nb); diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/subr_prf.c linux/arch/ppc/xmon/subr_prf.c --- v2.4.4/linux/arch/ppc/xmon/subr_prf.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/xmon/subr_prf.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.subr_prf.c 1.5 05/17/01 18:14:23 cort + */ +/* * Written by Cort Dougan to replace the version originally used * by Paul Mackerras, which came from NetBSD and thus had copyright * conflicts with Linux. diff -u --recursive --new-file v2.4.4/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.4.4/linux/arch/ppc/xmon/xmon.c Mon Jan 22 15:41:15 2001 +++ linux/arch/ppc/xmon/xmon.c Mon May 21 17:04:47 2001 @@ -1,4 +1,7 @@ /* + * BK Id: SCCS/s.xmon.c 1.9 05/17/01 18:14:24 cort + */ +/* * Routines providing a simple monitor for use on the PowerMac. * * Copyright (C) 1996 Paul Mackerras. @@ -208,10 +211,11 @@ xmon_irq(int irq, void *d, struct pt_regs *regs) { unsigned long flags; - save_flags(flags);cli(); + __save_flags(flags); + __cli(); printf("Keyboard interrupt\n"); xmon(regs); - restore_flags(flags); + __restore_flags(flags); } int @@ -657,7 +661,7 @@ unsigned stack[2]; struct pt_regs regs; extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2; - extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; + extern char do_bottom_half_ret, do_signal_ret; extern char ret_from_except; printf("backtrace:\n"); @@ -676,7 +680,6 @@ || stack[1] == (unsigned) &ret_from_except || stack[1] == (unsigned) &ret_from_syscall_1 || stack[1] == (unsigned) &ret_from_syscall_2 - || stack[1] == (unsigned) &lost_irq_ret || stack[1] == (unsigned) &do_bottom_half_ret || stack[1] == (unsigned) &do_signal_ret) { if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs)) diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/hd64465_gpio.c linux/arch/sh/kernel/hd64465_gpio.c --- v2.4.4/linux/arch/sh/kernel/hd64465_gpio.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/hd64465_gpio.c Sun May 20 12:11:38 2001 @@ -6,7 +6,6 @@ * GPIO pin support for HD64465 companion chip. */ -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/io_cat68701.c linux/arch/sh/kernel/io_cat68701.c --- v2.4.4/linux/arch/sh/kernel/io_cat68701.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/io_cat68701.c Sun May 20 12:11:38 2001 @@ -14,6 +14,7 @@ #include #include +#include #include #define SH3_PCMCIA_BUG_WORKAROUND 1 diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/io_dc.c linux/arch/sh/kernel/io_dc.c --- v2.4.4/linux/arch/sh/kernel/io_dc.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/io_dc.c Sun May 20 12:11:38 2001 @@ -3,7 +3,6 @@ * I/O routines for SEGA Dreamcast */ -#include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/io_ec3104.c linux/arch/sh/kernel/io_ec3104.c --- v2.4.4/linux/arch/sh/kernel/io_ec3104.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/io_ec3104.c Sun May 20 12:11:38 2001 @@ -14,8 +14,6 @@ * (prumpf@tux.org). */ - -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/irq_intc2.c linux/arch/sh/kernel/irq_intc2.c --- v2.4.4/linux/arch/sh/kernel/irq_intc2.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/irq_intc2.c Sun May 20 12:11:38 2001 @@ -12,7 +12,6 @@ * Hitachi 7751 and the STM ST40 STB1. */ -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/mach_dc.c linux/arch/sh/kernel/mach_dc.c --- v2.4.4/linux/arch/sh/kernel/mach_dc.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/mach_dc.c Sun May 20 12:11:38 2001 @@ -3,6 +3,7 @@ * SEGA Dreamcast machine vector */ +#include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/rtc.c linux/arch/sh/kernel/rtc.c --- v2.4.4/linux/arch/sh/kernel/rtc.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/rtc.c Thu May 24 15:14:08 2001 @@ -143,7 +143,6 @@ static int set_rtc_time(unsigned long nowtime) { - extern int abs (int); int retval = 0; int real_seconds, real_minutes, cmos_minutes; diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/setup_dc.c linux/arch/sh/kernel/setup_dc.c --- v2.4.4/linux/arch/sh/kernel/setup_dc.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/setup_dc.c Sun May 20 12:11:38 2001 @@ -3,7 +3,6 @@ * SEGA Dreamcast support */ -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/kernel/setup_ec3104.c linux/arch/sh/kernel/setup_ec3104.c --- v2.4.4/linux/arch/sh/kernel/setup_ec3104.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/setup_ec3104.c Sun May 20 12:11:38 2001 @@ -14,7 +14,6 @@ * (prumpf@tux.org). */ -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.4.4/linux/arch/sh/mm/cache.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/mm/cache.c Sun May 20 12:11:38 2001 @@ -6,6 +6,7 @@ * */ +#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.4.4/linux/arch/sparc/config.in Thu Apr 19 08:38:48 2001 +++ linux/arch/sparc/config.in Mon May 21 18:12:09 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.109 2001/04/18 21:06:05 davem Exp $ +# $Id: config.in,v 1.110 2001/05/20 05:14:46 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -162,9 +162,7 @@ dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then - int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 - fi + dep_tristate ' SCSI OnStream SC-x0 tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI diff -u --recursive --new-file v2.4.4/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.4.4/linux/arch/sparc/defconfig Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/defconfig Wed May 16 10:31:27 2001 @@ -148,7 +148,6 @@ # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m -# CONFIG_IPV6_EUI64 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.4.4/linux/arch/sparc/kernel/head.S Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/head.S Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.103 2000/05/09 17:40:13 davem Exp $ +/* $Id: head.S,v 1.104 2001/04/27 07:02:41 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.4.4/linux/arch/sparc/kernel/irq.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/irq.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.111 2001/04/14 21:13:46 davem Exp $ +/* $Id: irq.c,v 1.112 2001/04/27 07:02:42 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.4.4/linux/arch/sparc/kernel/sys_sunos.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/sys_sunos.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.133 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sunos.c,v 1.134 2001/04/27 07:02:42 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v2.4.4/linux/arch/sparc/prom/console.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/prom/console.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.23 2000/08/26 02:38:03 anton Exp $ +/* $Id: console.c,v 1.24 2001/04/27 07:02:42 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.4/linux/arch/sparc64/config.in Thu Apr 19 08:38:48 2001 +++ linux/arch/sparc64/config.in Sun May 20 11:32:07 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.141 2001/04/19 01:52:04 davem Exp $ +# $Id: config.in,v 1.143 2001/05/20 05:14:46 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -146,9 +146,7 @@ dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then - int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 - fi + dep_tristate ' SCSI OnStream SC-x0 tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI @@ -337,6 +335,15 @@ source drivers/input/Config.in source fs/Config.in + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu source drivers/usb/Config.in diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.4/linux/arch/sparc64/defconfig Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/defconfig Thu May 24 15:00:58 2001 @@ -178,7 +178,6 @@ CONFIG_INET_ECN=y # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m -# CONFIG_IPV6_EUI64 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -291,7 +290,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y -CONFIG_ST_EXTRA_DEVS=2 +CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 @@ -311,7 +310,8 @@ CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 @@ -454,6 +454,7 @@ CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_MINIX_FS=m +CONFIG_VXFS_FS=m # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m @@ -547,6 +548,28 @@ # CONFIG_NLS_UTF8 is not set # +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_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=m +# 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_SONICVIBES is not set +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# # USB support # CONFIG_USB=y @@ -561,8 +584,7 @@ # # USB Controllers # -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_UHCI=y CONFIG_USB_OHCI=y # @@ -573,6 +595,7 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m @@ -595,6 +618,7 @@ # CONFIG_USB_IBMCAM=m CONFIG_USB_OV511=m +CONFIG_USB_PWC=m CONFIG_USB_DSBR=m CONFIG_USB_DABUSB=m diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.4.4/linux/arch/sparc64/kernel/Makefile Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc64/kernel/Makefile Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.66 2001/04/03 12:29:38 davem Exp $ +# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -26,7 +26,7 @@ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o -obj-$(CONFIG_PCI) += ebus.o pci_common.o pci_iommu.o \ +obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o obj-$(CONFIG_SMP) += smp.o trampoline.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c --- v2.4.4/linux/arch/sparc64/kernel/devices.c Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/kernel/devices.c Sun May 20 12:11:38 2001 @@ -4,6 +4,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.4/linux/arch/sparc64/kernel/ioctl32.c Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc64/kernel/ioctl32.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.111 2001/03/27 07:28:43 davem Exp $ +/* $Id: ioctl32.c,v 1.115 2001/05/12 06:41:58 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -49,6 +49,7 @@ #include #include #include +#include #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) /* Ugh. This header really is not clean */ #define min min @@ -514,10 +515,19 @@ } } if (!err) { - if (i <= ifc32.ifc_len) + if (ifc32.ifcbuf == 0) { + /* Translate from 64-bit structure multiple to + * a 32-bit one. + */ + i = ifc.ifc_len; + i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); ifc32.ifc_len = i; - else - ifc32.ifc_len = i - sizeof (struct ifreq32); + } else { + if (i <= ifc32.ifc_len) + ifc32.ifc_len = i; + else + ifc32.ifc_len = i - sizeof (struct ifreq32); + } if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) err = -EFAULT; } @@ -3369,11 +3379,6 @@ COMPATIBLE_IOCTL(SIOCSARP) COMPATIBLE_IOCTL(SIOCGARP) COMPATIBLE_IOCTL(SIOCDARP) -#if 0 /* XXX No longer exist in new routing code. XXX */ -COMPATIBLE_IOCTL(OLD_SIOCSARP) -COMPATIBLE_IOCTL(OLD_SIOCGARP) -COMPATIBLE_IOCTL(OLD_SIOCDARP) -#endif COMPATIBLE_IOCTL(SIOCSRARP) COMPATIBLE_IOCTL(SIOCGRARP) COMPATIBLE_IOCTL(SIOCDRARP) @@ -3714,6 +3719,13 @@ COMPATIBLE_IOCTL(WIOCSTART) COMPATIBLE_IOCTL(WIOCSTOP) COMPATIBLE_IOCTL(WIOCGSTAT) +/* Misc. */ +COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ +COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ +COMPATIBLE_IOCTL(PCIIOC_CONTROLLER) +COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO) +COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM) +COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE) /* And these ioctls need translation */ HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) @@ -3991,8 +4003,9 @@ } else { static int count = 0; if (++count <= 20) - printk("sys32_ioctl: Unknown cmd fd(%d) " + printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) " "cmd(%08x) arg(%08x)\n", + current->comm, current->pid, (int)fd, (unsigned int)cmd, (unsigned int)arg); error = -EINVAL; } diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/isa.c linux/arch/sparc64/kernel/isa.c --- v2.4.4/linux/arch/sparc64/kernel/isa.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/isa.c Wed May 16 10:31:27 2001 @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include +#include + +struct isa_bridge *isa_chain; + +static void __init fatal_err(const char *reason) +{ + prom_printf("ISA: fatal error, %s.\n", reason); +} + +static void __init report_dev(struct isa_device *isa_dev, int child) +{ + if (child) + printk(" (%s)", isa_dev->prom_name); + else + printk(" [%s", isa_dev->prom_name); +} + +static void __init isa_dev_get_resource(struct isa_device *isa_dev) +{ + struct linux_prom_registers regs[PROMREG_MAX]; + unsigned long base, len; + int prop_len; + + prop_len = prom_getproperty(isa_dev->prom_node, "reg", + (char *) regs, sizeof(regs)); + + if (prop_len <= 0) + return; + + /* Only the first one is interesting. */ + len = regs[0].reg_size; + base = (((unsigned long)regs[0].which_io << 32) | + (unsigned long)regs[0].phys_addr); + base += isa_dev->bus->parent->io_space.start; + + isa_dev->resource.start = base; + isa_dev->resource.end = (base + len - 1UL); + isa_dev->resource.flags = IORESOURCE_IO; + isa_dev->resource.name = isa_dev->prom_name; + + request_resource(&isa_dev->bus->parent->io_space, + &isa_dev->resource); +} + +/* I can't believe they didn't put a real INO in the isa device + * interrupts property. The whole point of the OBP properties + * is to shield the kernel from IRQ routing details. + * + * The P1275 standard for ISA devices seems to also have been + * totally ignored. + */ +static struct { + int obp_irq; + int pci_ino; +} grover_irq_table[] = { + { 1, 0x00 }, /* dma, unknown ino at this point */ + { 2, 0x27 }, /* floppy */ + { 3, 0x22 }, /* parallel */ + { 4, 0x2b }, /* serial */ + { 5, 0x25 }, /* acpi power management */ + + { 0, 0x00 } /* end of table */ +}; + +static void __init isa_dev_get_irq(struct isa_device *isa_dev) +{ + int irq_prop; + + irq_prop = prom_getintdefault(isa_dev->prom_node, + "interrupts", -1); + if (irq_prop <= 0) { + isa_dev->irq = 0; + } else { + int i; + + for (i = 0; grover_irq_table[i].obp_irq != 0; i++) { + if (grover_irq_table[i].obp_irq == irq_prop) { + struct pci_controller_info *pcic; + struct pci_pbm_info *pbm; + int ino = grover_irq_table[i].pci_ino; + + if (ino == 0) { + isa_dev->irq = 0; + } else { + pbm = isa_dev->bus->parent; + pcic = pbm->parent; + isa_dev->irq = pcic->irq_build(pbm, NULL, ino); + } + } + } + } +} + +static void __init isa_fill_children(struct isa_device *parent_isa_dev) +{ + int node = prom_getchild(parent_isa_dev->prom_node); + + if (node == 0) + return; + + printk(" ->"); + while (node != 0) { + struct isa_device *isa_dev; + int prop_len; + + isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); + if (!isa_dev) { + fatal_err("cannot allocate child isa_dev"); + prom_halt(); + } + + memset(isa_dev, 0, sizeof(*isa_dev)); + + /* Link it in to parent. */ + isa_dev->next = parent_isa_dev->child; + parent_isa_dev->child = isa_dev; + + isa_dev->bus = parent_isa_dev->bus; + isa_dev->prom_node = node; + prop_len = prom_getproperty(node, "name", + (char *) isa_dev->prom_name, + sizeof(isa_dev->prom_name)); + if (prop_len <= 0) { + fatal_err("cannot get child isa_dev OBP node name"); + prom_halt(); + } + + prop_len = prom_getproperty(node, "compatible", + (char *) isa_dev->compatible, + sizeof(isa_dev->compatible)); + + /* Not having this is OK. */ + if (prop_len <= 0) + isa_dev->compatible[0] = '\0'; + + isa_dev_get_resource(isa_dev); + isa_dev_get_irq(isa_dev); + + report_dev(isa_dev, 1); + + node = prom_getsibling(node); + } +} + +static void __init isa_fill_devices(struct isa_bridge *isa_br) +{ + int node = prom_getchild(isa_br->prom_node); + + while (node != 0) { + struct isa_device *isa_dev; + int prop_len; + + isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); + if (!isa_dev) { + fatal_err("cannot allocate isa_dev"); + prom_halt(); + } + + memset(isa_dev, 0, sizeof(*isa_dev)); + + /* Link it in. */ + isa_dev->next = NULL; + if (isa_br->devices == NULL) { + isa_br->devices = isa_dev; + } else { + struct isa_device *tmp = isa_br->devices; + + while (tmp->next) + tmp = tmp->next; + + tmp->next = isa_dev; + } + + isa_dev->bus = isa_br; + isa_dev->prom_node = node; + prop_len = prom_getproperty(node, "name", + (char *) isa_dev->prom_name, + sizeof(isa_dev->prom_name)); + if (prop_len <= 0) { + fatal_err("cannot get isa_dev OBP node name"); + prom_halt(); + } + + prop_len = prom_getproperty(node, "compatible", + (char *) isa_dev->compatible, + sizeof(isa_dev->compatible)); + + /* Not having this is OK. */ + if (prop_len <= 0) + isa_dev->compatible[0] = '\0'; + + isa_dev_get_resource(isa_dev); + isa_dev_get_irq(isa_dev); + + report_dev(isa_dev, 0); + + isa_fill_children(isa_dev); + + printk("]"); + + node = prom_getsibling(node); + } +} + +void __init isa_init(void) +{ + struct pci_dev *pdev; + unsigned short vendor, device; + int index = 0; + + vendor = PCI_VENDOR_ID_AL; + device = PCI_DEVICE_ID_AL_M1533; + + pdev = NULL; + while ((pdev = pci_find_device(vendor, device, pdev)) != NULL) { + struct pcidev_cookie *pdev_cookie; + struct pci_pbm_info *pbm; + struct isa_bridge *isa_br; + int prop_len; + + pdev_cookie = pdev->sysdata; + if (!pdev_cookie) { + printk("ISA: Warning, ISA bridge ignored due to " + "lack of OBP data.\n"); + continue; + } + pbm = pdev_cookie->pbm; + + isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL); + if (!isa_br) { + fatal_err("cannot allocate isa_bridge"); + prom_halt(); + } + + memset(isa_br, 0, sizeof(*isa_br)); + + /* Link it in. */ + isa_br->next = isa_chain; + isa_chain = isa_br; + + isa_br->parent = pbm; + isa_br->self = pdev; + isa_br->index = index++; + isa_br->prom_node = pdev_cookie->prom_node; + strncpy(isa_br->prom_name, pdev_cookie->prom_name, + sizeof(isa_br->prom_name)); + + prop_len = prom_getproperty(isa_br->prom_node, + "ranges", + (char *) isa_br->isa_ranges, + sizeof(isa_br->isa_ranges)); + if (prop_len <= 0) + isa_br->num_isa_ranges = 0; + else + isa_br->num_isa_ranges = + (prop_len / sizeof(struct linux_prom_isa_ranges)); + + printk("isa%d:", isa_br->index); + + isa_fill_devices(isa_br); + + printk("\n"); + } +} diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.4.4/linux/arch/sparc64/kernel/pci.c Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc64/kernel/pci.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $ +/* $Id: pci.c,v 1.29 2001/05/15 08:54:30 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -19,6 +19,7 @@ #include #include #include +#include unsigned long pci_memspace_mask = 0xffffffffUL; @@ -77,13 +78,13 @@ volatile int pci_poke_faulted; /* Probe for all PCI controllers in the system. */ -extern void sabre_init(int); -extern void psycho_init(int); -extern void schizo_init(int); +extern void sabre_init(int, char *); +extern void psycho_init(int, char *); +extern void schizo_init(int, char *); static struct { char *model_name; - void (*init)(int); + void (*init)(int, char *); } pci_controller_table[] = { { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, @@ -104,7 +105,7 @@ if (!strncmp(model_name, pci_controller_table[i].model_name, namelen)) { - pci_controller_table[i].init(node); + pci_controller_table[i].init(node, model_name); return; } } @@ -187,6 +188,7 @@ if (pci_device_reorder) pci_reorder_devs(); + isa_init(); ebus_init(); } @@ -232,6 +234,149 @@ return NULL; } return str; +} + +/* Platform support for /proc/bus/pci/X/Y mmap()s. */ + +/* Adjust vm_pgoff of VMA such that it is the physical page offset corresponding + * to the 32-bit pci bus offset for DEV requested by the user. + * + * Basically, the user finds the base address for his device which he wishes + * to mmap. They read the 32-bit value from the config space base register, + * add whatever PAGE_SIZE multiple offset they wish, and feed this into the + * offset parameter of mmap on /proc/bus/pci/XXX for that device. + * + * Returns negative error code on failure, zero on success. + */ +static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long user32 = user_offset & 0xffffffffUL; + unsigned long largest_base, this_base, addr32; + int i; + + /* Figure out which base address this is for. */ + largest_base = 0UL; + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &dev->resource[i]; + + /* Active? */ + if (!rp->flags) + continue; + + /* Same type? */ + if (i == PCI_ROM_RESOURCE) { + if (mmap_state != pci_mmap_mem) + continue; + } else { + if ((mmap_state == pci_mmap_io && + (rp->flags & IORESOURCE_IO) == 0) || + (mmap_state == pci_mmap_mem && + (rp->flags & IORESOURCE_MEM) == 0)) + continue; + } + + this_base = rp->start; + + addr32 = (this_base & PAGE_MASK) & 0xffffffffUL; + + if (mmap_state == pci_mmap_io) + addr32 &= 0xffffff; + + if (addr32 <= user32 && this_base > largest_base) + largest_base = this_base; + } + + if (largest_base == 0UL) + return -EINVAL; + + /* Now construct the final physical address. */ + 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); + + return 0; +} + +/* Set vm_flags of VMA, as appropriate for this architecture, for a pci device + * mapping. + */ +static __inline__ void __pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + vma->vm_flags |= (VM_SHM | VM_LOCKED); +} + +/* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci + * device mapping. + */ +static __inline__ void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + /* Our io_remap_page_range takes care of this, do nothing. */ +} + +extern int io_remap_page_range(unsigned long from, unsigned long offset, + unsigned long size, pgprot_t prot, int space); + +/* Perform the actual remap of the pages for a PCI device mapping, as appropriate + * for this architecture. The region in the process to map is described by vm_start + * and vm_end members of VMA, the base physical address is found in vm_pgoff. + * The pci device structure is provided so that architectures may make mapping + * decisions on a per-device or per-bus basis. + * + * Returns a negative error code on failure, zero on success. + */ +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine) +{ + int ret; + + ret = __pci_mmap_make_offset(dev, vma, mmap_state); + if (ret < 0) + return ret; + + __pci_mmap_set_flags(dev, vma, mmap_state); + __pci_mmap_set_pgprot(dev, vma, mmap_state); + + ret = io_remap_page_range(vma->vm_start, + (vma->vm_pgoff << PAGE_SHIFT | + (write_combine ? 0x1UL : 0x0UL)), + vma->vm_end - vma->vm_start, vma->vm_page_prot, 0); + if (ret) + return ret; + + vma->vm_flags |= VM_IO; + return 0; +} + +/* Return the index of the PCI controller for device PDEV. */ + +int pci_controller_num(struct pci_dev *pdev) +{ + struct pcidev_cookie *cookie = pdev->sysdata; + int ret; + + if (cookie != NULL) { + struct pci_pbm_info *pbm = cookie->pbm; + if (pbm == NULL || pbm->parent == NULL) { + ret = -ENXIO; + } else { + struct pci_controller_info *p = pbm->parent; + + ret = p->index; + if (p->pbms_same_domain == 0) + ret = ((ret << 1) + + ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); + } + } else { + ret = -ENXIO; + } + + return ret; } #endif /* !(CONFIG_PCI) */ diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c --- v2.4.4/linux/arch/sparc64/kernel/pci_common.c Tue Mar 6 22:44:16 2001 +++ linux/arch/sparc64/kernel/pci_common.c Sat May 19 18:13:15 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.14 2001/02/28 03:28:55 davem Exp $ +/* $Id: pci_common.c,v 1.18 2001/05/18 23:06:35 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -10,6 +10,29 @@ #include +/* Fix self device of BUS and hook it into BUS->self. + * The pci_scan_bus does not do this for the host bridge. + */ +void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) +{ + struct list_head *walk = &pbus->devices; + + walk = walk->next; + while (walk != &pbus->devices) { + struct pci_dev *pdev = pci_dev_b(walk); + + if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { + pbus->self = pdev; + return; + } + + walk = walk->next; + } + + prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); + prom_halt(); +} + /* Find the OBP PROM device tree node for a PCI device. * Return zero if not found. */ @@ -29,7 +52,10 @@ */ if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) && (pdev->vendor == PCI_VENDOR_ID_SUN) && - (pdev->device == PCI_DEVICE_ID_SUN_PBM)) { + (pdev->device == PCI_DEVICE_ID_SUN_PBM || + pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || + pdev->device == PCI_DEVICE_ID_SUN_SABRE || + pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) { *nregs = 0; return bus_prom_node; } @@ -474,15 +500,21 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) { + struct linux_prom_pci_intmap bridge_local_intmap[PROM_PCIIMAP_MAX], *intmap; + struct linux_prom_pci_intmask bridge_local_intmask, *intmask; struct pcidev_cookie *dev_pcp = pdev->sysdata; struct pci_pbm_info *pbm = dev_pcp->pbm; struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs; unsigned int hi, mid, lo, irq; - int i; + int i, num_intmap; if (pbm->num_pbm_intmap == 0) return 0; + intmap = &pbm->pbm_intmap[0]; + intmask = &pbm->pbm_intmask; + num_intmap = pbm->num_pbm_intmap; + /* If we are underneath a PCI bridge, use PROM register * property of the parent bridge which is closest to * the PBM. @@ -490,7 +522,7 @@ if (pdev->bus->number != pbm->pci_first_busno) { struct pcidev_cookie *bus_pcp; struct pci_dev *pwalk; - int offset; + int offset, plen; pwalk = pdev->bus->self; while (pwalk->bus && @@ -498,6 +530,27 @@ pwalk = pwalk->bus->self; bus_pcp = pwalk->sysdata; + + /* But if the PCI bridge has it's own interrupt map + * and mask properties, use that and the device regs. + */ + plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map", + (char *) &bridge_local_intmap[0], + sizeof(bridge_local_intmap)); + if (plen != -1) { + intmap = &bridge_local_intmap[0]; + num_intmap = plen / sizeof(struct linux_prom_pci_intmap); + plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map-mask", + (char *) &bridge_local_intmask, + sizeof(bridge_local_intmask)); + if (plen == -1) { + prom_printf("pbm_intmap_match: Bridge has intmap but " + "no intmask.\n"); + prom_halt(); + } + goto check_intmap; + } + pregs = bus_pcp->prom_regs; offset = prom_getint(dev_pcp->prom_node, @@ -518,17 +571,18 @@ } } - hi = pregs->phys_hi & pbm->pbm_intmask.phys_hi; - mid = pregs->phys_mid & pbm->pbm_intmask.phys_mid; - lo = pregs->phys_lo & pbm->pbm_intmask.phys_lo; - irq = *interrupt & pbm->pbm_intmask.interrupt; - - for (i = 0; i < pbm->num_pbm_intmap; i++) { - if (pbm->pbm_intmap[i].phys_hi == hi && - pbm->pbm_intmap[i].phys_mid == mid && - pbm->pbm_intmap[i].phys_lo == lo && - pbm->pbm_intmap[i].interrupt == irq) { - *interrupt = pbm->pbm_intmap[i].cinterrupt; +check_intmap: + hi = pregs->phys_hi & intmask->phys_hi; + mid = pregs->phys_mid & intmask->phys_mid; + lo = pregs->phys_lo & intmask->phys_lo; + irq = *interrupt & intmask->interrupt; + + for (i = 0; i < num_intmap; i++) { + if (intmap[i].phys_hi == hi && + intmap[i].phys_mid == mid && + intmap[i].phys_lo == lo && + intmap[i].interrupt == irq) { + *interrupt = intmap[i].cinterrupt; return 1; } } diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h --- v2.4.4/linux/arch/sparc64/kernel/pci_impl.h Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc64/kernel/pci_impl.h Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.7 2001/03/28 10:56:34 davem Exp $ +/* $Id: pci_impl.h,v 1.8 2001/05/15 08:54:30 davem Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -19,6 +19,7 @@ extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ +extern void pci_fixup_host_bridge_self(struct pci_bus *pbus); extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, struct pci_pbm_info *pbm, int prom_node); diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c --- v2.4.4/linux/arch/sparc64/kernel/pci_iommu.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/pci_iommu.c Thu May 24 15:00:58 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_iommu.c,v 1.13 2001/03/14 08:42:38 davem Exp $ +/* $Id: pci_iommu.c,v 1.14 2001/05/23 03:06:51 davem Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -58,7 +58,7 @@ static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) { - iopte_t *iopte, *limit; + iopte_t *iopte, *limit, *first; unsigned long cnum, ent, flush_point; cnum = 0; @@ -77,6 +77,7 @@ iopte += ((ent = iommu->alloc_info[cnum].next) << cnum); flush_point = iommu->alloc_info[cnum].flush; + first = iopte; for (;;) { if (iopte_val(*iopte) == 0UL) { if ((iopte + (1 << cnum)) >= limit) @@ -98,10 +99,17 @@ } if (ent == flush_point) __iommu_flushall(iommu); + if (iopte == first) + goto bad; } /* I've got your streaming cluster right here buddy boy... */ return iopte; + +bad: + printk(KERN_EMERG "pci_iommu: alloc_streaming_cluster of npages(%ld) failed!\n", + npages); + return NULL; } static void free_streaming_cluster(struct pci_iommu *iommu, dma_addr_t base, @@ -319,6 +327,8 @@ spin_lock_irqsave(&iommu->lock, flags); base = alloc_streaming_cluster(iommu, npages); + if (base == NULL) + goto bad; bus_addr = (iommu->page_table_map_base + ((base - iommu->page_table) << PAGE_SHIFT)); ret = bus_addr | (oaddr & ~PAGE_MASK); @@ -339,6 +349,11 @@ spin_unlock_irqrestore(&iommu->lock, flags); return ret; + +bad: + spin_unlock_irqrestore(&iommu->lock, flags); + BUG(); + return 0; } /* Unmap a single streaming mode DMA translation. */ @@ -517,6 +532,8 @@ spin_lock_irqsave(&iommu->lock, flags); base = alloc_streaming_cluster(iommu, npages); + if (base == NULL) + goto bad; dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << PAGE_SHIFT); /* Step 3: Normalize DMA addresses. */ @@ -550,6 +567,11 @@ spin_unlock_irqrestore(&iommu->lock, flags); return used; + +bad: + spin_unlock_irqrestore(&iommu->lock, flags); + BUG(); + return 0; } /* Unmap a set of streaming mode DMA translations. */ diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.4.4/linux/arch/sparc64/kernel/pci_psycho.c Thu Apr 19 08:38:49 2001 +++ linux/arch/sparc64/kernel/pci_psycho.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.22 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_psycho.c,v 1.24 2001/05/15 08:54:30 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1235,9 +1235,23 @@ static void __init pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { + struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("PSYCHO: Critical allocation failure.\n"); + prom_halt(); + } + + /* All we care about is the PBM. */ + memset(cookie, 0, sizeof(*cookie)); + cookie->pbm = pbm; + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); + pci_fixup_host_bridge_self(pbm->pci_bus); + pbm->pci_bus->self->sysdata = cookie; + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); @@ -1521,7 +1535,7 @@ #define PSYCHO_CONFIGSPACE 0x001000000UL -void __init psycho_init(int node) +void __init psycho_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; @@ -1564,6 +1578,7 @@ p->portid = upa_portid; p->index = pci_num_controllers++; + p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; p->irq_build = psycho_irq_build; p->base_address_update = psycho_base_address_update; diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.4.4/linux/arch/sparc64/kernel/pci_sabre.c Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/kernel/pci_sabre.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.27 2001/04/24 05:14:12 davem Exp $ +/* $Id: pci_sabre.c,v 1.32 2001/05/15 11:10:01 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -215,7 +215,7 @@ ((unsigned long)(DEVFN) << 8) | \ ((unsigned long)(REG))) -static int apb_present; +static int hummingbird_p; static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, unsigned char bus, @@ -231,7 +231,7 @@ static int sabre_out_of_range(unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || @@ -243,7 +243,7 @@ unsigned char bus, unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return ((pbm->parent == 0) || @@ -1112,11 +1112,28 @@ } } +static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) +{ + struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("SABRE: Critical allocation failure.\n"); + prom_halt(); + } + + /* All we care about is the PBM. */ + memset(cookie, 0, sizeof(*cookie)); + cookie->pbm = pbm; + + return cookie; +} + static void __init sabre_scan_bus(struct pci_controller_info *p) { static int once = 0; struct pci_bus *sabre_bus; struct pci_pbm_info *pbm; + struct pcidev_cookie *cookie; struct list_head *walk; int sabres_scanned; @@ -1142,10 +1159,15 @@ } once++; + cookie = alloc_bridge_cookie(&p->pbm_A); + /* The pci_bus2pbm table has already been setup in sabre_init. */ sabre_bus = pci_scan_bus(p->pci_first_busno, p->pci_ops, &p->pbm_A); + pci_fixup_host_bridge_self(sabre_bus); + sabre_bus->self->sysdata = cookie; + apb_init(p, sabre_bus); sabres_scanned = 0; @@ -1161,6 +1183,9 @@ } else continue; + cookie = alloc_bridge_cookie(pbm); + pbus->self->sysdata = cookie; + sabres_scanned++; pbus->sysdata = pbm; @@ -1444,6 +1469,11 @@ memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } + + sprintf(pbm->name, "SABRE%d PBM%c", p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = pbm->name; + /* Hack up top-level resources. */ pbm->io_space.start = p->controller_regs + SABRE_IOSPACE; pbm->io_space.end = pbm->io_space.start + (1UL << 16) - 1UL; @@ -1461,12 +1491,10 @@ prom_printf("Cannot register Hummingbird's MEM space.\n"); prom_halt(); } - } else { - apb_present = 1; } } -void __init sabre_init(int pnode) +void __init sabre_init(int pnode, char *model_name) { struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; @@ -1478,6 +1506,18 @@ u32 upa_portid, dma_mask; int bus; + hummingbird_p = 0; + if (!strcmp(model_name, "pci108e,a001")) + hummingbird_p = 1; + else if (!strcmp(model_name, "SUNW,sabre")) { + char compat[64]; + + if (prom_getproperty(pnode, "compatible", + compat, sizeof(compat)) > 0 && + !strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + } + p = kmalloc(sizeof(*p), GFP_ATOMIC); if (!p) { prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); @@ -1502,6 +1542,7 @@ p->portid = upa_portid; p->index = pci_num_controllers++; + p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; p->irq_build = sabre_irq_build; p->base_address_update = sabre_base_address_update; diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c --- v2.4.4/linux/arch/sparc64/kernel/pci_schizo.c Thu Apr 19 08:38:49 2001 +++ linux/arch/sparc64/kernel/pci_schizo.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.14 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_schizo.c,v 1.16 2001/05/15 08:54:30 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -1328,9 +1328,23 @@ static void __init pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { + struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("SCHIZO: Critical allocation failure.\n"); + prom_halt(); + } + + /* All we care about is the PBM. */ + memset(cookie, 0, sizeof(*cookie)); + cookie->pbm = pbm; + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); + pci_fixup_host_bridge_self(pbm->pci_bus); + pbm->pci_bus->self->sysdata = cookie; + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); @@ -1709,7 +1723,7 @@ schizo_write(pbm_b_base + 0x2000UL, tmp); } -void __init schizo_init(int node) +void __init schizo_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; @@ -1761,6 +1775,7 @@ p->portid = portid; p->index = pci_num_controllers++; + p->pbms_same_domain = 0; p->scan_bus = schizo_scan_bus; p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c --- v2.4.4/linux/arch/sparc64/kernel/sbus.c Sun Feb 18 19:49:54 2001 +++ linux/arch/sparc64/kernel/sbus.c Thu May 24 15:00:58 2001 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.13 2001/02/13 01:16:44 davem Exp $ +/* $Id: sbus.c,v 1.14 2001/05/23 03:06:51 davem Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -133,7 +133,7 @@ static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) { - iopte_t *iopte, *limit; + iopte_t *iopte, *limit, *first; unsigned long cnum, ent, flush_point; cnum = 0; @@ -150,6 +150,7 @@ iopte += ((ent = iommu->alloc_info[cnum].next) << cnum); flush_point = iommu->alloc_info[cnum].flush; + first = iopte; for (;;) { if (iopte_val(*iopte) == 0UL) { if ((iopte + (1 << cnum)) >= limit) @@ -169,10 +170,17 @@ } if (ent == flush_point) __iommu_flushall(iommu); + if (iopte == first) + goto bad; } /* I've got your streaming cluster right here buddy boy... */ return iopte; + +bad: + printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n", + npages); + return NULL; } static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages) @@ -332,6 +340,8 @@ spin_lock_irqsave(&iommu->lock, flags); npages = size >> PAGE_SHIFT; iopte = alloc_streaming_cluster(iommu, npages); + if (iopte == NULL) + goto bad; dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); npages = size >> PAGE_SHIFT; iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; @@ -345,6 +355,11 @@ spin_unlock_irqrestore(&iommu->lock, flags); return (dma_base | offset); + +bad: + spin_unlock_irqrestore(&iommu->lock, flags); + BUG(); + return 0; } void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction) @@ -455,6 +470,8 @@ spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_streaming_cluster(iommu, npages); + if (iopte == NULL) + goto bad; dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); /* Normalize DVMA addresses. */ @@ -479,6 +496,11 @@ spin_unlock_irqrestore(&iommu->lock, flags); return used; + +bad: + spin_unlock_irqrestore(&iommu->lock, flags); + BUG(); + return 0; } void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c --- v2.4.4/linux/arch/sparc64/kernel/semaphore.c Tue Apr 17 17:19:30 2001 +++ linux/arch/sparc64/kernel/semaphore.c Sun May 20 11:32:07 2001 @@ -1,128 +1,88 @@ -/* $Id: semaphore.c,v 1.6 2001/04/14 01:12:02 davem Exp $ - * Generic semaphore code. Buyer beware. Do your own - * specific changes in +/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $ + * semaphore.c: Sparc64 semaphore implementation. + * + * This is basically the PPC semaphore scheme ported to use + * the sparc64 atomic instructions, so see the PPC code for + * credits. */ #include -#include /* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. + * Atomically update sem->count. + * This does the equivalent of the following: * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. + * old_count = sem->count; + * tmp = MAX(old_count, 0) + incr; + * sem->count = tmp; + * return old_count; */ +static __inline__ int __sem_update_count(struct semaphore *sem, int incr) +{ + int old_count, tmp; + + __asm__ __volatile__("\n" +" ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n" +"1: ldsw [%3], %0\n" +" mov %0, %1\n" +" cmp %0, 0\n" +" movl %%icc, 0, %1\n" +" add %1, %4, %1\n" +" cas [%3], %0, %1\n" +" cmp %0, %1\n" +" bne,pn %%icc, 1b\n" +" nop\n" + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (&sem->count), "r" (incr), "m" (sem->count) + : "cc"); + + return old_count; +} + void __up(struct semaphore *sem) { - wake_one_more(sem); + __sem_update_count(sem, 1); wake_up(&sem->wait); } -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + while (__sem_update_count(sem, -1) <= 0) { + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + } remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; -void __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) + wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) { - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + while (__sem_update_count(sem, -1) <= 0) { + if (signal_pending(current)) { + __sem_update_count(sem, 0); + retval = -EINTR; + break; + } + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + } + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; } diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.4.4/linux/arch/sparc64/kernel/sparc64_ksyms.c Fri Apr 13 20:15:55 2001 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Sun May 20 11:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.105 2001/04/14 01:12:02 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.107 2001/05/18 08:01:35 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -47,6 +47,7 @@ #endif #ifdef CONFIG_PCI #include +#include #endif #include @@ -156,7 +157,6 @@ /* semaphores */ EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); EXPORT_SYMBOL(__up); /* Atomic counter implementation. */ @@ -199,6 +199,7 @@ #endif #ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); +EXPORT_SYMBOL(isa_chain); EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(outsb); diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.4.4/linux/arch/sparc64/kernel/sys_sunos32.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc64/kernel/sys_sunos32.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $ +/* $Id: sys_sunos32.c,v 1.60 2001/04/27 07:02:42 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.4.4/linux/arch/sparc64/mm/init.c Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/mm/init.c Wed May 16 10:20:11 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.175 2001/04/24 01:09:12 davem Exp $ +/* $Id: init.c,v 1.176 2001/05/16 15:07:11 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -1139,8 +1139,16 @@ unsigned long second_alias_page = 0; unsigned long pt, flags, end_pfn, pages_avail; unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); + unsigned long real_end; set_bit(0, mmu_context_bmap); + + real_end = (unsigned long)&_end; +#ifdef CONFIG_BLK_DEV_INITRD + if (sparc_ramdisk_image) + real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size)); +#endif + /* We assume physical memory starts at some 4mb multiple, * if this were not true we wouldn't boot up to this point * anyways. @@ -1161,7 +1169,7 @@ : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) : "memory"); - if (((unsigned long)&_end) >= KERNBASE + 0x340000) { + if (real_end >= KERNBASE + 0x340000) { second_alias_page = alias_base + 0x400000; __asm__ __volatile__( " stxa %1, [%0] %3\n" @@ -1189,7 +1197,7 @@ : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" ((0<<16) | (13<<3)) : "memory"); - if (((unsigned long)&_end) >= KERNBASE + 0x340000) { + if (real_end >= KERNBASE + 0x340000) { second_alias_page = alias_base + 0x400000; __asm__ __volatile__( " stxa %1, [%0] %3\n" diff -u --recursive --new-file v2.4.4/linux/drivers/Makefile linux/drivers/Makefile --- v2.4.4/linux/drivers/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/Makefile Wed May 16 10:27:02 2001 @@ -9,7 +9,7 @@ mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi i2o ide \ scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi -subdir-y := block char net parport sound misc media cdrom +subdir-y := parport char block net sound misc media cdrom subdir-m := $(subdir-y) diff -u --recursive --new-file v2.4.4/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.4.4/linux/drivers/acorn/block/mfmhd.c Thu Oct 26 23:35:47 2000 +++ linux/drivers/acorn/block/mfmhd.c Sat Apr 28 11:27:53 2001 @@ -1485,14 +1485,7 @@ for (i = maxp - 1; i >= 0; i--) { int minor = start + i; - kdev_t devi = MKDEV(MAJOR_NR, minor); - struct super_block *sb = get_super(devi); - - sync_dev (devi); - if (sb) - invalidate_inodes (sb); - invalidate_buffers (devi); - + invalidate_device (MKDEV(MAJOR_NR, minor), 1); mfm_gendisk.part[minor].start_sect = 0; mfm_gendisk.part[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/acpi/driver.c linux/drivers/acpi/driver.c --- v2.4.4/linux/drivers/acpi/driver.c Fri Feb 9 11:45:58 2001 +++ linux/drivers/acpi/driver.c Tue May 22 09:38:51 2001 @@ -311,8 +311,10 @@ size = buf.length - file->f_pos; if (size > *len) size = *len; - if (copy_to_user(buffer, data, size)) + if (copy_to_user(buffer, data, size)) { + kfree(buf.pointer); return -EFAULT; + } } kfree(buf.pointer); diff -u --recursive --new-file v2.4.4/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.4.4/linux/drivers/atm/eni.c Thu Jul 6 21:37:24 2000 +++ linux/drivers/atm/eni.c Wed May 16 10:22:50 2001 @@ -1796,6 +1796,7 @@ return -EAGAIN; } /* @@@ should release IRQ on error */ + pci_set_master(eni_dev->pci_dev); if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { diff -u --recursive --new-file v2.4.4/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.4.4/linux/drivers/block/DAC960.c Tue Feb 20 21:26:22 2001 +++ linux/drivers/block/DAC960.c Sat Apr 28 11:27:53 2001 @@ -5134,16 +5134,12 @@ PartitionNumber); int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber); - SuperBlock_T *SuperBlock = get_super(Device); if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0) continue; /* Flush all changes and invalidate buffered state. */ - sync_dev(Device); - if (SuperBlock != NULL) - invalidate_inodes(SuperBlock); - invalidate_buffers(Device); + invalidate_device(Device, 1); /* Clear existing partition sizes. */ diff -u --recursive --new-file v2.4.4/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.4.4/linux/drivers/block/acsi.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/acsi.c Sat Apr 28 11:27:53 2001 @@ -1886,13 +1886,7 @@ for( i = max_p - 1; i >= 0 ; i-- ) { if (gdev->part[start + i].nr_sects != 0) { - kdev_t devp = MKDEV(MAJOR_NR, start + i); - struct super_block *sb = get_super(devp); - - fsync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, start + i), 1); gdev->part[start + i].nr_sects = 0; } gdev->part[start+i].start_sect = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.4.4/linux/drivers/block/acsi_slm.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/acsi_slm.c Tue May 22 10:23:16 2001 @@ -378,19 +378,22 @@ length = slm_getstats( (char *)page, MINOR(node->i_rdev) ); if (length < 0) { - free_page( page ); - return( length ); + count = length; + goto out; } if (file->f_pos >= length) { - free_page( page ); - return( 0 ); + count = 0; + goto out; } if (count + file->f_pos > length) count = length - file->f_pos; end = count + file->f_pos; - copy_to_user( buf, (char *)page + file->f_pos, count ); - free_page( page ); + if (copy_to_user(buf, (char *)page + file->f_pos, count)) { + count = -EFAULT; + goto out; + } file->f_pos = end; +out: free_page( page ); return( count ); } @@ -648,7 +651,8 @@ if (filled + n > BufferSize) n = BufferSize - filled; - copy_from_user( BufferP, buf, n ); + if (copy_from_user(BufferP, buf, n)) + return -EFAULT; BufferP += n; filled += n; @@ -725,8 +729,9 @@ if (put_user(stat, (long *)&((struct SLM_status *)arg)->stat)) return -EFAULT; - copy_to_user( ((struct SLM_status *)arg)->str, str, - strlen(str) + 1 ); + if (copy_to_user( ((struct SLM_status *)arg)->str, str, + strlen(str) + 1)) + return -EFAULT; } return( stat ); } @@ -734,10 +739,6 @@ case SLMIOGPSIZE: { /* get paper size */ int w, h; - err = verify_area( VERIFY_WRITE, (long *)arg, - sizeof(struct SLM_paper_size) ); - if (err) return( err ); - if ((err = slm_get_pagesize( device, &w, &h ))) return( err ); if (put_user(w, (long *)&((struct SLM_paper_size *)arg)->width)) diff -u --recursive --new-file v2.4.4/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.4.4/linux/drivers/block/amiflop.c Sun Oct 1 20:35:15 2000 +++ linux/drivers/block/amiflop.c Sat Apr 28 11:27:53 2001 @@ -1540,10 +1540,7 @@ break; case FDFMTEND: floppy_off(drive); - sb = get_super(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 0); break; case FDGETPRM: memset((void *)&getprm, 0, sizeof (getprm)); diff -u --recursive --new-file v2.4.4/linux/drivers/block/blkpg.c linux/drivers/block/blkpg.c --- v2.4.4/linux/drivers/block/blkpg.c Thu Oct 26 23:35:47 2000 +++ linux/drivers/block/blkpg.c Sun May 20 11:34:05 2001 @@ -157,8 +157,7 @@ /* partition in use? Incomplete check for now. */ devp = MKDEV(MAJOR(dev), minor); - if (get_super(devp) || /* mounted? */ - is_swap_partition(devp)) + if (is_mounted(devp) || is_swap_partition(devp)) return -EBUSY; /* all seems OK */ diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.4.4/linux/drivers/block/cciss.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/block/cciss.c Tue May 22 10:23:16 2001 @@ -44,8 +44,8 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.4.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,2) +#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation"); @@ -55,6 +55,17 @@ #include "cciss.h" #include +/* define the PCI info for the cards we can control */ +const struct pci_device_id cciss_pci_device_id[] = { + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS, + 0x0E11, 0x4070, 0, 0, 0}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, + 0x0E11, 0x4080, 0, 0, 0}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, + 0x0E11, 0x4082, 0, 0, 0}, +}; +MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); + #define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) /* board_id = Subsystem Device ID & Vendor ID @@ -73,7 +84,9 @@ #define READ_AHEAD 128 #define NR_CMDS 128 /* #commands that can be outstanding */ #define MAX_CTLR 8 -static int nr_ctlr; + +#define CCISS_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */ + static ctlr_info_t *hba[MAX_CTLR]; static struct proc_dir_entry *proc_cciss; @@ -125,10 +138,10 @@ ctlr = h->ctlr; size = sprintf(buffer, "%s: Compaq %s Controller\n" - " Board ID: %08lx\n" + " Board ID: 0x%08lx\n" " Firmware Version: %c%c%c%c\n" - " Memory Address: %08lx\n" - " IRQ: 0x%x\n" + " Memory Address: 0x%08lx\n" + " IRQ: %d\n" " Logical drives: %d\n" " Current Q depth: %d\n" " Current # commands on controller %d\n" @@ -172,7 +185,7 @@ static void __init cciss_procinit(int i) { if (proc_cciss == NULL) { - proc_cciss = proc_mkdir("driver/cciss", NULL); + proc_cciss = proc_mkdir("cciss", proc_root_driver); if (!proc_cciss) return; } @@ -186,29 +199,32 @@ * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track * which ones are free or in use. For operations that can wait for kmalloc - * to possible sleep, this routine can be called with a NULL pointer. - * cmd_free() MUST be called with a NULL pointer if cmd_alloc was. + * to possible sleep, this routine can be called with get_from_pool set to 0. + * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was. */ -static CommandList_struct * cmd_alloc(ctlr_info_t *h) +static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool) { CommandList_struct *c; int i; u64bit temp64; + dma_addr_t cmd_dma_handle, err_dma_handle; - if (h == NULL) + if (!get_from_pool) { - c = (CommandList_struct *)kmalloc(sizeof(CommandList_struct), - GFP_KERNEL); + c = (CommandList_struct *) pci_alloc_consistent( + h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); if(c==NULL) return NULL; memset(c, 0, sizeof(CommandList_struct)); - c->err_info = (ErrorInfo_struct *)kmalloc( - sizeof(ErrorInfo_struct), GFP_KERNEL); + c->err_info = (ErrorInfo_struct *)pci_alloc_consistent( + h->pdev, sizeof(ErrorInfo_struct), + &err_dma_handle); if (c->err_info == NULL) { - kfree(c); + pci_free_consistent(h->pdev, + sizeof(CommandList_struct), c, cmd_dma_handle); return NULL; } memset(c->err_info, 0, sizeof(ErrorInfo_struct)); @@ -223,18 +239,23 @@ printk(KERN_DEBUG "cciss: using command buffer %d\n", i); #endif c = h->cmd_pool + i; - memset(c, 0, sizeof(CommandList_struct)); + memset(c, 0, sizeof(CommandList_struct)); + cmd_dma_handle = h->cmd_pool_dhandle + + i*sizeof(CommandList_struct); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + err_dma_handle = h->errinfo_pool_dhandle + + i*sizeof(ErrorInfo_struct); h->nr_allocs++; } - - temp64.val = (__u64) virt_to_bus(c->err_info); + c->busaddr = (__u32) cmd_dma_handle; + temp64.val = (__u64) err_dma_handle; c->ErrDesc.Addr.lower = temp64.val32.lower; c->ErrDesc.Addr.upper = temp64.val32.upper; c->ErrDesc.Len = sizeof(ErrorInfo_struct); - c->busaddr = virt_to_bus(c); + + c->ctlr = h->ctlr; return c; @@ -243,14 +264,19 @@ /* * Frees a command block that was previously allocated with cmd_alloc(). */ -static void cmd_free(ctlr_info_t *h, CommandList_struct *c) +static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool) { int i; + u64bit temp64; - if( h == NULL) + if( !got_from_pool) { - kfree(c->err_info); - kfree(c); + temp64.val32.lower = c->ErrDesc.Addr.lower; + temp64.val32.upper = c->ErrDesc.Addr.upper; + pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), + c->err_info, (dma_addr_t) temp64.val); + pci_free_consistent(h->pdev, sizeof(CommandList_struct), + c, (dma_addr_t) c->busaddr); } else { i = c - h->cmd_pool; @@ -390,8 +416,8 @@ cciss_pci_info_struct pciinfo; if (!arg) return -EINVAL; - pciinfo.bus = hba[ctlr]->pci_bus; - pciinfo.dev_fn = hba[ctlr]->pci_dev_fn; + pciinfo.bus = hba[ctlr]->pdev->bus->number; + pciinfo.dev_fn = hba[ctlr]->pdev->devfn; pciinfo.board_id = hba[ctlr]->board_id; if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct ))) return -EFAULT; @@ -583,13 +609,10 @@ if (iocommand.Request.Type.Direction == XFER_WRITE) { /* Copy the data into the buffer we created */ - if (copy_from_user(buff, iocommand.buf, - iocommand.buf_size)) { - kfree(buff); + if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) return -EFAULT; - } } - if ((c = cmd_alloc(NULL)) == NULL) + if ((c = cmd_alloc(h , 0)) == NULL) { kfree(buff); return -ENOMEM; @@ -615,8 +638,10 @@ // Fill in the scatter gather information if (iocommand.buf_size > 0 ) - { - temp64.val = (__u64) virt_to_bus(buff); + { + temp64.val = pci_map_single( h->pdev, buff, + iocommand.buf_size, + PCI_DMA_BIDIRECTIONAL); c->SG[0].Addr.lower = temp64.val32.lower; c->SG[0].Addr.upper = temp64.val32.upper; c->SG[0].Len = iocommand.buf_size; @@ -633,12 +658,18 @@ while(c->cmd_type != CMD_IOCTL_DONE) schedule_timeout(1); + /* unlock the buffers from DMA */ + temp64.val32.lower = c->SG[0].Addr.lower; + temp64.val32.upper = c->SG[0].Addr.upper; + pci_unmap_single( h->pdev, (dma_addr_t) temp64.val, + iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); + /* Copy the error information out */ iocommand.error_info = *(c->err_info); if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) { - cmd_free(NULL, c); kfree(buff); + cmd_free(h, c, 0); return( -EFAULT); } @@ -647,13 +678,12 @@ /* Copy the data out of the buffer we created */ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { - cmd_free(NULL, c); - kfree(buff); - return -EFAULT; + kfree(buff); + cmd_free(h, c, 0); } } - cmd_free(NULL, c); kfree(buff); + cmd_free(h, c, 0); return(0); } @@ -691,13 +721,9 @@ max_p = gdev->max_p; start = target << gdev->minor_shift; - for(i=max_p; i>=0; i--) { + for(i=max_p-1; i>=0; i--) { int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; @@ -820,9 +846,9 @@ int i; unsigned long complete; ctlr_info_t *info_p= hba[ctlr]; - u64bit temp64; + u64bit buff_dma_handle; - c = cmd_alloc(info_p); + c = cmd_alloc(info_p, 1); if (c == NULL) { printk(KERN_WARNING "cciss: unable to get memory"); @@ -903,15 +929,16 @@ printk(KERN_WARNING "cciss: Unknown Command 0x%c sent attempted\n", cmd); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return(IO_ERROR); }; // Fill in the scatter gather information if (size > 0 ) { - temp64.val = (__u64) virt_to_bus(buff); - c->SG[0].Addr.lower = temp64.val32.lower; - c->SG[0].Addr.upper = temp64.val32.upper; + buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, + buff, size, PCI_DMA_BIDIRECTIONAL); + c->SG[0].Addr.lower = buff_dma_handle.val32.lower; + c->SG[0].Addr.upper = buff_dma_handle.val32.upper; c->SG[0].Len = size; c->SG[0].Ext = 0; // we are not chaining } @@ -947,6 +974,9 @@ printk(KERN_DEBUG "cciss: command completed\n"); #endif /* CCISS_DEBUG */ + /* unlock the data buffer from DMA */ + pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, + size, PCI_DMA_BIDIRECTIONAL); if (complete != 1) { if ( (complete & CISS_ERROR_BIT) && (complete & ~CISS_ERROR_BIT) == c->busaddr) @@ -974,7 +1004,7 @@ c->err_info->MoreErrInfo.Invalid_Cmd.offense_size, c->err_info->MoreErrInfo.Invalid_Cmd.offense_num, c->err_info->MoreErrInfo.Invalid_Cmd.offense_value); - cmd_free(info_p,c); + cmd_free(info_p,c, 1); return(IO_ERROR); } } @@ -982,7 +1012,7 @@ printk( KERN_WARNING "cciss cciss%d: SendCmd " "Invalid command list address returned! (%lx)\n", ctlr, complete); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_ERROR); } } else { @@ -990,10 +1020,10 @@ "cciss cciss%d: SendCmd Timeout out, " "No command list address returned!\n", ctlr); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_ERROR); } - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_OK); } /* @@ -1084,9 +1114,22 @@ static inline void complete_command( CommandList_struct *cmd, int timeout) { int status = 1; - + int i; + u64bit temp64; + if (timeout) status = 0; + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; iHeader.SGList; i++) + { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_unmap_single(hba[cmd->ctlr]->pdev, + temp64.val, cmd->SG[i].Len, + (cmd->Request.Type.Direction == XFER_READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } + if(cmd->err_info->CommandStatus != 0) { /* an error has occurred */ switch(cmd->err_info->CommandStatus) @@ -1221,7 +1264,12 @@ struct list_head *queue_head = &q->queue_head; struct request *creq; u64bit temp64; + struct my_sg tmp_sg[MAXSGENTRIES]; + int i; + // Loop till the queue is empty if or it is plugged + while (1) + { if (q->plugged || list_empty(queue_head)) { start_io(h); return; @@ -1231,7 +1279,7 @@ if (creq->nr_segments > MAXSGENTRIES) BUG(); - if ((h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR) || (h->ctlr > nr_ctlr)) + if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", h->ctlr, creq->rq_dev, creq); @@ -1241,7 +1289,7 @@ return; } - if (( c = cmd_alloc(h)) == NULL) + if (( c = cmd_alloc(h, 1)) == NULL) { start_io(h); return; @@ -1277,22 +1325,32 @@ sect += bh->b_size/512; if (bh->b_data == lastdataend) { // tack it on to the last segment - c->SG[seg-1].Len +=bh->b_size; + tmp_sg[seg-1].len +=bh->b_size; lastdataend += bh->b_size; } else { if (seg == MAXSGENTRIES) BUG(); - c->SG[seg].Len = bh->b_size; - temp64.val = (__u64) virt_to_bus(bh->b_data); - c->SG[seg].Addr.lower = temp64.val32.lower; - c->SG[seg].Addr.upper = temp64.val32.upper; - c->SG[0].Ext = 0; // we are not chaining + tmp_sg[seg].len = bh->b_size; + tmp_sg[seg].start_addr = bh->b_data; lastdataend = bh->b_data + bh->b_size; seg++; } bh = bh->b_reqnext; } + /* get the DMA records for the setup */ + for (i=0; iSG[i].Len = tmp_sg[i].len; + temp64.val = (__u64) pci_map_single( h->pdev, + tmp_sg[i].start_addr, + tmp_sg[i].len, + (c->Request.Type.Direction == XFER_READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + c->SG[i].Addr.lower = temp64.val32.lower; + c->SG[i].Addr.upper = temp64.val32.upper; + c->SG[i].Ext = 0; // we are not chaining + } /* track how many SG entries we are using */ if( seg > h->maxSG) h->maxSG = seg; @@ -1329,7 +1387,7 @@ h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - start_io(h); + } // while loop } static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -1373,7 +1431,7 @@ removeQ(&h->cmpQ, c); if (c->cmd_type == CMD_RWREQ) { complete_command(c, 0); - cmd_free(h, c); + cmd_free(h, c, 1); } else if (c->cmd_type == CMD_IOCTL_PEND) { c->cmd_type = CMD_IOCTL_DONE; } @@ -1427,20 +1485,18 @@ } #endif /* CCISS_DEBUG */ -static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort vendor_id, device_id, command; unchar cache_line_size, latency_timer; unchar irq, revision; uint addr[6]; __u32 board_id; - struct pci_dev *pdev; int cfg_offset; int cfg_base_addr; int cfg_base_addr_index; int i; - pdev = pci_find_slot(bus, device_fn); vendor_id = pdev->vendor; device_id = pdev->device; irq = pdev->irq; @@ -1449,7 +1505,15 @@ addr[i] = pdev->resource[i].start; if (pci_enable_device(pdev)) + { + printk(KERN_ERR "cciss: Unable to Enable PCI device\n"); return( -1); + } + if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) + { + printk(KERN_ERR "cciss: Unable to set DMA mask\n"); + return(-1); + } (void) pci_read_config_word(pdev, PCI_COMMAND,&command); (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); @@ -1566,59 +1630,6 @@ return 0; } -/* - * Scans PCI space for any controllers that this driver can control. - */ -static int cciss_pci_detect(void) -{ - - int index; - unchar bus=0, dev_fn=0; - - #define CCISS_BOARD_TYPES 2 - static int cciss_device_id[CCISS_BOARD_TYPES] = { - PCI_DEVICE_ID_COMPAQ_CISS, PCI_DEVICE_ID_COMPAQ_CISSB}; - int brdtype; - - /* search for all PCI board types that could be for this driver */ - for(brdtype=0; brdtypedevname, "cciss%d", nr_ctlr); - hba[nr_ctlr]->ctlr = nr_ctlr; - hba[nr_ctlr]->pci_bus = bus; - hba[nr_ctlr]->pci_dev_fn = dev_fn; - nr_ctlr++; - - } - } - return nr_ctlr; - -} /* * Gets information about the local volumes attached to the controller. @@ -1797,166 +1808,265 @@ kfree(size_buff); } +/* Function to find the first free pointer into our hba[] array */ +/* Returns -1 if no free entries are left. */ +static int alloc_cciss_hba(void) +{ + int i; + for(i=0; i< MAX_CTLR; i++) + { + if (hba[i] == NULL) + { + hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[i]==NULL) + { + printk(KERN_ERR "cciss: out of memory.\n"); + return (-1); + } + return (i); + } + } + printk(KERN_WARNING "cciss: This driver supports a maximum" + " of 8 controllers.\n"); + return(-1); +} + +static void free_hba(int i) +{ + kfree(hba[i]); + hba[i]=NULL; +} + /* * This is it. Find all the controllers and register them. I really hate * stealing all these major device numbers. * returns the number of block devices registered. */ -int __init cciss_init(void) +static int __init cciss_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int num_cntlrs_reg = 0; - int i,j; request_queue_t *q; + int i; + int j; - /* detect controllers */ - cciss_pci_detect(); - - if (nr_ctlr == 0) - return(num_cntlrs_reg); - - printk(KERN_INFO DRIVER_NAME "\n"); - printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr); - for(i=0;idevice, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + i = alloc_cciss_hba(); + if( i < 0 ) + return (-1); + memset(hba[i], 0, sizeof(ctlr_info_t)); + if (cciss_pci_init(hba[i], pdev) != 0) + { + free_hba(i); + return (-1); + } + sprintf(hba[i]->devname, "cciss%d", i); + hba[i]->ctlr = i; + hba[i]->pdev = pdev; + + if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) { - if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) - { - printk(KERN_ERR "cciss: Unable to get major number " - "%d for %s\n", MAJOR_NR+i, hba[i]->devname); - continue; - } - /* make sure the board interrupts are off */ - hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); - if( request_irq(hba[i]->intr, do_cciss_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) - { - printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", - hba[i]->intr, hba[i]->devname); - unregister_blkdev( MAJOR_NR+i, hba[i]->devname); - continue; - } - num_cntlrs_reg++; - hba[i]->cmd_pool_bits = (__u32*)kmalloc( - ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); - hba[i]->cmd_pool = (CommandList_struct *)kmalloc( - NR_CMDS * sizeof(CommandList_struct), - GFP_KERNEL); - hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc( - NR_CMDS * sizeof( ErrorInfo_struct), - GFP_KERNEL); - if((hba[i]->cmd_pool_bits == NULL) - || (hba[i]->cmd_pool == NULL) - || (hba[i]->errinfo_pool == NULL)) - { - nr_ctlr = i; - kfree(hba[i]->cmd_pool_bits); - kfree(hba[i]->cmd_pool); - kfree(hba[i]->errinfo_pool); - free_irq(hba[i]->intr, hba[i]); - unregister_blkdev(MAJOR_NR+i, hba[i]->devname); - num_cntlrs_reg--; - printk( KERN_ERR "cciss: out of memory"); - return(num_cntlrs_reg); - } - - /* command and error info recs zeroed out before + printk(KERN_ERR "cciss: Unable to get major number " + "%d for %s\n", MAJOR_NR+i, hba[i]->devname); + free_hba(i); + return(-1); + } + /* make sure the board interrupts are off */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + if( request_irq(hba[i]->intr, do_cciss_intr, + SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) + { + printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", + hba[i]->intr, hba[i]->devname); + unregister_blkdev( MAJOR_NR+i, hba[i]->devname); + free_hba(i); + return(-1); + } + hba[i]->cmd_pool_bits = (__u32*)kmalloc( + ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); + hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent( + hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), + &(hba[i]->cmd_pool_dhandle)); + hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent( + hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), + &(hba[i]->errinfo_pool_dhandle)); + if((hba[i]->cmd_pool_bits == NULL) + || (hba[i]->cmd_pool == NULL) + || (hba[i]->errinfo_pool == NULL)) + { + if(hba[i]->cmd_pool_bits) + kfree(hba[i]->cmd_pool_bits); + if(hba[i]->cmd_pool) + pci_free_consistent(hba[i]->pdev, + NR_CMDS * sizeof(CommandList_struct), + hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle); + if(hba[i]->errinfo_pool) + pci_free_consistent(hba[i]->pdev, + NR_CMDS * sizeof( ErrorInfo_struct), + hba[i]->errinfo_pool, + hba[i]->errinfo_pool_dhandle); + free_irq(hba[i]->intr, hba[i]); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + free_hba(i); + printk( KERN_ERR "cciss: out of memory"); + return(-1); + } + + /* Initialize the pdev driver private data. + have it point to hba[i]. */ + pdev->driver_data = hba[i]; + /* command and error info recs zeroed out before they are used */ - memset(hba[i]->cmd_pool_bits, 0, - ((NR_CMDS+31)/32)*sizeof(__u32)); + memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); #ifdef CCISS_DEBUG - printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i); + printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i); #endif /* CCISS_DEBUG */ - cciss_getgeometry(i); + cciss_getgeometry(i); - /* Turn the interrupts on so we can service requests */ - hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); + /* Turn the interrupts on so we can service requests */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); - cciss_procinit(i); + cciss_procinit(i); - q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); - q->queuedata = hba[i]; - blk_init_queue(q, do_cciss_request); - blk_queue_headactive(q, 0); - - /* fill in the other Kernel structs */ - blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; - hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes; - read_ahead[MAJOR_NR+i] = READ_AHEAD; - - /* Set the pointers to queue functions */ - q->back_merge_fn = cpq_back_merge_fn; - q->front_merge_fn = cpq_front_merge_fn; - q->merge_requests_fn = cpq_merge_requests_fn; - - - /* Fill in the gendisk data */ - hba[i]->gendisk.major = MAJOR_NR + i; - hba[i]->gendisk.major_name = "cciss"; - hba[i]->gendisk.minor_shift = NWD_SHIFT; - hba[i]->gendisk.max_p = MAX_PART; - hba[i]->gendisk.part = hba[i]->hd; - hba[i]->gendisk.sizes = hba[i]->sizes; - hba[i]->gendisk.nr_real = hba[i]->num_luns; - - /* Get on the disk list */ - hba[i]->gendisk.next = gendisk_head; - gendisk_head = &(hba[i]->gendisk); - - cciss_geninit(i); - for(j=0; jgendisk), - MKDEV(MAJOR_NR+i, j <<4), - MAX_PART, &cciss_fops, - hba[i]->drv[j].nr_blocks); - } - return(nr_ctlr); -} + q = BLK_DEFAULT_QUEUE(MAJOR_NR + i); + q->queuedata = hba[i]; + blk_init_queue(q, do_cciss_request); + blk_queue_headactive(q, 0); -EXPORT_NO_SYMBOLS; + /* fill in the other Kernel structs */ + blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; + hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes; + read_ahead[MAJOR_NR+i] = READ_AHEAD; -/* This is a bit of a hack... */ -static int __init init_cciss_module(void) -{ + /* Set the pointers to queue functions */ + q->back_merge_fn = cpq_back_merge_fn; + q->front_merge_fn = cpq_front_merge_fn; + q->merge_requests_fn = cpq_merge_requests_fn; - if (cciss_init() == 0) /* all the block dev numbers already used */ - return -EIO; /* or no controllers were found */ - return 0; + + /* Fill in the gendisk data */ + hba[i]->gendisk.major = MAJOR_NR + i; + hba[i]->gendisk.major_name = "cciss"; + hba[i]->gendisk.minor_shift = NWD_SHIFT; + hba[i]->gendisk.max_p = MAX_PART; + hba[i]->gendisk.part = hba[i]->hd; + hba[i]->gendisk.sizes = hba[i]->sizes; + hba[i]->gendisk.nr_real = hba[i]->num_luns; + + /* Get on the disk list */ + hba[i]->gendisk.next = gendisk_head; + gendisk_head = &(hba[i]->gendisk); + + cciss_geninit(i); + for(j=0; jgendisk), + MKDEV(MAJOR_NR+i, j <<4), + MAX_PART, &cciss_fops, + hba[i]->drv[j].nr_blocks); + + return(1); } -static void __exit cleanup_cciss_module(void) +static void __devexit cciss_remove_one (struct pci_dev *pdev) { + ctlr_info_t *tmp_ptr; int i; struct gendisk *g; - for(i=0; idriver_data == NULL) + { + printk( KERN_ERR "cciss: Unable to remove device \n"); + return; + } + tmp_ptr = (ctlr_info_t *) pdev->driver_data; + i = tmp_ptr->ctlr; + if (hba[i] == NULL) { - /* Turn board interrupts off */ - hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); - free_irq(hba[i]->intr, hba[i]); - iounmap((void*)hba[i]->vaddr); - unregister_blkdev(MAJOR_NR+i, hba[i]->devname); - remove_proc_entry(hba[i]->devname, proc_cciss); + printk(KERN_ERR "cciss: device appears to " + "already be removed \n"); + return; + } + /* Turn board interrupts off */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + free_irq(hba[i]->intr, hba[i]); + pdev->driver_data = NULL; + iounmap((void*)hba[i]->vaddr); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + remove_proc_entry(hba[i]->devname, proc_cciss); + - /* remove it from the disk list */ - if (gendisk_head == &(hba[i]->gendisk)) - { - gendisk_head = hba[i]->gendisk.next; - } else + /* remove it from the disk list */ + if (gendisk_head == &(hba[i]->gendisk)) + { + gendisk_head = hba[i]->gendisk.next; + } else + { + for(g=gendisk_head; g ; g=g->next) { - for(g=gendisk_head; g ; g=g->next) + if(g->next == &(hba[i]->gendisk)) { - if(g->next == &(hba[i]->gendisk)) - { - g->next = hba[i]->gendisk.next; - } + g->next = hba[i]->gendisk.next; } } - remove_proc_entry("driver/cciss", &proc_root); - kfree(hba[i]->cmd_pool); - kfree(hba[i]->errinfo_pool); - kfree(hba[i]->cmd_pool_bits); - kfree(hba[i]); } + pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), + hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle); + pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), + hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); + kfree(hba[i]->cmd_pool_bits); + free_hba(i); +} + +static struct pci_driver cciss_pci_driver = { + name: "cciss", + probe: cciss_init_one, + remove: cciss_remove_one, + id_table: cciss_pci_device_id, /* id_table */ +}; + +/* +* This is it. Register the PCI driver information for the cards we control +* the OS will call our registered routines when it finds one of our cards. +*/ +int __init cciss_init(void) +{ + + printk(KERN_INFO DRIVER_NAME "\n"); + /* Register for out PCI devices */ + if (pci_register_driver(&cciss_pci_driver) > 0 ) + return 0; + else + return -ENODEV; + + } + +EXPORT_NO_SYMBOLS; +static int __init init_cciss_module(void) +{ + + return ( cciss_init()); +} + +static void __exit cleanup_cciss_module(void) +{ + int i; + + pci_unregister_driver(&cciss_pci_driver); + /* double check that all controller entrys have been removed */ + for (i=0; i< MAX_CTLR; i++) + { + if (hba[i] != NULL) + { + printk(KERN_WARNING "cciss: had to remove" + " controller %d\n", i); + cciss_remove_one(hba[i]->pdev); + } + } + remove_proc_entry("cciss", proc_root_driver); } module_init(init_cciss_module); diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss.h linux/drivers/block/cciss.h --- v2.4.4/linux/drivers/block/cciss.h Fri Apr 13 20:26:07 2001 +++ linux/drivers/block/cciss.h Tue May 22 10:23:16 2001 @@ -15,6 +15,11 @@ #define MAJOR_NR COMPAQ_CISS_MAJOR +struct my_sg { + int len; + char *start_addr; +}; + struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -42,8 +47,7 @@ char devname[8]; char *product_name; char firm_ver[4]; // Firmware version - unchar pci_bus; - unchar pci_dev_fn; + struct pci_dev *pdev; __u32 board_id; ulong vaddr; __u32 paddr; @@ -70,7 +74,9 @@ //* pointers to command and error info pool */ CommandList_struct *cmd_pool; + dma_addr_t cmd_pool_dhandle; ErrorInfo_struct *errinfo_pool; + dma_addr_t errinfo_pool_dhandle; __u32 *cmd_pool_bits; int nr_allocs; int nr_frees; diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- v2.4.4/linux/drivers/block/cciss_cmd.h Fri Apr 13 20:26:07 2001 +++ linux/drivers/block/cciss_cmd.h Tue May 22 10:23:16 2001 @@ -125,20 +125,20 @@ //Command List Structure typedef union _SCSI3Addr_struct { struct { + BYTE Dev; BYTE Bus:6; BYTE Mode:2; // b00 - BYTE Dev; } PeripDev; struct { + BYTE DevLSB; BYTE DevMSB:6; BYTE Mode:2; // b01 - BYTE DevLSB; } LogDev; struct { - BYTE Targ:6; - BYTE Mode:2; // b10 BYTE Dev:5; BYTE Bus:3; + BYTE Targ:6; + BYTE Mode:2; // b10 } LogUnit; } SCSI3Addr_struct; @@ -224,6 +224,7 @@ /* information associated with the command */ __u32 busaddr; /* physical address of this record */ ErrorInfo_struct * err_info; /* pointer to the allocated mem */ + int ctlr; int cmd_type; struct _CommandList_struct *prev; struct _CommandList_struct *next; diff -u --recursive --new-file v2.4.4/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.4.4/linux/drivers/block/cpqarray.c Tue Feb 13 14:13:43 2001 +++ linux/drivers/block/cpqarray.c Tue May 22 10:23:16 2001 @@ -44,8 +44,8 @@ #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.2)" -#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,2) +#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.4)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,4) /* Embedded module documentation macros - see modules.h */ /* Original author Chris Frantz - Compaq Computer Corporation */ @@ -68,6 +68,8 @@ #define MAX_CTLR 8 #define CTLR_SHIFT 8 +#define CPQARRAY_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */ + static int nr_ctlr; static ctlr_info_t *hba[MAX_CTLR]; @@ -123,8 +125,8 @@ static void getgeometry(int ctlr); static void start_fwbk(int ctlr); -static cmdlist_t * cmd_alloc(ctlr_info_t *h); -static void cmd_free(ctlr_info_t *h, cmdlist_t *c); +static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool); +static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool); static int sendcmd( __u8 cmd, @@ -204,7 +206,7 @@ static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = proc_mkdir("driver/array", NULL); + proc_array = proc_mkdir("array", proc_root_driver); if (!proc_array) return; } @@ -228,12 +230,12 @@ ctlr = h->ctlr; size = sprintf(buffer, "%s: Compaq %s Controller\n" - " Board ID: %08lx\n" + " Board ID: 0x%08lx\n" " Firmware Revision: %c%c%c%c\n" - " Controller Sig: %08lx\n" - " Memory Address: %08lx\n" - " I/O Port: %04x\n" - " IRQ: %x\n" + " Controller Sig: 0x%08lx\n" + " Memory Address: 0x%08lx\n" + " I/O Port: 0x%04x\n" + " IRQ: %d\n" " Logical drives: %d\n" " Physical drives: %d\n\n" " Current Q depth: %d\n" @@ -314,7 +316,7 @@ int i; struct gendisk *g; - remove_proc_entry("driver/array", NULL); + remove_proc_entry("array", proc_root_driver); for(i=0; iaccess.set_intr_mask(hba[i], 0); @@ -324,7 +326,9 @@ del_timer(&hba[i]->timer); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i)); remove_proc_entry(hba[i]->devname, proc_array); - kfree(hba[i]->cmd_pool); + pci_free_consistent(hba[i]->pci_dev, + NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool), + hba[i]->cmd_pool_dhandle); kfree(hba[i]->cmd_pool_bits); if (gendisk_head == &ida_gendisk[i]) { @@ -474,8 +478,9 @@ continue; } num_cntlrs_reg++; - hba[i]->cmd_pool = (cmdlist_t *)kmalloc( - NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL); + hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent( + hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), + &(hba[i]->cmd_pool_dhandle)); hba[i]->cmd_pool_bits = (__u32*)kmalloc( ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); @@ -485,7 +490,10 @@ if(hba[i]->cmd_pool_bits) kfree(hba[i]->cmd_pool_bits); if(hba[i]->cmd_pool) - kfree(hba[i]->cmd_pool); + pci_free_consistent(hba[i]->pci_dev, + NR_CMDS * sizeof(cmdlist_t), + hba[i]->cmd_pool, + hba[i]->cmd_pool_dhandle); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); num_cntlrs_reg--; @@ -580,9 +588,11 @@ pdev = pci_find_device(ida_vendor_id[brdtype], ida_device_id[brdtype], NULL); while (pdev) { - printk(KERN_DEBUG "cpqarray: Device %x has been found at %x %x\n", + printk(KERN_DEBUG "cpqarray: Device 0x%x has" + " been found at bus %d dev %d func %d\n", ida_vendor_id[brdtype], - pdev->bus->number, pdev->devfn); + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); if (nr_ctlr == 8) { printk(KERN_WARNING "cpqarray: This driver" " supports a maximum of 8 controllers.\n"); @@ -647,7 +657,15 @@ addr[i] = pci_resource_start(pdev, i); if (pci_enable_device(pdev)) + { + printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n"); + return -1; + } + if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) + { + printk(KERN_ERR "cpqarray: Unable to set DMA mask\n"); return -1; + } pci_read_config_word(pdev, PCI_COMMAND, &command); pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); @@ -905,7 +923,12 @@ struct list_head * queue_head = &q->queue_head; struct buffer_head *bh; struct request *creq; + struct my_sg tmp_sg[SG_MAX]; + int i; +// Loop till the queue is empty if or it is plugged + while (1) +{ if (q->plugged || list_empty(queue_head)) { start_io(h); return; @@ -925,7 +948,7 @@ return; } - if ((c = cmd_alloc(h)) == NULL) + if ((c = cmd_alloc(h,1)) == NULL) { start_io(h); return; @@ -951,18 +974,28 @@ while(bh) { sect += bh->b_size/512; if (bh->b_data == lastdataend) { - c->req.sg[seg-1].size += bh->b_size; + tmp_sg[seg-1].size += bh->b_size; lastdataend += bh->b_size; } else { if (seg == SG_MAX) BUG(); - c->req.sg[seg].size = bh->b_size; - c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data); + tmp_sg[seg].size = bh->b_size; + tmp_sg[seg].start_addr = bh->b_data; lastdataend = bh->b_data + bh->b_size; seg++; } bh = bh->b_reqnext; } + /* Now do all the DMA Mappings */ + for( i=0; i < seg; i++) + { + c->req.sg[i].size = tmp_sg[i].size; + c->req.sg[i].addr = (__u32) pci_map_single( + h->pci_dev, tmp_sg[i].start_addr, + tmp_sg[i].size, + (creq->cmd == READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); c->req.hdr.sg_cnt = seg; c->req.hdr.blk_cnt = sect; @@ -993,8 +1026,7 @@ h->Qdepth++; if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - - start_io(h); + } // while loop } /* @@ -1043,6 +1075,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) { int ok=1; + int i; if (cmd->req.hdr.rcode & RCODE_NONFATAL && (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) { @@ -1063,6 +1096,13 @@ ok = 0; } if (timeout) ok = 0; + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; ireq.hdr.sg_cnt; i++) + { + pci_unmap_single(hba[cmd->ctlr]->pci_dev, + cmd->req.sg[i].addr, cmd->req.sg[i].size, + (cmd->req.hdr.cmd == IDA_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } complete_buffers(cmd->bh, ok); } @@ -1110,7 +1150,7 @@ removeQ(&h->cmpQ, c); if (c->type == CMD_RWREQ) { complete_command(c, 0); - cmd_free(h, c); + cmd_free(h, c, 1); } else if (c->type == CMD_IOCTL_PEND) { c->type = CMD_IOCTL_DONE; } @@ -1243,7 +1283,7 @@ unsigned long flags; int error; - if ((c = cmd_alloc(NULL)) == NULL) + if ((c = cmd_alloc(h, 0)) == NULL) return -ENOMEM; c->ctlr = ctlr; c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk; @@ -1262,13 +1302,16 @@ if (!p) { error = -ENOMEM; - cmd_free(NULL, c); + cmd_free(h, c, 0); return(error); } copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); - c->req.hdr.blk = virt_to_bus(&(io->c)); + c->req.hdr.blk = pci_map_single(h->pci_dev, &(io->c), + sizeof(ida_ioctl_t), + PCI_DMA_BIDIRECTIONAL); c->req.sg[0].size = io->sg[0].size; - c->req.sg[0].addr = virt_to_bus(p); + c->req.sg[0].addr = pci_map_single(h->pci_dev, p, + c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); c->req.hdr.sg_cnt = 1; break; case IDA_READ: @@ -1276,12 +1319,13 @@ if (!p) { error = -ENOMEM; - cmd_free(NULL, c); + cmd_free(h, c, 0); return(error); } c->req.sg[0].size = io->sg[0].size; - c->req.sg[0].addr = virt_to_bus(p); + c->req.sg[0].addr = pci_map_single(h->pci_dev, p, + c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); c->req.hdr.sg_cnt = 1; break; case IDA_WRITE: @@ -1291,20 +1335,22 @@ if (!p) { error = -ENOMEM; - cmd_free(NULL, c); + cmd_free(h, c, 0); return(error); } copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); c->req.sg[0].size = io->sg[0].size; - c->req.sg[0].addr = virt_to_bus(p); + c->req.sg[0].addr = pci_map_single(h->pci_dev, p, + c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); c->req.hdr.sg_cnt = 1; break; default: c->req.sg[0].size = sizeof(io->c); - c->req.sg[0].addr = virt_to_bus(&io->c); + c->req.sg[0].addr = pci_map_single(h->pci_dev,&io->c, + c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); c->req.hdr.sg_cnt = 1; } - + /* Put the request on the tail of the request queue */ spin_lock_irqsave(&io_request_lock, flags); addQ(&h->reqQ, c); @@ -1316,9 +1362,15 @@ while(c->type != CMD_IOCTL_DONE) schedule(); + /* Unmap the DMA */ + pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size, + PCI_DMA_BIDIRECTIONAL); /* Post submit processing */ switch(io->cmd) { case PASSTHRU_A: + pci_unmap_single(h->pci_dev, c->req.hdr.blk, + sizeof(ida_ioctl_t), + PCI_DMA_BIDIRECTIONAL); case IDA_READ: case DIAG_PASS_THRU: copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size); @@ -1332,7 +1384,7 @@ } io->rcode = c->req.hdr.rcode; - cmd_free(NULL, c); + cmd_free(h, c, 0); return(0); } @@ -1342,13 +1394,15 @@ * critical (and can wait for kmalloc and possibly sleep) can pass in NULL * as the first argument to get a new command. */ -static cmdlist_t * cmd_alloc(ctlr_info_t *h) +static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool) { cmdlist_t * c; int i; + dma_addr_t cmd_dhandle; - if (h == NULL) { - c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL); + if (!get_from_pool) { + c = (cmdlist_t*)pci_alloc_consistent(h->pci_dev, + sizeof(cmdlist_t), &cmd_dhandle); if(c==NULL) return NULL; } else { @@ -1358,20 +1412,22 @@ return NULL; } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0); c = h->cmd_pool + i; + cmd_dhandle = h->cmd_pool_dhandle + i*sizeof(cmdlist_t); h->nr_allocs++; } memset(c, 0, sizeof(cmdlist_t)); - c->busaddr = virt_to_bus(c); + c->busaddr = cmd_dhandle; return c; } -static void cmd_free(ctlr_info_t *h, cmdlist_t *c) +static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool) { int i; - if (h == NULL) { - kfree(c); + if (!got_from_pool) { + pci_free_consistent(h->pci_dev, sizeof(cmdlist_t), c, + c->busaddr); } else { i = c - h->cmd_pool; clear_bit(i%32, h->cmd_pool_bits+(i/32)); @@ -1400,7 +1456,7 @@ unsigned long i; ctlr_info_t *info_p = hba[ctlr]; - c = cmd_alloc(info_p); + c = cmd_alloc(info_p, 1); if(!c) return IO_ERROR; c->ctlr = ctlr; @@ -1424,7 +1480,8 @@ c->req.hdr.blk = blk; c->req.hdr.blk_cnt = blkcnt; c->req.hdr.cmd = (unsigned char) cmd; - c->req.sg[0].addr = (__u32) virt_to_bus(buff); + c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, + buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); /* * Disable interrupt */ @@ -1447,13 +1504,16 @@ */ info_p->access.submit_command(info_p, c); complete = pollcomplete(ctlr); + + pci_unmap_single(info_p->pci_dev, (dma_addr_t) c->req.sg[0].addr, + c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); if (complete != 1) { if (complete != c->busaddr) { printk( KERN_WARNING "cpqarray ida%d: idaSendPciCmd " "Invalid command list address returned! (%08lx)\n", ctlr, (unsigned long)complete); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_ERROR); } } else { @@ -1461,7 +1521,7 @@ "cpqarray ida%d: idaSendPciCmd Timeout out, " "No command list address returned!\n", ctlr); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_ERROR); } @@ -1473,11 +1533,11 @@ "cmd: 0x%x, return code = 0x%x\n", ctlr, c->req.hdr.cmd, c->req.hdr.rcode); - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_ERROR); } } - cmd_free(info_p, c); + cmd_free(info_p, c, 1); return (IO_OK); } @@ -1574,13 +1634,9 @@ max_p = gdev->max_p; start = target << gdev->minor_shift; - for(i=max_p; i>=0; i--) { + for(i=max_p-1; i>=0; i--) { int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.4.4/linux/drivers/block/cpqarray.h Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/cpqarray.h Tue May 22 10:23:16 2001 @@ -56,6 +56,11 @@ #ifdef __KERNEL__ +struct my_sg { + int size; + char *start_addr; +}; + struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -104,6 +109,7 @@ cmdlist_t *reqQ; cmdlist_t *cmpQ; cmdlist_t *cmd_pool; + dma_addr_t cmd_pool_dhandle; __u32 *cmd_pool_bits; unsigned int Qdepth; diff -u --recursive --new-file v2.4.4/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.4.4/linux/drivers/block/genhd.c Sun Sep 17 23:16:35 2000 +++ linux/drivers/block/genhd.c Wed May 16 14:01:32 2001 @@ -17,8 +17,6 @@ #include #include -extern int parport_init(void); -extern int chr_dev_init(void); extern int blk_dev_init(void); #ifdef CONFIG_BLK_DEV_DAC960 extern void DAC960_Initialize(void); @@ -31,12 +29,8 @@ extern int cpqarray_init(void); extern void ieee1394_init(void); -void __init device_init(void) +int __init device_init(void) { -#ifdef CONFIG_PARPORT - parport_init(); -#endif - chr_dev_init(); blk_dev_init(); sti(); #ifdef CONFIG_I2O @@ -64,4 +58,7 @@ #ifdef CONFIG_VT console_map_init(); #endif + return 0; } + +__initcall(device_init); diff -u --recursive --new-file v2.4.4/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.4.4/linux/drivers/block/nbd.c Wed Apr 11 19:02:30 2001 +++ linux/drivers/block/nbd.c Tue May 1 14:20:25 2001 @@ -5,7 +5,8 @@ * deadlocks sometimes - you can not swap over TCP in general. * * Copyright 1997-2000 Pavel Machek - * + * Parts copyright 2001 Steven Whitehouse + * * (part of code stolen from loop.c) * * 97-3-25 compiled 0-th version, not yet tested it @@ -20,6 +21,9 @@ * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines * 01-2-27 Fix to store proper blockcount for kernel (calculated using * BLOCK_SIZE_BITS, not device blocksize) + * 01-3-11 Make nbd work with new Linux block layer code. It now supports + * plugging like all the other block devices. Also added in MSG_MORE to + * reduce number of partial TCP segments sent. * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another diff -u --recursive --new-file v2.4.4/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c --- v2.4.4/linux/drivers/block/paride/pd.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/block/paride/pd.c Sat Apr 28 11:27:53 2001 @@ -589,9 +589,6 @@ { int p, unit, minor; long flags; - kdev_t devp; - - struct super_block *sb; unit = DEVICE_NR(dev); if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV; @@ -607,13 +604,7 @@ for (p=(PD_PARTNS-1);p>=0;p--) { minor = p + unit*PD_PARTNS; - devp = MKDEV(MAJOR_NR, minor); - fsync_dev(devp); - - sb = get_super(devp); - if (sb) invalidate_inodes(sb); - - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); pd_hd[minor].start_sect = 0; pd_hd[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.4.4/linux/drivers/block/ps2esdi.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/block/ps2esdi.c Thu May 24 15:14:08 2001 @@ -56,7 +56,7 @@ #include #define PS2ESDI_IRQ 14 -#define MAX_HD 1 +#define MAX_HD 2 #define MAX_RETRIES 5 #define MAX_16BIT 65536 #define ESDI_TIMEOUT 0xf000 @@ -105,14 +105,14 @@ static void ps2esdi_get_device_cfg(void); -void ps2esdi_reset_timer(unsigned long unused); +static void ps2esdi_reset_timer(unsigned long unused); -u_int dma_arb_level; /* DMA arbitration level */ +static u_int dma_arb_level; /* DMA arbitration level */ static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open); -int no_int_yet; +static int no_int_yet; static int access_count[MAX_HD]; static char ps2esdi_valid[MAX_HD]; static int ps2esdi_sizes[MAX_HD << 6]; @@ -123,26 +123,26 @@ static struct timer_list esdi_timer = { function: ps2esdi_reset_timer }; static int reset_status; static int ps2esdi_slot = -1; -int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ -int intg_esdi = 0; /* If integrated adapter */ +static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ +static int intg_esdi = 0; /* If integrated adapter */ struct ps2esdi_i_struct { unsigned int head, sect, cyl, wpcom, lzone, ctl; }; #if 0 #if 0 /* try both - I don't know which one is better... UB */ -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {4, 48, 1553, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; #else -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {64, 32, 161, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; #endif #endif -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; @@ -191,9 +191,9 @@ #ifdef MODULE -int cyl[2] = {-1,-1}; -int head[2] = {-1, -1}; -int sect[2] = {-1, -1}; +static int cyl[MAX_HD] = {-1,-1}; +static int head[MAX_HD] = {-1, -1}; +static int sect[MAX_HD] = {-1, -1}; MODULE_PARM(tp720esdi, "i"); MODULE_PARM(cyl, "i"); @@ -203,7 +203,7 @@ int init_module(void) { int drive; - for(drive = 0; drive <= 1; drive++) { + for(drive = 0; drive < MAX_HD; drive++) { struct ps2_esdi_i_struct *info = &ps2esdi_info[drive]; if (cyl[drive] != -1) { @@ -953,10 +953,10 @@ break; } if(ending != -1) { - spin_lock_irqsave(io_request_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); end_request(ending); do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR)); - spin_unlock_irqrestore(io_request_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } } /* handle interrupts */ @@ -1145,15 +1145,9 @@ for (partition = ps2esdi_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - struct super_block * sb = get_super(devp); - - sync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); - ps2esdi_gendisk.part[start + partition].start_sect = 0; - ps2esdi_gendisk.part[start + partition].nr_sects = 0; + invalidate_device(MKDEV(MAJOR_NR, minor), 1); + ps2esdi_gendisk.part[minor].start_sect = 0; + ps2esdi_gendisk.part[minor].nr_sects = 0; } grok_partitions(&ps2esdi_gendisk, target, 1<<6, @@ -1165,7 +1159,7 @@ return (0); } -void ps2esdi_reset_timer(unsigned long unused) +static void ps2esdi_reset_timer(unsigned long unused) { int status; diff -u --recursive --new-file v2.4.4/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h --- v2.4.4/linux/drivers/block/smart1,2.h Fri Jun 23 21:04:36 2000 +++ linux/drivers/block/smart1,2.h Tue May 1 16:05:00 2001 @@ -45,7 +45,7 @@ } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x08 turns them off... */ diff -u --recursive --new-file v2.4.4/linux/drivers/block/swim3.c linux/drivers/block/swim3.c --- v2.4.4/linux/drivers/block/swim3.c Tue Sep 19 08:31:53 2000 +++ linux/drivers/block/swim3.c Tue May 22 10:23:16 2001 @@ -851,7 +851,7 @@ sizeof(struct floppy_struct)); return err; } - return -ENOIOCTLCMD; + return -ENOTTY; } static int floppy_open(struct inode *inode, struct file *filp) diff -u --recursive --new-file v2.4.4/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c --- v2.4.4/linux/drivers/block/swim_iop.c Wed Feb 16 10:56:45 2000 +++ linux/drivers/block/swim_iop.c Sat May 19 17:43:05 2001 @@ -363,7 +363,7 @@ sizeof(struct floppy_struct)); return err; } - return -ENOIOCTLCMD; + return -ENOTTY; } static int floppy_open(struct inode *inode, struct file *filp) diff -u --recursive --new-file v2.4.4/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.4.4/linux/drivers/block/xd.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/block/xd.c Thu May 24 15:14:08 2001 @@ -401,13 +401,7 @@ for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - struct super_block * sb = get_super(devp); - - sync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); xd_gendisk.part[minor].start_sect = 0; xd_gendisk.part[minor].nr_sects = 0; }; @@ -1160,19 +1154,7 @@ void cleanup_module(void) { - int partition,dev,start; - devfs_unregister_blkdev(MAJOR_NR, "xd"); - for (dev = 0; dev < xd_drives; dev++) { - start = dev << xd_gendisk.minor_shift; - for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { - int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - start = dev << xd_gendisk.minor_shift; - sync_dev(devp); - invalidate_buffers(devp); - } - } xd_done(); devfs_unregister (devfs_handle); if (xd_drives) { diff -u --recursive --new-file v2.4.4/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.4/linux/drivers/cdrom/cdrom.c Thu Mar 29 11:56:07 2001 +++ linux/drivers/cdrom/cdrom.c Fri May 4 15:09:23 2001 @@ -2626,7 +2626,8 @@ static void cdrom_sysctl_unregister(void) { - unregister_sysctl_table(cdrom_sysctl_header); + if (cdrom_sysctl_header) + unregister_sysctl_table(cdrom_sysctl_header); } #endif /* CONFIG_SYSCTL */ diff -u --recursive --new-file v2.4.4/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.4.4/linux/drivers/cdrom/sbpcd.c Fri Apr 6 10:42:55 2001 +++ linux/drivers/cdrom/sbpcd.c Thu May 24 15:14:08 2001 @@ -1118,7 +1118,7 @@ return (0); } /*==========================================================================*/ -#endif 00000 +#endif /*==========================================================================*/ static int ResponseInfo(void) { diff -u --recursive --new-file v2.4.4/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.4/linux/drivers/char/Makefile Thu Apr 26 14:11:29 2001 +++ linux/drivers/char/Makefile Wed May 16 10:27:02 2001 @@ -16,7 +16,7 @@ O_TARGET := char.o -obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. diff -u --recursive --new-file v2.4.4/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.4.4/linux/drivers/char/acquirewdt.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/acquirewdt.c Sat May 19 17:43:05 2001 @@ -110,7 +110,7 @@ break; default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c --- v2.4.4/linux/drivers/char/advantechwdt.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/char/advantechwdt.c Sat May 19 17:43:05 2001 @@ -120,7 +120,7 @@ break; default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.4.4/linux/drivers/char/agp/agpgart_fe.c Wed Apr 11 19:02:30 2001 +++ linux/drivers/char/agp/agpgart_fe.c Tue May 15 01:29:34 2001 @@ -852,6 +852,9 @@ if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) { return -EFAULT; } + if ((unsigned) reserve.seg_count >= ~0U/sizeof(agp_segment)) + return -EFAULT; + client = agp_find_client_by_pid(reserve.pid); if (reserve.seg_count == 0) { diff -u --recursive --new-file v2.4.4/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.4.4/linux/drivers/char/drm/ffb_drv.c Fri Apr 13 20:15:55 2001 +++ linux/drivers/char/drm/ffb_drv.c Sun May 20 12:11:38 2001 @@ -6,7 +6,6 @@ #include "drmP.h" -#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c --- v2.4.4/linux/drivers/char/drm/fops.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/fops.c Tue May 22 10:23:16 2001 @@ -47,7 +47,10 @@ DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + if(priv == NULL) + return -ENOMEM; memset(priv, 0, sizeof(*priv)); + filp->private_data = priv; priv->uid = current->euid; priv->pid = current->pid; diff -u --recursive --new-file v2.4.4/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.4.4/linux/drivers/char/epca.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/char/epca.c Tue May 22 10:23:16 2001 @@ -876,6 +876,9 @@ /* First we read the data in from the file system into a temp buffer */ + memoff(ch); + restore_flags(flags); + if (bytesAvailable) { /* Begin bytesAvailable */ @@ -916,8 +919,6 @@ post_fep_init. --------------------------------------------------------------------- */ buf = ch->tmp_buf; - memoff(ch); - restore_flags(flags); } /* End from_user */ diff -u --recursive --new-file v2.4.4/linux/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c --- v2.4.4/linux/drivers/char/i810-tco.c Fri Dec 29 14:35:47 2000 +++ linux/drivers/char/i810-tco.c Thu May 24 15:14:08 2001 @@ -181,8 +181,10 @@ /* * Shut off the timer. */ +#ifdef CONFIG_WATCHDOG_NOWAYOUT tco_timer_stop (); timer_alive = 0; +#endif return 0; } @@ -213,7 +215,7 @@ }; switch (cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: if (copy_to_user ((struct watchdog_info *) arg, &ident, sizeof (ident))) diff -u --recursive --new-file v2.4.4/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c --- v2.4.4/linux/drivers/char/machzwd.c Thu Apr 12 12:16:35 2001 +++ linux/drivers/char/machzwd.c Tue May 22 10:23:16 2001 @@ -357,7 +357,7 @@ break; default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; diff -u --recursive --new-file v2.4.4/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.4/linux/drivers/char/mem.c Fri Apr 27 14:23:25 2001 +++ linux/drivers/char/mem.c Sat May 19 18:11:36 2001 @@ -29,9 +29,6 @@ #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif -#ifdef CONFIG_VIDEO_DEV -extern int videodev_init(void); -#endif #ifdef CONFIG_FB extern void fbmem_init(void); #endif @@ -648,8 +645,7 @@ #if defined(CONFIG_ADB) adbdev_init(); #endif -#ifdef CONFIG_VIDEO_DEV - videodev_init(); -#endif return 0; } + +__initcall(chr_dev_init); diff -u --recursive --new-file v2.4.4/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.4.4/linux/drivers/char/misc.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/char/misc.c Thu May 24 15:14:08 2001 @@ -73,7 +73,6 @@ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int ds1286_init(void); -extern int radio_init(void); extern int pmu_device_init(void); extern int tosh_init(void); @@ -261,9 +260,6 @@ #endif #ifdef CONFIG_SGI_DS1286 ds1286_init(); -#endif -#ifdef CONFIG_MISC_RADIO - radio_init(); #endif #ifdef CONFIG_PMAC_PBOOK pmu_device_init(); diff -u --recursive --new-file v2.4.4/linux/drivers/char/mixcomwd.c linux/drivers/char/mixcomwd.c --- v2.4.4/linux/drivers/char/mixcomwd.c Sun Dec 3 17:45:21 2000 +++ linux/drivers/char/mixcomwd.c Tue May 22 10:23:16 2001 @@ -165,7 +165,7 @@ mixcomwd_ping(); break; default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/char/moxa.c linux/drivers/char/moxa.c --- v2.4.4/linux/drivers/char/moxa.c Wed Dec 6 12:06:18 2000 +++ linux/drivers/char/moxa.c Tue May 22 10:23:16 2001 @@ -698,21 +698,32 @@ struct moxa_str *ch; int len, port; unsigned long flags; - unsigned char *temp; ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return (0); port = ch->port; save_flags(flags); - cli(); if (from_user) { - copy_from_user(moxaXmitBuff, buf, count); - temp = moxaXmitBuff; - } else - temp = (unsigned char *) buf; - len = MoxaPortWriteData(port, temp, count); - restore_flags(flags); + if (count > PAGE_SIZE) + count = PAGE_SIZE; + down(&moxaBuffSem); + if (copy_from_user(moxaXmitBuff, buf, count)) { + len = -EFAULT; + } else { + cli(); + len = MoxaPortWriteData(port, moxaXmitBuff, count); + restore_flags(flags); + } + up(&moxaBuffSem); + if (len < 0) + return len; + } else { + cli(); + len = MoxaPortWriteData(port, (unsigned char *) buf, count); + restore_flags(flags); + } + /********************************************* if ( !(ch->statusflags & LOWWAIT) && ((len != count) || (MoxaPortTxFree(port) <= 100)) ) diff -u --recursive --new-file v2.4.4/linux/drivers/char/mxser.c linux/drivers/char/mxser.c --- v2.4.4/linux/drivers/char/mxser.c Fri Mar 2 11:12:07 2001 +++ linux/drivers/char/mxser.c Wed May 16 10:31:27 2001 @@ -27,10 +27,11 @@ * * Copyright (C) 1999,2000 Moxa Technologies Co., LTD. * - * for : LINUX 2.0.X, 2.2.X - * date : 1999/07/22 - * version : 1.1 + * for : LINUX 2.0.X, 2.2.X, 2.4.X + * date : 2001/05/01 + * version : 1.2 * + * Fixes for C104H/PCI by Tim Hockin */ #include @@ -61,7 +62,7 @@ #include #include -#define MXSER_VERSION "1.1kern" +#define MXSER_VERSION "1.2" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -120,7 +121,7 @@ #define CI104J_ASIC_ID 5 enum { - MXSER_BOARD_C168_ISA = 1, + MXSER_BOARD_C168_ISA = 0, MXSER_BOARD_C104_ISA, MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, @@ -434,7 +435,7 @@ "mxser", info); if (retval) { restore_flags(flags); - printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]); + printk("Board %d: %s", board, mxser_brdname[hwconf->board_type]); printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq); return (retval); } @@ -455,7 +456,7 @@ unsigned int ioaddress; hwconf->board_type = board_type; - hwconf->ports = mxser_numports[board_type - 1]; + hwconf->ports = mxser_numports[board_type]; ioaddress = pci_resource_start (pdev, 2); for (i = 0; i < hwconf->ports; i++) hwconf->ioaddr[i] = ioaddress + 8 * i; @@ -544,7 +545,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -579,7 +580,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -612,21 +613,15 @@ n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo); index = 0; - b = 0; - while (b < n) { + for (b = 0; b < n; b++) { pdev = pci_find_device(mxser_pcibrds[b].vendor_id, mxser_pcibrds[b].device_id, pdev); - if (!pdev) - { - b++; - continue; - } - if (pci_enable_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].board_type - 1], - pdev->bus->number, PCI_SLOT(pdev->devfn >> 3)); + mxser_brdname[mxser_pcibrds[b].board_type], + 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 { @@ -892,29 +887,56 @@ if (from_user) down(&mxvar_tmp_buf_sem); save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; + if (from_user) { + down(&mxvar_tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; - if (from_user) { - copy_from_user(mxvar_tmp_buf, buf, c); + c -= copy_from_user(mxvar_tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); - } else + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&mxvar_tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } } - if (from_user) - up(&mxvar_tmp_buf_sem); + + cli(); if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; @@ -1352,7 +1374,7 @@ return; if (port == 0) return; - max = mxser_numports[mxsercfg[i].board_type - 1]; + max = mxser_numports[mxsercfg[i].board_type]; while (1) { irqbits = inb(port->vector) & port->vectormask; diff -u --recursive --new-file v2.4.4/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.4.4/linux/drivers/char/pc110pad.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/char/pc110pad.c Tue May 22 10:23:16 2001 @@ -766,7 +766,7 @@ current_params.tap_interval = new.tap_interval; return 0; } - return -ENOIOCTLCMD; + return -ENOTTY; } diff -u --recursive --new-file v2.4.4/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.4.4/linux/drivers/char/pcwd.c Fri Apr 6 10:42:55 2001 +++ linux/drivers/char/pcwd.c Thu May 24 15:14:08 2001 @@ -247,7 +247,7 @@ switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: i = copy_to_user((void*)arg, &ident, sizeof(ident)); @@ -506,6 +506,8 @@ char *ret; ret = kmalloc(6, GFP_KERNEL); + if(ret == NULL) + return NULL; while((count < 3) && (!found)) { outb_p(0x80, current_readport + 2); @@ -527,10 +529,8 @@ ten = send_command(0x82); hund = send_command(0x83); minor = send_command(0x84); - } - - if (found) sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); + } else sprintf(ret, "ERROR"); @@ -642,12 +642,12 @@ static void __exit pcwatchdog_exit(void) { + misc_deregister(&pcwd_miscdev); /* Disable the board */ if (revision == PCWD_REVISION_C) { outb_p(0xA5, current_readport + 3); outb_p(0xA5, current_readport + 3); } - misc_deregister(&pcwd_miscdev); if (supports_temp) misc_deregister(&temp_miscdev); diff -u --recursive --new-file v2.4.4/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.4.4/linux/drivers/char/pcxx.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/char/pcxx.c Tue May 22 10:23:16 2001 @@ -685,7 +685,6 @@ int total, remain, size, stlen; unsigned int head, tail; unsigned long flags; - /* printk("Entering pcxe_write()\n"); */ if ((ch=chan(tty))==NULL) @@ -696,6 +695,7 @@ if (from_user) { + down(&ch->tmp_buf_sem); save_flags(flags); cli(); globalwinon(ch); @@ -703,19 +703,21 @@ /* It seems to be necessary to make sure that the value is stable here somehow This is a rather odd pice of code here. */ do - { tail = bc->tout; + { + tail = bc->tout; } while (tail != bc->tout); tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); count = MIN(stlen, count); + memoff(ch); + restore_flags(flags); + if (count) if (copy_from_user(ch->tmp_buf, buf, count)) count = 0; buf = ch->tmp_buf; - memoff(ch); - restore_flags(flags); } /* @@ -763,6 +765,9 @@ } memoff(ch); restore_flags(flags); + + if(from_user) + up(&ch->tmp_buf_sem); return(total); } @@ -1587,6 +1592,7 @@ ch->txbufsize = bc->tmax + 1; ch->rxbufsize = bc->rmax + 1; ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); + init_MUTEX(&ch->tmp_buf_sem); if (!ch->tmp_buf) { printk(KERN_ERR "Unable to allocate memory for temp buffers\n"); diff -u --recursive --new-file v2.4.4/linux/drivers/char/pcxx.h linux/drivers/char/pcxx.h --- v2.4.4/linux/drivers/char/pcxx.h Tue Aug 22 15:21:54 2000 +++ linux/drivers/char/pcxx.h Tue May 22 10:23:16 2001 @@ -120,6 +120,7 @@ unchar *txptr; unchar *rxptr; unchar *tmp_buf; /* Temp buffer */ + struct semaphore tmp_buf_sem; /* ---- Termios data ---- */ ulong c_iflag; ulong c_cflag; diff -u --recursive --new-file v2.4.4/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.4.4/linux/drivers/char/ppdev.c Mon Oct 16 12:58:51 2000 +++ linux/drivers/char/ppdev.c Sat May 19 18:07:04 2001 @@ -35,17 +35,25 @@ * WCTLONIRQ on interrupt, set control lines * CLRIRQ clear (and return) interrupt count * SETTIME sets device timeout (struct timeval) - * GETTIME gets device timeout (struct timeval) + * GETTIME gets device timeout (struct timeval) + * GETMODES gets hardware supported modes (unsigned int) + * GETMODE gets the current IEEE1284 mode + * GETPHASE gets the current IEEE1284 phase + * GETFLAGS gets current (user-visible) flags + * SETFLAGS sets current (user-visible) flags * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) * * Changes: - * Added SETTIME/GETTIME ioctl, Fred Barnes 1999. + * Added SETTIME/GETTIME ioctl, Fred Barnes, 1999. * * Arnaldo Carvalho de Melo 2000/08/25 * - On error, copy_from_user and copy_to_user do not return -EFAULT, * They return the positive number of bytes *not* copied due to address * space errors. + * + * Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes , 03/01/2001. + * Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001 */ #include @@ -84,7 +92,7 @@ /* Other constants */ #define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */ -#define PP_BUFFER_SIZE 256 +#define PP_BUFFER_SIZE 1024 #define PARDEVICE_MAX 8 /* ROUND_UP macro from fs/select.c */ @@ -109,6 +117,8 @@ char * kbuffer; ssize_t bytes_read = 0; ssize_t got = 0; + struct parport *pport; + int mode; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ @@ -118,18 +128,40 @@ } kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); - if (!kbuffer) + if (!kbuffer) { return -ENOMEM; + } + pport = pp->pdev->port; + mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); while (bytes_read < count) { ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE); - got = parport_read (pp->pdev->port, kbuffer, need); + if (mode == IEEE1284_MODE_EPP) { + /* various specials for EPP mode */ + int flags = 0; + size_t (*fn)(struct parport *, void *, size_t, int); + + if (pp->flags & PP_W91284PIC) { + flags |= PARPORT_W91284PIC; + } + if (pp->flags & PP_FASTREAD) { + flags |= PARPORT_EPP_FAST; + } + if (pport->ieee1284.mode & IEEE1284_ADDR) { + fn = pport->ops->epp_read_addr; + } else { + fn = pport->ops->epp_read_data; + } + got = (*fn)(pport, kbuffer, need, flags); + } else { + got = parport_read (pport, kbuffer, need); + } if (got <= 0) { - if (!bytes_read) + if (!bytes_read) { bytes_read = got; - + } break; } @@ -141,13 +173,15 @@ bytes_read += got; if (signal_pending (current)) { - if (!bytes_read) + if (!bytes_read) { bytes_read = -EINTR; + } break; } - if (current->need_resched) + if (current->need_resched) { schedule (); + } } kfree (kbuffer); @@ -163,6 +197,8 @@ char * kbuffer; ssize_t bytes_written = 0; ssize_t wrote; + int mode; + struct parport *pport; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ @@ -172,8 +208,11 @@ } kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); - if (!kbuffer) + if (!kbuffer) { return -ENOMEM; + } + pport = pp->pdev->port; + mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); while (bytes_written < count) { ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE); @@ -183,24 +222,38 @@ break; } - wrote = parport_write (pp->pdev->port, kbuffer, n); + if ((pp->flags & PP_FASTWRITE) && (mode == IEEE1284_MODE_EPP)) { + /* do a fast EPP write */ + if (pport->ieee1284.mode & IEEE1284_ADDR) { + wrote = pport->ops->epp_write_addr (pport, + kbuffer, n, PARPORT_EPP_FAST); + } else { + wrote = pport->ops->epp_write_data (pport, + kbuffer, n, PARPORT_EPP_FAST); + } + } else { + wrote = parport_write (pp->pdev->port, kbuffer, n); + } if (wrote <= 0) { - if (!bytes_written) + if (!bytes_written) { bytes_written = wrote; + } break; } bytes_written += wrote; if (signal_pending (current)) { - if (!bytes_written) + if (!bytes_written) { bytes_written = -EINTR; + } break; } - if (current->need_resched) + if (current->need_resched) { schedule (); + } } kfree (kbuffer); @@ -276,7 +329,9 @@ struct parport * port; /* First handle the cases that don't take arguments. */ - if (cmd == PPCLAIM) { + switch (cmd) { + case PPCLAIM: + { struct ieee1284_info *info; if (pp->flags & PP_CLAIMED) { @@ -288,8 +343,9 @@ /* Deferred device registration. */ if (!pp->pdev) { int err = register_device (minor, pp); - if (err) + if (err) { return err; + } } parport_claim_or_block (pp->pdev); @@ -307,9 +363,8 @@ info->phase = pp->state.phase; return 0; - } - - if (cmd == PPEXCL) { + } + case PPEXCL: if (pp->pdev) { printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; " "already registered\n", minor); @@ -324,9 +379,8 @@ * when we finally do the registration. */ pp->flags |= PP_EXCL; return 0; - } - - if (cmd == PPSETMODE) { + case PPSETMODE: + { int mode; if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; @@ -340,20 +394,82 @@ } return 0; - } + } + case PPGETMODE: + { + int mode; - if (cmd == PPSETPHASE) { + if (pp->flags & PP_CLAIMED) { + mode = pp->pdev->port->ieee1284.mode; + } else { + mode = pp->state.mode; + } + if (copy_to_user ((int *)arg, &mode, sizeof (mode))) { + return -EFAULT; + } + return 0; + } + case PPSETPHASE: + { int phase; - if (copy_from_user (&phase, (int *) arg, sizeof (phase))) + if (copy_from_user (&phase, (int *) arg, sizeof (phase))) { return -EFAULT; + } /* FIXME: validate phase */ pp->state.phase = phase; - if (pp->flags & PP_CLAIMED) + if (pp->flags & PP_CLAIMED) { pp->pdev->port->ieee1284.phase = phase; + } return 0; - } + } + case PPGETPHASE: + { + int phase; + + if (pp->flags & PP_CLAIMED) { + phase = pp->pdev->port->ieee1284.phase; + } else { + phase = pp->state.phase; + } + if (copy_to_user ((int *)arg, &phase, sizeof (phase))) { + return -EFAULT; + } + return 0; + } + case PPGETMODES: + { + unsigned int modes; + + modes = pp->pdev->port->modes; + if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) { + return -EFAULT; + } + return 0; + } + case PPSETFLAGS: + { + int uflags; + + if (copy_from_user (&uflags, (int *)arg, sizeof (uflags))) { + return -EFAULT; + } + pp->flags &= ~PP_FLAGMASK; + pp->flags |= (uflags & PP_FLAGMASK); + return 0; + } + case PPGETFLAGS: + { + int uflags; + + uflags = pp->flags & PP_FLAGMASK; + if (copy_to_user ((int *)arg, &uflags, sizeof (uflags))) { + return -EFAULT; + } + return 0; + } + } /* end switch() */ /* Everything else requires the port to be claimed, so check * that now. */ @@ -537,13 +653,28 @@ { unsigned int minor = MINOR (inode->i_rdev); struct pp_struct *pp = file->private_data; + int compat_negot; lock_kernel(); - if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) { - if (!(pp->flags & PP_CLAIMED)) { - parport_claim_or_block (pp->pdev); - pp->flags |= PP_CLAIMED; - } + compat_negot = 0; + if (!(pp->flags & PP_CLAIMED) && pp->pdev && + (pp->state.mode != IEEE1284_MODE_COMPAT)) { + struct ieee1284_info *info; + + /* parport released, but not in compatability mode */ + parport_claim_or_block (pp->pdev); + pp->flags |= PP_CLAIMED; + info = &pp->pdev->port->ieee1284; + pp->saved_state.mode = info->mode; + pp->saved_state.phase = info->phase; + info->mode = pp->state.mode; + info->phase = pp->state.phase; + compat_negot = 1; + } else if ((pp->flags & PP_CLAIMED) && pp->pdev && + (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT)) { + compat_negot = 2; + } + if (compat_negot) { parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT); printk (KERN_DEBUG CHRDEV "%x: negotiated back to compatibility mode because " @@ -551,9 +682,18 @@ } if (pp->flags & PP_CLAIMED) { + struct ieee1284_info *info; + + info = &pp->pdev->port->ieee1284; + pp->state.mode = info->mode; + pp->state.phase = info->phase; + info->mode = pp->saved_state.mode; + info->phase = pp->saved_state.phase; parport_release (pp->pdev); - printk (KERN_DEBUG CHRDEV "%x: released pardevice because " - "user-space forgot\n", minor); + if (compat_negot != 1) { + printk (KERN_DEBUG CHRDEV "%x: released pardevice " + "because user-space forgot\n", minor); + } } if (pp->pdev) { diff -u --recursive --new-file v2.4.4/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.4.4/linux/drivers/char/random.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/char/random.c Tue May 1 16:05:00 2001 @@ -610,7 +610,7 @@ static void batch_entropy_process(void *private_); /* note: the size must be a power of 2 */ -static int batch_entropy_init(int size, struct entropy_store *r) +static int __init batch_entropy_init(int size, struct entropy_store *r) { batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL); if (!batch_entropy_pool) diff -u --recursive --new-file v2.4.4/linux/drivers/char/raw.c linux/drivers/char/raw.c --- v2.4.4/linux/drivers/char/raw.c Fri Apr 27 14:23:25 2001 +++ linux/drivers/char/raw.c Sun May 20 11:34:05 2001 @@ -131,7 +131,7 @@ */ sector_size = 512; - if (get_super(rdev) != NULL) { + if (is_mounted(rdev)) { if (blksize_size[MAJOR(rdev)]) sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)]; } else { diff -u --recursive --new-file v2.4.4/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.4.4/linux/drivers/char/riscom8.c Thu Jan 4 12:50:12 2001 +++ linux/drivers/char/riscom8.c Wed May 16 10:31:27 2001 @@ -1217,33 +1217,58 @@ if (!tty || !port->xmit_buf || !tmp_buf) return 0; - if (from_user) + save_flags(flags); + if (from_user) { down(&tmp_buf_sem); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) + break; - save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) - break; + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } - if (from_user) { - copy_from_user(tmp_buf, buf, c); + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); - } else + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(port->xmit_buf + port->xmit_head, buf, c); - port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - port->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } } - if (from_user) - up(&tmp_buf_sem); + + cli(); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; @@ -1251,6 +1276,7 @@ rc_out(bp, CD180_IER, port->IER); } restore_flags(flags); + return total; } diff -u --recursive --new-file v2.4.4/linux/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c --- v2.4.4/linux/drivers/char/sbc60xxwdt.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/sbc60xxwdt.c Tue May 22 10:23:16 2001 @@ -16,6 +16,7 @@ * * 12/4 - 2000 [Initial revision] * 25/4 - 2000 Added /dev/watchdog support + * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success * * * Theory of operation: @@ -178,6 +179,7 @@ /* Well, anyhow someone wrote to us, we should return that favour */ next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; } return 0; } @@ -241,7 +243,7 @@ switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; case WDIOC_KEEPALIVE: diff -u --recursive --new-file v2.4.4/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.4/linux/drivers/char/serial.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/char/serial.c Sun May 20 12:11:38 2001 @@ -565,9 +565,12 @@ icount = &info->state->icount; do { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.tqueue.routine((void *) tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + return; // if TTY_DONT_FLIP is set + } ch = serial_inp(info, UART_RX); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -657,7 +660,9 @@ tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; } +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ignore_char: +#endif *status = serial_inp(info, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); #if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ diff -u --recursive --new-file v2.4.4/linux/drivers/char/serial167.c linux/drivers/char/serial167.c --- v2.4.4/linux/drivers/char/serial167.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/char/serial167.c Wed May 16 10:31:27 2001 @@ -1247,36 +1247,54 @@ return 0; } - while (1) { - save_flags(flags); cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0){ - restore_flags(flags); - break; - } - - if (from_user) { + if (from_user) { down(&tmp_buf_sem); - if (copy_from_user(tmp_buf, buf, c)) { - up(&tmp_buf_sem); - restore_flags(flags); - return 0; + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; } - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); up(&tmp_buf_sem); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; - } + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + } if (info->xmit_cnt && !tty->stopped diff -u --recursive --new-file v2.4.4/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.4.4/linux/drivers/char/softdog.c Tue Feb 13 14:13:43 2001 +++ linux/drivers/char/softdog.c Sat May 19 17:43:05 2001 @@ -132,7 +132,7 @@ }; switch (cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) return -EFAULT; diff -u --recursive --new-file v2.4.4/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.4.4/linux/drivers/char/specialix.c Wed Dec 6 12:06:18 2000 +++ linux/drivers/char/specialix.c Wed May 16 10:31:27 2001 @@ -1611,33 +1611,56 @@ if (!tty || !port->xmit_buf || !tmp_buf) return 0; - if (from_user) + save_flags(flags); + if (from_user) { down(&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) + break; - save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) - break; + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } - if (from_user) { - copy_from_user(tmp_buf, buf, c); + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); - } else + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } memcpy(port->xmit_buf + port->xmit_head, buf, c); - port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - port->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } } - if (from_user) - up(&tmp_buf_sem); + + cli(); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; diff -u --recursive --new-file v2.4.4/linux/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.4.4/linux/drivers/char/synclink.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/char/synclink.c Tue May 1 16:05:00 2001 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -107,8 +107,12 @@ #endif #ifdef CONFIG_SYNCLINK_SYNCPPP +#if LINUX_VERSION_CODE < VERSION(2,4,3) +#include "../net/wan/syncppp.h" +#else #include #endif +#endif #include #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -176,6 +180,14 @@ int cts_down; }; +/* transmit holding buffer definitions*/ +#define MAX_TX_HOLDING_BUFFERS 5 +struct tx_holding_buffer { + int buffer_size; + unsigned char * buffer; +}; + + /* * Device instance data structure */ @@ -241,11 +253,21 @@ DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ unsigned int current_rx_buffer; + int num_tx_dma_buffers; /* number of tx dma frames required */ + int tx_dma_buffers_used; unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ + int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */ + int current_tx_buffer; /* next tx dma buffer to be loaded */ unsigned char *intermediate_rxbuffer; + int num_tx_holding_buffers; /* number of tx holding buffer allocated */ + int get_tx_holding_index; /* next tx holding buffer for adapter to load */ + int put_tx_holding_index; /* next tx holding buffer to store user request */ + int tx_holding_count; /* number of tx holding buffers waiting */ + struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; + int rx_enabled; int rx_overflow; @@ -685,6 +707,8 @@ #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b))) #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) +#define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) + void usc_process_rxoverrun_sync( struct mgsl_struct *info ); void usc_start_receiver( struct mgsl_struct *info ); void usc_stop_receiver( struct mgsl_struct *info ); @@ -775,7 +799,10 @@ */ void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); int mgsl_get_rx_frame( struct mgsl_struct *info ); +int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); +int num_free_tx_dma_buffers(struct mgsl_struct *info); void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); @@ -790,6 +817,10 @@ void mgsl_free_buffer_list_memory(struct mgsl_struct *info); int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); +int load_next_tx_holding_buffer(struct mgsl_struct *info); +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* * Bottom half interrupt handlers @@ -810,6 +841,7 @@ void mgsl_isr_io_pin( struct mgsl_struct *info ); void mgsl_isr_misc( struct mgsl_struct *info ); void mgsl_isr_receive_dma( struct mgsl_struct *info ); +void mgsl_isr_transmit_dma( struct mgsl_struct *info ); typedef void (*isr_dispatch_func)(struct mgsl_struct *); @@ -874,6 +906,8 @@ static int debug_level = 0; static int maxframe[MAX_TOTAL_DEVICES] = {0,}; static int dosyncppp[MAX_TOTAL_DEVICES] = {0,}; +static int txdmabufs[MAX_TOTAL_DEVICES] = {0,}; +static int txholdbufs[MAX_TOTAL_DEVICES] = {0,}; MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); @@ -884,9 +918,11 @@ MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "3.2"; +static char *driver_version = "3.8"; static int __init synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -1096,11 +1132,14 @@ void mgsl_bh_receive(struct mgsl_struct *info) { + int (*get_rx_frame)(struct mgsl_struct *info) = + (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); + if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_receive(%s)\n", __FILE__,__LINE__,info->device_name); - while( mgsl_get_rx_frame(info) ); + while( (get_rx_frame)(info) ); } void mgsl_bh_transmit(struct mgsl_struct *info) @@ -1318,11 +1357,6 @@ #endif } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & MISCSTATUS_DCD_LATCHED)) - hardpps(); -#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -1609,6 +1643,58 @@ } /* end of mgsl_isr_receive_dma() */ +/* mgsl_isr_transmit_dma() + * + * This function services a transmit DMA channel interrupt. + * + * For this driver there is one source of transmit DMA interrupts + * as identified in the Transmit DMA Mode Register (TDMR): + * + * BIT2 EOB End of Buffer. This interrupt occurs when a + * transmit DMA buffer has been emptied. + * + * The driver maintains enough transmit DMA buffers to hold at least + * one max frame size transmit frame. When operating in a buffered + * transmit mode, there may be enough transmit DMA buffers to hold at + * least two or more max frame size frames. On an EOB condition, + * determine if there are any queued transmit buffers and copy into + * transmit DMA buffers if we have room. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_transmit_dma( struct mgsl_struct *info ) +{ + u16 status; + + /* clear interrupt pending and IUS bit for Tx DMA IRQ */ + usc_OutDmaReg(info, CDIR, BIT8+BIT0 ); + + /* Read the transmit DMA status to identify interrupt type. */ + /* This also clears the status bits. */ + + status = usc_InDmaReg( info, TDMR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n", + __FILE__,__LINE__,info->device_name,status); + + if ( status & BIT2 ) { + --info->tx_dma_buffers_used; + + /* if there are transmit frames queued, + * try to load the next one + */ + if ( load_next_tx_holding_buffer(info) ) { + /* if call returns non-zero value, we have + * at least one free tx holding buffer + */ + info->pending_bh |= BH_TRANSMIT; + } + } + +} /* end of mgsl_isr_transmit_dma() */ + /* mgsl_interrupt() * * Interrupt service routine entry point. @@ -1652,6 +1738,8 @@ /* Dispatch interrupt vector */ if ( UscVector ) (*UscIsrTable[UscVector])(info); + else if ( (DmaVector&(BIT10|BIT9)) == BIT10) + mgsl_isr_transmit_dma(info); else mgsl_isr_receive_dma(info); @@ -1818,7 +1906,9 @@ usc_stop_transmitter(info); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW || + info->netcount) usc_set_sync_mode(info); else usc_set_async_mode(info); @@ -1970,8 +2060,7 @@ spin_lock_irqsave(&info->irq_spinlock,flags); - if ( (info->params.mode != MGSL_MODE_HDLC) || - !info->tx_active ) { + if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) { if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; @@ -2015,8 +2104,8 @@ spin_lock_irqsave(&info->irq_spinlock,flags); if (!info->tx_active) { - if ( (info->params.mode == MGSL_MODE_HDLC) && - info->xmit_cnt ) { + if ( (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) { /* operating in synchronous (frame oriented) mode */ /* copy data from circular xmit_buf to */ /* transmit DMA buffer. */ @@ -2060,11 +2149,51 @@ if (!tty || !info->xmit_buf || !tmp_buf) goto cleanup; - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { + /* operating in synchronous (frame oriented) mode */ /* operating in synchronous (frame oriented) mode */ - if (info->tx_active) { - ret = 0; goto cleanup; + + if ( info->params.mode == MGSL_MODE_HDLC ) { + ret = 0; + goto cleanup; + } + /* transmitter is actively sending data - + * if we have multiple transmit dma and + * holding buffers, attempt to queue this + * frame for transmission at a later time. + */ + if (info->tx_holding_count >= info->num_tx_holding_buffers ) { + /* no tx holding buffers available */ + ret = 0; + goto cleanup; + } + + /* queue transmit frame request */ + ret = count; + if (from_user) { + down(&tmp_buf_sem); + COPY_FROM_USER(err,tmp_buf, buf, count); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n", + __FILE__,__LINE__,info->device_name); + ret = -EFAULT; + } else + save_tx_buffer_request(info,tmp_buf,count); + up(&tmp_buf_sem); + } + else + save_tx_buffer_request(info,buf,count); + + /* if we have sufficient tx dma buffers, + * load the next buffered tx request + */ + spin_lock_irqsave(&info->irq_spinlock,flags); + load_next_tx_holding_buffer(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto cleanup; } /* if operating in HDLC LoopMode and the adapter */ @@ -2200,7 +2329,8 @@ printk("%s(%d):mgsl_write_room(%s)=%d\n", __FILE__,__LINE__, info->device_name,ret ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) return 0; @@ -2234,10 +2364,11 @@ printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", __FILE__,__LINE__, info->device_name,info->xmit_cnt ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) - return info->tx_buffer_list[0].rcc; + return info->max_frame_size; else return 0; } @@ -2627,11 +2758,11 @@ unsigned long flags; int s; int rc=0; - u16 regval; struct mgsl_icount cprev, cnow; - int events = 0; + int events; int mask; - struct _input_signal_events signal_events_prev, signal_events_now; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); if (rc) { @@ -2644,114 +2775,99 @@ spin_lock_irqsave(&info->irq_spinlock,flags); + /* return immediately if state matches requested events */ usc_get_serial_signals(info); s = info->serial_signals; + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto exit; + } - /* note the counters on entry */ + /* save current irq counts */ cprev = info->icount; - signal_events_prev = info->input_signal_events; + oldsigs = info->input_signal_events; - if (mask & MgslEvent_ExitHuntMode) { - /* enable exit hunt mode IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_EXITED_HUNT)) - usc_OutReg(info, RICR, regval | RXSTATUS_EXITED_HUNT); + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + u16 oldreg = usc_InReg(info,RICR); + u16 newreg = oldreg + + (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) + + (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0); + if (oldreg != newreg) + usc_OutReg(info, RICR, newreg); } - if (mask & MgslEvent_IdleReceived) { - /* enable idle mode received IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_IDLE_RECEIVED)) - usc_OutReg(info, RICR, regval | RXSTATUS_IDLE_RECEIVED); - } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); spin_unlock_irqrestore(&info->irq_spinlock,flags); - /* Determine if any user requested events for input signals is currently TRUE */ - - events |= (mask & ((s & SerialSignal_DSR) ? - MgslEvent_DsrActive:MgslEvent_DsrInactive)); - - events |= (mask & ((s & SerialSignal_DCD) ? - MgslEvent_DcdActive:MgslEvent_DcdInactive)); - - events |= (mask & ((s & SerialSignal_CTS) ? - MgslEvent_CtsActive:MgslEvent_CtsInactive)); - - events |= (mask & ((s & SerialSignal_RI) ? - MgslEvent_RiActive:MgslEvent_RiInactive)); - - while(!events) { - /* sleep until event occurs */ - interruptible_sleep_on(&info->event_wait_q); - - /* see if a signal woke us */ + for(;;) { + schedule(); if (signal_pending(current)) { rc = -ERESTARTSYS; break; } + /* get current irq counts */ spin_lock_irqsave(&info->irq_spinlock,flags); - - /* get icount and serial signal states */ cnow = info->icount; - signal_events_now = info->input_signal_events; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (signal_events_now.dsr_up != signal_events_prev.dsr_up && - mask & MgslEvent_DsrActive ) - events |= MgslEvent_DsrActive; - - if (signal_events_now.dsr_down != signal_events_prev.dsr_down && - mask & MgslEvent_DsrInactive ) - events |= MgslEvent_DsrInactive; - - if (signal_events_now.dcd_up != signal_events_prev.dcd_up && - mask & MgslEvent_DcdActive ) - events |= MgslEvent_DcdActive; - - if (signal_events_now.dcd_down != signal_events_prev.dcd_down && - mask & MgslEvent_DcdInactive ) - events |= MgslEvent_DcdInactive; - - if (signal_events_now.cts_up != signal_events_prev.cts_up && - mask & MgslEvent_CtsActive ) - events |= MgslEvent_CtsActive; - - if (signal_events_now.cts_down != signal_events_prev.cts_down && - mask & MgslEvent_CtsInactive ) - events |= MgslEvent_CtsInactive; - - if (signal_events_now.ri_up != signal_events_prev.ri_up && - mask & MgslEvent_RiActive ) - events |= MgslEvent_RiActive; - - if (signal_events_now.ri_down != signal_events_prev.ri_down && - mask & MgslEvent_RiInactive ) - events |= MgslEvent_RiInactive; - - if (cnow.exithunt != cprev.exithunt) - events |= (mask & MgslEvent_ExitHuntMode); + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } - if (cnow.rxidle != cprev.rxidle) - events |= (mask & MgslEvent_IdleReceived); + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; cprev = cnow; - signal_events_prev = signal_events_now; + oldsigs = newsigs; } + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { spin_lock_irqsave(&info->irq_spinlock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - regval = usc_InReg(info,RICR); - usc_OutReg(info, RICR, regval & + usc_OutReg(info, RICR, usc_InReg(info,RICR) & ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)); } spin_unlock_irqrestore(&info->irq_spinlock,flags); } - +exit: if ( rc == 0 ) PUT_USER(rc, events, mask_ptr); @@ -2759,6 +2875,56 @@ } /* end of mgsl_wait_event() */ +static int modem_input_wait(struct mgsl_struct *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || + (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || + (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || + (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + /* get_modem_info() * * Read the state of the serial control and @@ -2926,7 +3092,7 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) { int error; - struct mgsl_icount cprev, cnow; /* kernel counter temps */ + struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ unsigned long flags; @@ -2961,37 +3127,12 @@ while(MOD_IN_USE) MOD_DEC_USE_COUNT; 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 + + /* Wait for modem input (DCD,RI,DSR,CTS) change + * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) */ case TIOCMIWAIT: - spin_lock_irqsave(&info->irq_spinlock,flags); - /* note the counters on entry */ - cprev = info->icount; - spin_unlock_irqrestore(&info->irq_spinlock,flags); - while (1) { - interruptible_sleep_on(&info->status_event_wait_q); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - save_flags(flags); cli(); - cnow = info->icount; /* atomic copy */ - restore_flags(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ + return modem_input_wait(info,(int)arg); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -3243,7 +3384,8 @@ if (timeout) char_time = MIN(char_time, timeout); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { while (info->tx_active) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); @@ -3601,7 +3743,8 @@ if (info->serial_signals & SerialSignal_RI) strcat(stat_buf, "|RI"); - if (info->params.mode == MGSL_MODE_HDLC) { + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) @@ -3742,15 +3885,15 @@ * * This leaves 62 4K pages. * - * The next N pages are used for a transmit frame. We - * reserve enough 4K page blocks to hold the configured - * MaxFrameSize + * The next N pages are used for transmit frame(s). We + * reserve enough 4K page blocks to hold the required + * number of transmit dma buffers (num_tx_dma_buffers), + * each of MaxFrameSize size. * * Of the remaining pages (62-N), determine how many can * be used to receive full MaxFrameSize inbound frames */ - - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = 62 - info->tx_buffer_count; } else { /* Calculate the number of PAGE_SIZE buffers needed for */ @@ -3763,7 +3906,7 @@ /* End of List condition if all receive buffers are used when */ /* using linked list DMA buffers. */ - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6; /* @@ -3783,12 +3926,14 @@ if ( mgsl_alloc_buffer_list_memory( info ) < 0 || mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || - mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 ) { + mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 || + mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) { printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); return -ENOMEM; } mgsl_reset_rx_dma_buffers( info ); + mgsl_reset_tx_dma_buffers( info ); return 0; @@ -4044,6 +4189,149 @@ } /* end of mgsl_free_intermediate_rxbuffer_memory() */ +/* + * mgsl_alloc_intermediate_txbuffer_memory() + * + * Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size. + * This buffer is used to load transmit frames into the adapter's dma transfer + * buffers when there is sufficient space. + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 0 if success, otherwise -ENOMEM + */ +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s %s(%d) allocating %d tx holding buffers\n", + info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers); + + memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers)); + + for ( i=0; inum_tx_holding_buffers; ++i) { + info->tx_holding_buffers[i].buffer = + kmalloc(info->max_frame_size, GFP_KERNEL); + if ( info->tx_holding_buffers[i].buffer == NULL ) + return -ENOMEM; + } + + return 0; + +} /* end of mgsl_alloc_intermediate_txbuffer_memory() */ + +/* + * mgsl_free_intermediate_txbuffer_memory() + * + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: None + */ +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + for ( i=0; inum_tx_holding_buffers; ++i ) { + if ( info->tx_holding_buffers[i].buffer ) { + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer=NULL; + } + } + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_free_intermediate_txbuffer_memory() */ + + +/* + * load_next_tx_holding_buffer() + * + * attempts to load the next buffered tx request into the + * tx dma buffers + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 1 if next buffered tx request loaded + * into adapter's tx dma buffer, + * 0 otherwise + */ +int load_next_tx_holding_buffer(struct mgsl_struct *info) +{ + int ret = 0; + + if ( info->tx_holding_count ) { + /* determine if we have enough tx dma buffers + * to accomodate the next tx frame + */ + struct tx_holding_buffer *ptx = + &info->tx_holding_buffers[info->get_tx_holding_index]; + int num_free = num_free_tx_dma_buffers(info); + int num_needed = ptx->buffer_size / DMABUFFERSIZE; + if ( ptx->buffer_size % DMABUFFERSIZE ) + ++num_needed; + + if (num_needed <= num_free) { + info->xmit_cnt = ptx->buffer_size; + mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size); + + --info->tx_holding_count; + if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers) + info->get_tx_holding_index=0; + + /* restart transmit timer */ + del_timer(&info->tx_timer); + info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + add_timer(&info->tx_timer); + + ret = 1; + } + } + + return ret; +} + +/* + * save_tx_buffer_request() + * + * attempt to store transmit frame request for later transmission + * + * Arguments: + * + * info pointer to device instance data + * Buffer pointer to buffer containing frame to load + * BufferSize size in bytes of frame in Buffer + * + * Return Value: 1 if able to store, 0 otherwise + */ +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) +{ + struct tx_holding_buffer *ptx; + + if ( info->tx_holding_count >= info->num_tx_holding_buffers ) { + return 0; /* all buffers in use */ + } + + ptx = &info->tx_holding_buffers[info->put_tx_holding_index]; + ptx->buffer_size = BufferSize; + memcpy( ptx->buffer, Buffer, BufferSize); + + ++info->tx_holding_count; + if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers) + info->put_tx_holding_index=0; + + return 1; +} + int mgsl_claim_resources(struct mgsl_struct *info) { if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { @@ -4120,7 +4408,7 @@ return 0; errout: mgsl_release_resources(info); - return ENODEV; + return -ENODEV; } /* end of mgsl_claim_resources() */ @@ -4141,6 +4429,7 @@ } mgsl_free_dma_buffers(info); mgsl_free_intermediate_rxbuffer_memory(info); + mgsl_free_intermediate_txbuffer_memory(info); if ( info->io_addr_requested ) { release_region(info->io_base,info->io_addr_size); @@ -4187,6 +4476,20 @@ if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; info->dosyncppp = dosyncppp[info->line]; + + if (txdmabufs[info->line]) { + info->num_tx_dma_buffers = txdmabufs[info->line]; + if (info->num_tx_dma_buffers < 1) + info->num_tx_dma_buffers = 1; + } + + if (txholdbufs[info->line]) { + info->num_tx_holding_buffers = txholdbufs[info->line]; + if (info->num_tx_holding_buffers < 1) + info->num_tx_holding_buffers = 1; + else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS) + info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS; + } } mgsl_device_count++; @@ -4255,6 +4558,8 @@ spin_lock_init(&info->netlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; + info->num_tx_dma_buffers = 1; + info->num_tx_holding_buffers = 0; } return info; @@ -4432,6 +4737,7 @@ unsigned long flags; int rc; struct mgsl_struct *info; + struct mgsl_struct *tmp; printk("Unloading %s: version %s\n", driver_name, driver_version); save_flags(flags); @@ -4451,7 +4757,9 @@ mgsl_sppp_delete(info); #endif mgsl_release_resources(info); + tmp = info; info = info->next_device; + kfree(tmp); } if (tmp_buf) { @@ -4691,6 +4999,27 @@ * * 0000 0110 0000 0110 = 0x0606 */ + if (info->params.mode == MGSL_MODE_RAW) { + RegValue = 0x0001; /* Set Receive mode = external sync */ + + usc_OutReg( info, IOCR, /* Set IOCR DCD is RxSync Detect Input */ + (unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12)); + + /* + * TxSubMode: + * CMR <15> 0 Don't send CRC on Tx Underrun + * CMR <14> x undefined + * CMR <13> 0 Send preamble before openning sync + * CMR <12> 0 Send 8-bit syncs, 1=send Syncs per TxLength + * + * TxMode: + * CMR <11-8) 0100 MonoSync + * + * 0x00 0100 xxxx xxxx 04xx + */ + RegValue |= 0x0400; + } + else { RegValue = 0x0606; @@ -4700,12 +5029,14 @@ RegValue |= BIT15; else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) RegValue |= BIT15 + BIT14; + } if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) RegValue |= BIT13; } - if ( info->params.flags & HDLC_FLAG_SHARE_ZERO ) + if ( info->params.mode == MGSL_MODE_HDLC && + (info->params.flags & HDLC_FLAG_SHARE_ZERO) ) RegValue |= BIT12; if ( info->params.addr_filter != 0xff ) @@ -4745,15 +5076,13 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 ); usc_OutReg( info, RMR, RegValue ); - - /* Set the Receive count Limit Register (RCLR) to 0xffff. */ /* When an opening flag of an SDLC frame is recognized the */ /* Receive Character count (RCC) is loaded with the value in */ @@ -4822,9 +5151,9 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9 + BIT8; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8); usc_OutReg( info, TMR, RegValue ); @@ -5495,7 +5824,8 @@ usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); usc_RTCmd( info, RTCmd_PurgeRxFifo ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* DMA mode Transfers */ /* Program the DMA controller. */ /* Enable the DMA controller end of buffer interrupt. */ @@ -5585,8 +5915,14 @@ /* Transmit DMA buffer is loaded, so program USC */ /* to send the frame contained in the buffers. */ + FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc; - FrameSize = info->tx_buffer_list[0].rcc; + /* if operating in Raw sync mode, reset the rcc component + * of the tx dma buffer entry, otherwise, the serial controller + * will send a closing sync char after this count. + */ + if ( info->params.mode == MGSL_MODE_RAW ) + info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0; /* Program the Transmit Character Length Register (TCLR) */ /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ @@ -5595,7 +5931,7 @@ usc_RTCmd( info, RTCmd_PurgeTxFifo ); /* Program the address of the 1st DMA Buffer Entry in linked list */ - phys_addr = info->tx_buffer_list[0].phys_entry; + phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry; usc_OutDmaReg( info, NTARL, (u16)phys_addr ); usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); @@ -5603,6 +5939,19 @@ usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); usc_EnableInterrupts( info, TRANSMIT_STATUS ); + if ( info->params.mode == MGSL_MODE_RAW && + info->num_tx_dma_buffers > 1 ) { + /* When running external sync mode, attempt to 'stream' transmit */ + /* by filling tx dma buffers as they become available. To do this */ + /* we need to enable Tx DMA EOB Status interrupts : */ + /* */ + /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */ + /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */ + + usc_OutDmaReg( info, TDIAR, BIT2|BIT3 ); + usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) ); + } + /* Initialize Transmit DMA Channel */ usc_DmaCmd( info, DmaCmd_InitTxChannel ); @@ -6026,6 +6375,9 @@ void usc_loopback_frame( struct mgsl_struct *info ) { int i; + unsigned long oldmode = info->params.mode; + + info->params.mode = MGSL_MODE_HDLC; usc_DisableMasterIrqBit( info ); @@ -6079,6 +6431,8 @@ usc_EnableMasterIrqBit(info); + info->params.mode = oldmode; + } /* end of usc_loopback_frame() */ /* usc_set_sync_mode() Programs the USC for SDLC communications. @@ -6130,6 +6484,38 @@ info->tcsr_value += usc_idle_mode; usc_OutReg(info, TCSR, info->tcsr_value); + /* + * if SyncLink WAN adapter is running in external sync mode, the + * transmitter has been set to Monosync in order to try to mimic + * a true raw outbound bit stream. Monosync still sends an open/close + * sync char at the start/end of a frame. Try to match those sync + * patterns to the idle mode set here + */ + if ( info->params.mode == MGSL_MODE_RAW ) { + unsigned char syncpat = 0; + switch( info->idle_mode ) { + case HDLC_TXIDLE_FLAGS: + syncpat = 0x7e; + break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: + syncpat = 0x55; + break; + case HDLC_TXIDLE_ZEROS: + case HDLC_TXIDLE_SPACE: + syncpat = 0x00; + break; + case HDLC_TXIDLE_ONES: + case HDLC_TXIDLE_MARK: + syncpat = 0xff; + break; + case HDLC_TXIDLE_ALT_MARK_SPACE: + syncpat = 0xaa; + break; + } + + usc_SetTransmitSyncChars(info,syncpat,syncpat); + } + } /* end of usc_set_txidle() */ /* usc_get_serial_signals() @@ -6307,6 +6693,48 @@ */ /* + * mgsl_reset_tx_dma_buffers() + * + * Set the count for all transmit buffers to 0 to indicate the + * buffer is available for use and set the current buffer to the + * first buffer. This effectively makes all buffers free and + * discards any data in buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) +{ + unsigned int i; + + for ( i = 0; i < info->tx_buffer_count; i++ ) { + *((unsigned long *)&(info->tx_buffer_list[i].count)) = 0; + } + + info->current_tx_buffer = 0; + info->start_tx_dma_buffer = 0; + info->tx_dma_buffers_used = 0; + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_reset_tx_dma_buffers() */ + +/* + * num_free_tx_dma_buffers() + * + * returns the number of free tx dma buffers available + * + * Arguments: info pointer to device instance data + * Return Value: number of free tx dma buffers + */ +int num_free_tx_dma_buffers(struct mgsl_struct *info) +{ + return info->tx_buffer_count - info->tx_dma_buffers_used; +} + +/* * mgsl_reset_rx_dma_buffers() * * Set the count for all receive buffers to DMABUFFERSIZE @@ -6392,10 +6820,11 @@ unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; DMABUFFERENTRY *pBufEntry; - unsigned int framesize; + unsigned int framesize = 0; int ReturnCode = 0; unsigned long flags; struct tty_struct *tty = info->tty; + int return_frame = 0; /* * current_rx_buffer points to the 1st buffer of the next available @@ -6451,14 +6880,20 @@ info->icount.rxabort++; else if ( status & RXSTATUS_OVERRUN ) info->icount.rxover++; - else + else { info->icount.rxcrc++; + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) + return_frame = 1; + } framesize = 0; #ifdef CONFIG_SYNCLINK_SYNCPPP info->netstats.rx_errors++; info->netstats.rx_frame_errors++; #endif - } else { + } else + return_frame = 1; + + if ( return_frame ) { /* receive frame has no errors, get frame size. * The frame size is the starting value of the RCC (which was * set to 0xffff) minus the ending value of the RCC (decremented @@ -6483,7 +6918,9 @@ MIN(framesize,DMABUFFERSIZE),0); if (framesize) { - if (framesize > info->max_frame_size) + if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && + ((framesize+1) > info->max_frame_size) ) || + (framesize > info->max_frame_size) ) info->icount.rxlong++; else { /* copy dma buffer(s) to contiguous intermediate buffer */ @@ -6491,6 +6928,7 @@ int index = StartIndex; unsigned char *ptmp = info->intermediate_rxbuffer; + if ( !(status & RXSTATUS_CRC_ERROR)) info->icount.rxok++; while(copy_count) { @@ -6509,6 +6947,18 @@ index = 0; } + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) { + ++framesize; + *ptmp = (status & RXSTATUS_CRC_ERROR ? + RX_CRC_ERROR : + RX_OK); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n", + __FILE__,__LINE__,info->device_name, + *ptmp); + } + #ifdef CONFIG_SYNCLINK_SYNCPPP if (info->netcount) { /* pass frame to syncppp device */ @@ -6518,6 +6968,7 @@ #endif { /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } } @@ -6547,6 +6998,180 @@ } /* end of mgsl_get_rx_frame() */ +/* mgsl_get_raw_rx_frame() + * + * This function attempts to return a received frame from the + * receive DMA buffers when running in external loop mode. In this mode, + * we will return at most one DMABUFFERSIZE frame to the application. + * The USC receiver is triggering off of DCD going active to start a new + * frame, and DCD going inactive to terminate the frame (similar to + * processing a closing flag character). + * + * In this routine, we will return DMABUFFERSIZE "chunks" at a time. + * If DCD goes inactive, the last Rx DMA Buffer will have a non-zero + * status field and the RCC field will indicate the length of the + * entire received frame. We take this RCC field and get the modulus + * of RCC and DMABUFFERSIZE to determine if number of bytes in the + * last Rx DMA buffer and return that last portion of the frame. + * + * Arguments: info pointer to device extension + * Return Value: 1 if frame returned, otherwise 0 + */ +int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +{ + unsigned int CurrentIndex, NextIndex; + unsigned short status; + DMABUFFERENTRY *pBufEntry; + unsigned int framesize = 0; + int ReturnCode = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + + /* + * current_rx_buffer points to the 1st buffer of the next available + * receive frame. The status field is set by the 16C32 after + * completing a receive frame. If the status field of this buffer + * is zero, either the USC is still filling this buffer or this + * is one of a series of buffers making up a received frame. + * + * If the count field of this buffer is zero, the USC is either + * using this buffer or has used this buffer. Look at the count + * field of the next buffer. If that next buffer's count is + * non-zero, the USC is still actively using the current buffer. + * Otherwise, if the next buffer's count field is zero, the + * current buffer is complete and the USC is using the next + * buffer. + */ + CurrentIndex = NextIndex = info->current_rx_buffer; + ++NextIndex; + if ( NextIndex == info->rx_buffer_count ) + NextIndex = 0; + + if ( info->rx_buffer_list[CurrentIndex].status != 0 || + (info->rx_buffer_list[CurrentIndex].count == 0 && + info->rx_buffer_list[NextIndex].count == 0)) { + /* + * Either the status field of this dma buffer is non-zero + * (indicating the last buffer of a receive frame) or the next + * buffer is marked as in use -- implying this buffer is complete + * and an intermediate buffer for this received frame. + */ + + status = info->rx_buffer_list[CurrentIndex].status; + + if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + + RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { + if ( status & RXSTATUS_SHORT_FRAME ) + info->icount.rxshort++; + else if ( status & RXSTATUS_ABORT ) + info->icount.rxabort++; + else if ( status & RXSTATUS_OVERRUN ) + info->icount.rxover++; + else + info->icount.rxcrc++; + framesize = 0; + } else { + /* + * A receive frame is available, get frame size and status. + * + * The frame size is the starting value of the RCC (which was + * set to 0xffff) minus the ending value of the RCC (decremented + * once for each receive character) minus 2 or 4 for the 16-bit + * or 32-bit CRC. + * + * If the status field is zero, this is an intermediate buffer. + * It's size is 4K. + * + * If the DMA Buffer Entry's Status field is non-zero, the + * receive operation completed normally (ie: DCD dropped). The + * RCC field is valid and holds the received frame size. + * It is possible that the RCC field will be zero on a DMA buffer + * entry with a non-zero status. This can occur if the total + * frame size (number of bytes between the time DCD goes active + * to the time DCD goes inactive) exceeds 65535 bytes. In this + * case the 16C32 has underrun on the RCC count and appears to + * stop updating this counter to let us know the actual received + * frame size. If this happens (non-zero status and zero RCC), + * simply return the entire RxDMA Buffer + */ + if ( status ) { + /* + * In the event that the final RxDMA Buffer is + * terminated with a non-zero status and the RCC + * field is zero, we interpret this as the RCC + * having underflowed (received frame > 65535 bytes). + * + * Signal the event to the user by passing back + * a status of RxStatus_CrcError returning the full + * buffer and let the app figure out what data is + * actually valid + */ + if ( info->rx_buffer_list[CurrentIndex].rcc ) + framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc; + else + framesize = DMABUFFERSIZE; + } + else + framesize = DMABUFFERSIZE; + } + + if ( framesize > DMABUFFERSIZE ) { + /* + * if running in raw sync mode, ISR handler for + * End Of Buffer events terminates all buffers at 4K. + * If this frame size is said to be >4K, get the + * actual number of bytes of the frame in this buffer. + */ + framesize = framesize % DMABUFFERSIZE; + } + + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n", + __FILE__,__LINE__,info->device_name,status,framesize); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, + MIN(framesize,DMABUFFERSIZE),0); + + if (framesize) { + /* copy dma buffer(s) to contiguous intermediate buffer */ + /* NOTE: we never copy more than DMABUFFERSIZE bytes */ + + pBufEntry = &(info->rx_buffer_list[CurrentIndex]); + memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); + info->icount.rxok++; + + /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) + tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + } + + /* Free the buffers used by this frame. */ + mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); + + ReturnCode = 1; + } + + + if ( info->rx_enabled && info->rx_overflow ) { + /* The receiver needs to restarted because of + * a receive overflow (buffer or FIFO). If the + * receive buffers are now empty, then restart receiver. + */ + + if ( !info->rx_buffer_list[CurrentIndex].status && + info->rx_buffer_list[CurrentIndex].count ) { + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_start_receiver(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + } + + return ReturnCode; + +} /* end of mgsl_get_raw_rx_frame() */ + /* mgsl_load_tx_dma_buffer() * * Load the transmit DMA buffer with the specified data. @@ -6576,12 +7201,19 @@ info->cmr_value |= BIT13; } + /* begin loading the frame in the next available tx dma + * buffer, remember it's starting location for setting + * up tx dma operation + */ + i = info->current_tx_buffer; + info->start_tx_dma_buffer = i; + /* Setup the status and RCC (Frame Size) fields of the 1st */ /* buffer entry in the transmit DMA buffer list. */ - info->tx_buffer_list[0].status = info->cmr_value & 0xf000; - info->tx_buffer_list[0].rcc = BufferSize; - info->tx_buffer_list[0].count = BufferSize; + info->tx_buffer_list[i].status = info->cmr_value & 0xf000; + info->tx_buffer_list[i].rcc = BufferSize; + info->tx_buffer_list[i].count = BufferSize; /* Copy frame data from 1st source buffer to the DMA buffers. */ /* The frame data may span multiple DMA buffers. */ @@ -6590,6 +7222,9 @@ /* Get a pointer to next DMA buffer entry. */ pBufEntry = &info->tx_buffer_list[i++]; + if ( i == info->tx_buffer_count ) + i=0; + /* Calculate the number of bytes that can be copied from */ /* the source buffer to this DMA buffer. */ if ( BufferSize > DMABUFFERSIZE ) @@ -6609,8 +7244,13 @@ /* Advance source pointer and reduce remaining data count. */ Buffer += Copycount; BufferSize -= Copycount; + + ++info->tx_dma_buffers_used; } + /* remember next available tx dma buffer */ + info->current_tx_buffer = i; + } /* end of mgsl_load_tx_dma_buffer() */ /* @@ -6741,7 +7381,7 @@ unsigned int i; char *TmpPtr; BOOLEAN rc = TRUE; - unsigned short status; + unsigned short status=0; unsigned long EndTime; unsigned long flags; MGSL_PARAMS tmp_params; @@ -6998,7 +7638,7 @@ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { - /* receive error has occurred */ + /* receive error has occured */ rc = FALSE; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , @@ -7219,7 +7859,9 @@ if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_tx_timeout(%s)\n", __FILE__,__LINE__,info->device_name); - if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + if(info->tx_active && + (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) ) { info->icount.txtimeout++; } spin_lock_irqsave(&info->irq_spinlock,flags); diff -u --recursive --new-file v2.4.4/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.4.4/linux/drivers/char/wdt.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/wdt.c Sat May 19 17:43:05 2001 @@ -311,7 +311,7 @@ switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; diff -u --recursive --new-file v2.4.4/linux/drivers/char/wdt285.c linux/drivers/char/wdt285.c --- v2.4.4/linux/drivers/char/wdt285.c Mon Oct 16 12:58:51 2000 +++ linux/drivers/char/wdt285.c Sat May 19 17:43:05 2001 @@ -136,7 +136,7 @@ switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); if (i) diff -u --recursive --new-file v2.4.4/linux/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c --- v2.4.4/linux/drivers/char/wdt_pci.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/wdt_pci.c Sat May 19 17:43:05 2001 @@ -327,7 +327,7 @@ switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.4.4/linux/drivers/i2o/i2o_block.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_block.c Tue May 1 16:12:51 2001 @@ -28,14 +28,16 @@ * Support for larger I/Os through merge* functions * (taken from DAC960 driver) * Boji T Kannanthanam: - * Reduced the timeout during RAID 5 creation. - * This is to prevent race condition when a RAID volume - * is created and immediately deleted. + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off from as + * the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the system + * gendisk list. The I2O block devices now appear in + * /proc/partitions. * * To do: * Serial number scanning to find duplicates for FC multipathing - * Remove the random timeout in the code needed for RAID 5 - * volume creation. */ #include @@ -86,7 +88,8 @@ #define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ - I2O_EVT_IND_BSA_CAPACITY_CHANGE) + I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ + I2O_EVT_IND_BSA_SCSI_SMART ) /* @@ -135,6 +138,8 @@ request_queue_t *req_queue; int max_segments; int done_flag; + int constipated; + int depth; }; /* @@ -164,7 +169,9 @@ struct i2ob_request *i2ob_qhead; request_queue_t req_queue; }; -static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL}; +static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS]; +static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS]; +static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS]; /* * Each I2O disk is one of these. @@ -179,10 +186,10 @@ * Mutex and spin lock for event handling synchronization * evt_msg contains the last event. */ -DECLARE_MUTEX(i2ob_evt_sem); +static DECLARE_MUTEX_LOCKED(i2ob_evt_sem); +static DECLARE_MUTEX_LOCKED(i2ob_thread_dead); static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; -static unsigned int evt_msg[MSG_FRAME_SIZE>>2]; -DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait); +static u32 evt_msg[MSG_FRAME_SIZE>>2]; static struct timer_list i2ob_timer; static int i2ob_timer_started = 0; @@ -195,6 +202,7 @@ static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); static void i2ob_end_request(struct request *); static void i2ob_request(request_queue_t *); +static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *); static int i2ob_init_iop(unsigned int); static request_queue_t* i2ob_get_queue(kdev_t); static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); @@ -203,6 +211,7 @@ static int evt_pid = 0; static int evt_running = 0; +static int scan_unit = 0; /* * I2O OSM registration structure...keeps getting bigger and bigger :) @@ -255,7 +264,12 @@ __raw_writel(i2ob_context|(unit<<8), msg+8); __raw_writel(ireq->num, msg+12); __raw_writel(req->nr_sectors << 9, msg+20); - + + /* + * Mask out partitions from now on + */ + unit &= 0xF0; + /* This can be optimised later - just want to be sure its right for starters */ offset = ((u64)(req->sector+base)) << 9; @@ -266,8 +280,6 @@ if(req->cmd == READ) { __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); - /* We don't yet do cache/readahead and other magic */ - __raw_writel(1<<16, msg+16); while(bh!=NULL) { if(bh->b_data == last) { @@ -293,16 +305,20 @@ count -= bh->b_size; bh = bh->b_reqnext; } + /* + * Heuristic for now since the block layer doesnt give + * us enough info. If its a big write assume sequential + * readahead on controller. If its small then don't read + * ahead but do use the controller cache. + */ + if(size >= 8192) + __raw_writel((8<<24)|(1<<16)|8, msg+16); + else + __raw_writel((8<<24)|(1<<16)|4, msg+16); } else if(req->cmd == WRITE) { __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - /* - * Allow replies to come back once data is cached in the controller - * This allows us to handle writes quickly thus giving more of the - * queue to reads. - */ - __raw_writel(0x00000010, msg+16); while(bh!=NULL) { if(bh->b_data == last) { @@ -328,13 +344,32 @@ count -= bh->b_size; bh = bh->b_reqnext; } + + if(c->battery) + { + + if(size>16384) + __raw_writel(4, msg+16); + else + /* + * Allow replies to come back once data is cached in the controller + * This allows us to handle writes quickly thus giving more of the + * queue to reads. + */ + __raw_writel(16, msg+16); + } + else + { + /* Large write, don't cache */ + if(size>8192) + __raw_writel(4, msg+16); + else + /* write through */ + __raw_writel(8, msg+16); + } } __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - if(req->current_nr_sectors > i2ob_max_sectors[unit]) - printk("Gathered sectors %ld.\n", - req->current_nr_sectors); - if(count != 0) { printk(KERN_ERR "Request count botched by %d.\n", count); @@ -434,7 +469,32 @@ return 1; } +static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit) +{ + unsigned long msg; + u32 m = i2ob_get(d); + + if(m == 0xFFFFFFFF) + return -1; + + msg = c->mem_offset + m; + /* + * Ask the controller to write the cache back. This sorts out + * the supertrak firmware flaw and also does roughly the right + * thing for other cases too. + */ + + __raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg); + __raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4); + __raw_writel(i2ob_context|(unit<<8), msg+8); + __raw_writel(0, msg+12); + __raw_writel(60<<16, msg+16); + + i2o_post_message(c,m); + return 0; +} + /* * OSM reply handler. This gets all the message replies */ @@ -447,7 +507,7 @@ u32 *m = (u32 *)msg; u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)]; - + /* * FAILed message */ @@ -482,9 +542,20 @@ if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) { spin_lock(&i2ob_evt_lock); - memcpy(&evt_msg, m, msg->size); + memcpy(evt_msg, msg, (m[0]>>16)<<2); spin_unlock(&i2ob_evt_lock); - wake_up_interruptible(&i2ob_evt_wait); + up(&i2ob_evt_sem); + return; + } + + if(msg->function == I2O_CMD_BLOCK_CFLUSH) + { + spin_lock_irqsave(&io_request_lock, flags); + dev->constipated=0; + DEBUG(("unconstipated\n")); + if(i2ob_backlog_request(c, dev)==0) + i2ob_request(dev->req_queue); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -517,6 +588,7 @@ if(st!=0) { + int err; char *bsa_errors[] = { "Success", @@ -535,12 +607,78 @@ "Volume has changed, waiting for acknowledgement" }; + err = m[4]&0xFFFF; + + /* + * Device not ready means two things. One is that the + * the thing went offline (but not a removal media) + * + * The second is that you have a SuperTrak 100 and the + * firmware got constipated. Unlike standard i2o card + * setups the supertrak returns an error rather than + * blocking for the timeout in these cases. + */ + + + spin_lock_irqsave(&io_request_lock, flags); + if(err==4) + { + /* + * Time to uncork stuff + */ + + if(!dev->constipated) + { + dev->constipated = 1; + DEBUG(("constipated\n")); + /* Now pull the chain */ + if(i2ob_flush(c, dev, unit)<0) + { + DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n")); + dev->constipated=0; + } + DEBUG(("flushing\n")); + } + + /* + * Recycle the request + */ + +// i2ob_unhook_request(ireq, c->unit); + + /* + * Place it on the recycle queue + */ + + ireq->next = NULL; + if(i2ob_backlog_tail[c->unit]!=NULL) + i2ob_backlog_tail[c->unit]->next = ireq; + else + i2ob_backlog[c->unit] = ireq; + i2ob_backlog_tail[c->unit] = ireq; + + atomic_dec(&i2ob_queues[c->unit]->queue_depth); + + /* + * If the constipator flush failed we want to + * poke the queue again. + */ + + i2ob_request(dev->req_queue); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* + * and out + */ + + return; + } + spin_unlock_irqrestore(&io_request_lock, flags); printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, bsa_errors[m[4]&0XFFFF]); if(m[4]&0x00FF0000) printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); - printk("\n"); - + printk(".\n"); ireq->req->errors++; } else @@ -559,7 +697,9 @@ /* * We may be able to do more I/O */ - i2ob_request(dev->req_queue); + + if(i2ob_backlog_request(c, dev)==0) + i2ob_request(dev->req_queue); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -575,6 +715,14 @@ unsigned int flags; int unit; int i; + //The only event that has data is the SCSI_SMART event. + struct i2o_reply { + u32 header[4]; + u32 evt_indicator; + u8 ASC; + u8 ASCQ; + u8 data[16]; + } *evt_local; lock_kernel(); daemonize(); @@ -585,15 +733,13 @@ while(1) { -#warning "RACE" - interruptible_sleep_on(&i2ob_evt_wait); - if(signal_pending(current)) { + if(down_interruptible(&i2ob_evt_sem)) + { evt_running = 0; - return 0; + printk("exiting..."); + break; } - printk(KERN_INFO "Doing something in i2o_block event thread\n"); - /* * Keep another CPU/interrupt from overwriting the * message while we're reading it @@ -602,10 +748,12 @@ * None of the BSA we care about events have EventData */ spin_lock_irqsave(&i2ob_evt_lock, flags); - unit = evt_msg[3]; - evt = evt_msg[4]; + evt_local = (struct i2o_reply *)evt_msg; spin_unlock_irqrestore(&i2ob_evt_lock, flags); + unit = evt_local->header[3]; + evt = evt_local->evt_indicator; + switch(evt) { /* @@ -675,18 +823,43 @@ break; } + /* + * We got a SCSI SMART event, we just log the relevant + * information and let the user decide what they want + * to do with the information. + */ + case I2O_EVT_IND_BSA_SCSI_SMART: + { + char buf[16]; + printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name); + evt_local->data[16]='\0'; + sprintf(buf,"%s",&evt_local->data[0]); + printk(KERN_INFO " Disk Serial#:%s\n",buf); + printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); + printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); + break; + } + + /* + * Non event + */ + + case 0: + break; + /* * An event we didn't ask for. Call the card manufacturer * and tell them to fix their firmware :) */ default: - printk(KERN_INFO "%s: Received event we didn't register for\n" - KERN_INFO " Call I2O card manufacturer\n", - i2ob_dev[unit].i2odev->dev_name); + printk(KERN_INFO "%s: Received event %d we didn't register for\n" + KERN_INFO " Blame the I2O card manufacturer 8)\n", + i2ob_dev[unit].i2odev->dev_name, evt); break; } }; + up_and_exit(&i2ob_thread_dead,0); return 0; } @@ -724,6 +897,34 @@ spin_unlock_irqrestore(&io_request_lock,flags); } +static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev) +{ + u32 m; + struct i2ob_request *ireq; + + while((ireq=i2ob_backlog[c->unit])!=NULL) + { + int unit; + + if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4) + break; + + m = i2ob_get(dev); + if(m == 0xFFFFFFFF) + break; + + i2ob_backlog[c->unit] = ireq->next; + if(i2ob_backlog[c->unit] == NULL) + i2ob_backlog_tail[c->unit] = NULL; + + unit = MINOR(ireq->req->rq_dev); + i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit); + } + if(i2ob_backlog[c->unit]) + return 1; + return 0; +} + /* * The I2O block driver is listed as one of those that pulls the * front entry off the queue before processing it. This is important @@ -731,6 +932,7 @@ * on us. We must unlink CURRENT in this routine before we return, if * we use it. */ + static void i2ob_request(request_queue_t *q) { struct request *req; @@ -738,9 +940,8 @@ int unit; struct i2ob_device *dev; u32 m; - - // printk(KERN_INFO "i2ob_request() called with queue %p\n", q); - + + while (!list_empty(&q->queue_head)) { /* * On an IRQ completion if there is an inactive @@ -760,9 +961,16 @@ * generic IOP commit control. Certainly its not right * its global! */ - if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH) + if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth) break; + + /* + * Is the channel constipated ? + */ + if(i2ob_backlog[dev->unit]!=NULL) + break; + /* Get a message */ m = i2ob_get(dev); @@ -773,7 +981,7 @@ */ if (!i2ob_timer_started) { - printk(KERN_ERR "i2ob: starting timer\n"); + DEBUG((KERN_ERR "i2ob: starting timer\n")); /* * Set the timer_started flag to insure @@ -795,6 +1003,7 @@ */ add_timer(&i2ob_timer); + return; } } @@ -804,7 +1013,7 @@ req->errors = 0; blkdev_dequeue_request(req); req->sem = NULL; - + ireq = i2ob_queues[dev->unit]->i2ob_qhead; i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; ireq->req = req; @@ -892,13 +1101,7 @@ for( i = 15; i>=0 ; i--) { int m = minor+i; - kdev_t d = MKDEV(MAJOR_NR, m); - struct super_block *sb = get_super(d); - - sync_dev(d); - if(sb) - invalidate_inodes(sb); - invalidate_buffers(d); + invalidate_device(MKDEV(MAJOR_NR, m), 1); i2ob_gendisk.part[m].start_sect = 0; i2ob_gendisk.part[m].nr_sects = 0; } @@ -1009,7 +1212,8 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Flushing..."); + i2o_post_wait(dev->controller, msg, 20, 60); /* * Unlock the media @@ -1019,14 +1223,18 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; + DEBUG("Unlocking..."); i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Unlocked.\n"); /* * Now unclaim the device. */ + if (i2o_release_device(dev->i2odev, &i2o_block_handler)) printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); - + + DEBUG("Unclaim\n"); } MOD_DEC_USE_COUNT; return 0; @@ -1055,12 +1263,14 @@ { u32 msg[6]; + DEBUG("Claim "); if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) { dev->refcnt--; printk(KERN_INFO "I2O Block: Could not open device\n"); return -EBUSY; } + DEBUG("Claimed "); /* * Mount the media if needed. Note that we don't use @@ -1072,6 +1282,7 @@ msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; msg[4] = -1; msg[5] = 0; + DEBUG("Mount "); i2o_post_wait(dev->controller, msg, 24, 2); /* @@ -1080,7 +1291,9 @@ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; msg[4] = -1; + DEBUG("Lock "); i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Ready.\n"); } MOD_INC_USE_COUNT; return 0; @@ -1132,7 +1345,8 @@ i2ob_query_device(dev, 0x0000, 5, &flags, 4); i2ob_query_device(dev, 0x0000, 6, &status, 4); i2ob_sizes[unit] = (int)(size>>10); - i2ob_hardsizes[unit] = blocksize; + for(i=unit; i <= unit+15 ; i++) + i2ob_hardsizes[i] = blocksize; i2ob_gendisk.part[unit].nr_sects = size>>9; i2ob[unit].nr_sects = (int)(size>>9); @@ -1143,20 +1357,33 @@ /* * Max number of Scatter-Gather Elements */ - i2ob_dev[unit].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; - printk(KERN_INFO "Max Segments set to %d\n", - i2ob_dev[unit].max_segments); - printk(KERN_INFO "Byte limit is %d.\n", limit); - for(i=unit;i<=unit+15;i++) { - i2ob_max_sectors[i]=MAX_SECTORS; - i2ob_dev[i].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; + if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy) + { + i2ob_max_sectors[i] = 32; + i2ob_dev[i].max_segments = 8; + i2ob_dev[i].depth = 4; + } + else if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req) + { + i2ob_max_sectors[i] = 8; + i2ob_dev[i].max_segments = 8; + } + else + { + /* MAX_SECTORS was used but 255 is a dumb number for + striped RAID */ + i2ob_max_sectors[i]=256; + i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2; + } } + printk(KERN_INFO "Max segments set to %d\n", + i2ob_dev[unit].max_segments); + printk(KERN_INFO "Byte limit is %d.\n", limit); + i2ob_query_device(dev, 0x0000, 0, &type, 1); sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); @@ -1190,6 +1417,7 @@ printk(", %dMb cache", cachesize>>10); else printk(", %dKb cache", cachesize); + } printk(".\n"); printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", @@ -1277,53 +1505,94 @@ /* * Probe the I2O subsytem for block class devices */ -static void i2ob_probe(void) +static void i2ob_scan(int bios) { int i; - int unit = 0; int warned = 0; + + struct i2o_device *d, *b=NULL; + struct i2o_controller *c; + struct i2ob_device *dev; for(i=0; i< MAX_I2O_CONTROLLERS; i++) { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; + c=i2o_find_controller(i); if(c==NULL) continue; - for(d=c->devices;d!=NULL;d=d->next) - { + /* + * 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; + + 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; if(d->lct_data.user_tid != 0xFFF) continue; + if(bios) + { + if(d->lct_data.bios_info != 0x80) + continue; + printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid); + } + else + { + if(d->lct_data.bios_info == 0x80) + continue; /*Already claimed on pass 1 */ + } + if(i2o_claim_device(d, &i2o_block_handler)) { printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit, d->lct_data.tid); - printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n"); + printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D"); continue; } - if(uniti2odev = d; dev->controller = c; dev->unit = c->unit; dev->tid = d->lct_data.tid; - if(i2ob_install_device(c,d,unit)) + if(i2ob_install_device(c,d,scan_unit)) printk(KERN_WARNING "Could not install I2O block device\n"); else { - unit+=16; + scan_unit+=16; i2ob_dev_count++; /* We want to know when device goes away */ @@ -1333,7 +1602,7 @@ else { if(!warned++) - printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4); + printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4); } i2o_release_device(d, &i2o_block_handler); } @@ -1341,6 +1610,31 @@ } } +static void i2ob_probe(void) +{ + /* + * Some overhead/redundancy involved here, while trying to + * claim the first boot volume encountered as /dev/i2o/hda + * everytime. All the i2o_controllers are searched and the + * first i2o block device marked as bootable is claimed + * If an I2O block device was booted off , the bios sets + * its bios_info field to 0x80, this what we search for. + * Assuming that the bootable volume is /dev/i2o/hda + * everytime will prevent any kernel panic while mounting + * root partition + */ + + printk(KERN_INFO "i2o_block: Checking for Boot device...\n"); + i2ob_scan(1); + + /* + * Now the remainder. + */ + printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n"); + i2ob_scan(0); +} + + /* * New device notification handler. Called whenever a new * I2O block storage device is added to the system. @@ -1369,14 +1663,6 @@ break; } - /* - * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM - * will fail if we don't give the card enough time to do it's magic, - * so we just sleep for a little while and let it do it's thing - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3*HZ); - if(i2o_claim_device(d, &i2o_block_handler)) { printk(KERN_INFO @@ -1435,6 +1721,7 @@ if(unit >= MAX_I2OB<<4) { printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -1492,8 +1779,6 @@ i2ob_media_change_flag[unit] = 1; i2ob_dev_count--; - - return; } /* @@ -1540,8 +1825,11 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); + + DEBUG("Flushing..."); + i2o_post_wait(dev->controller, msg, 20, 60); + DEBUG("Unlocking..."); /* * Unlock the media */ @@ -1551,20 +1839,21 @@ msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); + + DEBUG("Unlocked.\n"); } } } static struct block_device_operations i2ob_fops = { - open: i2ob_open, - release: i2ob_release, - ioctl: i2ob_ioctl, - check_media_change: i2ob_media_change, - revalidate: i2ob_revalidate, + open: i2ob_open, + release: i2ob_release, + ioctl: i2ob_ioctl, + check_media_change: i2ob_media_change, + revalidate: i2ob_revalidate, }; - static struct gendisk i2ob_gendisk = { MAJOR_NR, @@ -1573,9 +1862,10 @@ 1<<4, i2ob, i2ob_sizes, - 0, + MAX_I2OB, + NULL, NULL, - NULL + &i2ob_fops, }; @@ -1593,7 +1883,7 @@ int i; printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); - printk(KERN_INFO " (c) Copyright 1999, 2000 Red Hat Software.\n"); + printk(KERN_INFO " (c) Copyright 1999-2001 Red Hat Software.\n"); /* * Register the block device interfaces @@ -1629,6 +1919,7 @@ i2ob_dev[i].tid = 0; i2ob_dev[i].head = NULL; i2ob_dev[i].tail = NULL; + i2ob_dev[i].depth = MAX_I2OB_DEPTH; i2ob_blksizes[i] = 1024; i2ob_max_sectors[i] = 2; } @@ -1683,7 +1974,13 @@ register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); - + + /* + * Adding i2ob_gendisk into the gendisk list. + */ + i2ob_gendisk.next = gendisk_head; + gendisk_head = &i2ob_gendisk; + return 0; } @@ -1695,9 +1992,20 @@ void cleanup_module(void) { - struct gendisk **gdp; + struct gendisk *gdp; int i; + if(evt_running) { + printk(KERN_INFO "Killing I2O block threads..."); + i = kill_proc(evt_pid, SIGTERM, 1); + if(!i) { + printk("waiting..."); + } + /* Be sure it died */ + down(&i2ob_thread_dead); + printk("done.\n"); + } + /* * Unregister for updates from any devices..otherwise we still * get them and the core jumps to random memory :O @@ -1713,6 +2021,18 @@ } /* + * We may get further callbacks for ourself. The i2o_core + * code handles this case reasonably sanely. The problem here + * is we shouldn't get them .. but a couple of cards feel + * obliged to tell us stuff we dont care about. + * + * This isnt ideal at all but will do for now. + */ + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + + /* * Flush the OSM */ @@ -1729,28 +2049,20 @@ */ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - if(evt_running) { - i = kill_proc(evt_pid, SIGTERM, 1); - if(!i) { - int count = 5 * 100; - while(evt_running && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "Giving up on i2oblock thread...\n"); - } - } - - /* * Why isnt register/unregister gendisk in the kernel ??? */ - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == &i2ob_gendisk) - break; - + if (gendisk_head == &i2ob_gendisk) { + gendisk_head = i2ob_gendisk.next; + } + else { + for (gdp = gendisk_head; gdp; gdp = gdp->next) + if (gdp->next == &i2ob_gendisk) + { + gdp->next = i2ob_gendisk.next; + break; + } + } } #endif diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.4.4/linux/drivers/i2o/i2o_config.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_config.c Tue May 1 16:10:37 2001 @@ -42,7 +42,6 @@ static int i2o_cfg_context = -1; static void *page_buf; -static void *i2o_buffer; static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; @@ -499,6 +498,7 @@ if(!res) { i2o_unlock_controller(c); + kfree(query); return -ENOMEM; } @@ -517,16 +517,25 @@ msg[7] = 0xD4000000|(kcmd.qlen); msg[8] = virt_to_bus(query); } - - token = i2o_post_wait(c, msg, 9*4, 10); - if(token) + /* + Wait for a considerable time till the Controller + does its job before timing out. The controller might + take more time to process this request if there are + many devices connected to it. + */ + token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res); + if(token < 0) { printk(KERN_DEBUG "token = %#10x\n", token); i2o_unlock_controller(c); - kfree(res); - if(kcmd.qlen) kfree(query); + + if(token != -ETIMEDOUT) + { + kfree(res); + if(kcmd.qlen) kfree(query); + } - return -ETIMEDOUT; + return token; } i2o_unlock_controller(c); @@ -595,17 +604,18 @@ msg[8]= virt_to_bus(buffer); // printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); i2o_unlock_controller(c); - kfree(buffer); + if(status != -ETIMEDOUT) + kfree(buffer); if (status != I2O_POST_WAIT_OK) { // it fails if you try and send frags out of order // and for some yet unknown reasons too printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; + return status; } return 0; @@ -660,14 +670,15 @@ msg[8]= virt_to_bus(buffer); // printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); i2o_unlock_controller(c); if (status != I2O_POST_WAIT_OK) { - kfree(buffer); + if(status != -ETIMEDOUT) + kfree(buffer); printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; + return status; } __copy_to_user(kxfer.buf, buffer, fragsize); @@ -787,13 +798,6 @@ struct i2o_evt_get kget; unsigned int flags; - // access_ok doesn't check for NULL?!?! - if(!arg) - return -EFAULT; - - if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get))) - return -EFAULT; - for(p = open_files; p; p = p->next) if(p->q_id == id) break; @@ -812,8 +816,8 @@ kget.lost = p->q_lost; spin_unlock_irqrestore(&i2o_config_lock, flags); - __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); - + if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) + return -EFAULT; return 0; } @@ -958,8 +962,6 @@ kfree(page_buf); if(i2o_cfg_context != -1) i2o_remove_handler(&cfg_handler); - if(i2o_buffer) - kfree(i2o_buffer); } EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.4.4/linux/drivers/i2o/i2o_core.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_core.c Tue May 1 16:10:37 2001 @@ -1,5 +1,5 @@ -/* - * Core I2O structure managment +/* + * Core I2O structure management * * (C) Copyright 1999 Red Hat Software * @@ -49,7 +49,7 @@ #include "i2o_lan.h" -// #define DRIVERDEBUG +//#define DRIVERDEBUG #ifdef DRIVERDEBUG #define dprintk(s, args...) printk(s, ## args) @@ -147,10 +147,12 @@ */ struct i2o_post_wait_data { - int status; - u32 id; - wait_queue_head_t *wq; - struct i2o_post_wait_data *next; + int *status; /* Pointer to status block on caller stack */ + int *complete; /* Pointer to completion flag on caller stack */ + u32 id; /* Unique identifier */ + wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ + struct i2o_post_wait_data *next; /* Chain */ + void *mem[2]; /* Memory blocks to recover on failure path */ }; static struct i2o_post_wait_data *post_wait_queue = NULL; static u32 post_wait_id = 0; // Unique ID for each post_wait @@ -169,10 +171,10 @@ I2O_CLASS_EXECUTIVE }; - /* - * Used when queing a reply to be handled later + * Used when queueing a reply to be handled later */ + struct reply_info { struct i2o_controller *iop; @@ -199,10 +201,12 @@ static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; /* - * Semaphore used to syncrhonize event handling thread with + * Semaphore used to synchronize event handling thread with * interrupt handler. */ -DECLARE_MUTEX(evt_sem); + +static DECLARE_MUTEX(evt_sem); +static DECLARE_MUTEX_LOCKED(evt_dead); DECLARE_WAIT_QUEUE_HEAD(evt_wait); static struct notifier_block i2o_reboot_notifier = @@ -212,6 +216,12 @@ 0 }; +/* + * Config options + */ + +static int verbose = 0; +MODULE_PARM(verbose, "i"); /* * I2O Core reply handler @@ -252,7 +262,7 @@ if(msg[2]&0x80000000) // Post wait message { if (msg[4] >> 24) - status = -(msg[4] & 0xFFFF); + status = (msg[4] & 0xFFFF); else status = I2O_POST_WAIT_OK; @@ -369,6 +379,9 @@ d->controller=c; d->owner=NULL; d->next=c->devices; + d->prev=NULL; + if (c->devices != NULL) + c->devices->prev=d; c->devices=d; *d->dev_name = 0; @@ -696,7 +709,7 @@ { down(&i2o_configuration_lock); if (d->owner) { - printk(KERN_INFO "Device claim called, but dev allready owned by %s!", + printk(KERN_INFO "Device claim called, but dev already owned by %s!", h->name); up(&i2o_configuration_lock); return -EBUSY; @@ -721,37 +734,59 @@ * Drop a claim by an OSM on a given I2O device. The handler is cleared * and 0 is returned on success. * + * AC - some devices seem to want to refuse an unclaim until they have + * finished internal processing. It makes sense since you don't want a + * new device to go reconfiguring the entire system until you are done. + * Thus we are prepared to wait briefly. */ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; + int tries; down(&i2o_configuration_lock); if (d->owner != h) { - printk(KERN_INFO "Claim release called, but not owned by %s!", + printk(KERN_INFO "Claim release called, but not owned by %s!\n", h->name); up(&i2o_configuration_lock); return -ENOENT; } - d->owner = NULL; - - if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, - I2O_CLAIM_PRIMARY)) + for(tries=0;tries<10;tries++) { - err = -ENXIO; - d->owner = h; - } + d->owner = NULL; + /* + * If the controller takes a nonblocking approach to + * releases we have to sleep/poll for a few times. + */ + + if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) ) + { + err = -ENXIO; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + else + { + err=0; + break; + } + } up(&i2o_configuration_lock); return err; } -/* - * Called by OSMs to let the core know that they want to be - * notified if the given device is deleted from the system. +/** + * i2o_device_notify_on - Enable deletion notifiers + * @d: device for notification + * @h: handler to install + * + * Called by OSMs to let the core know that they want to be + * notified if the given device is deleted from the system. */ + int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) { int i; @@ -773,7 +808,11 @@ return 0; } -/* +/** + * i2o_device_notify_off - Remove deletion notifiers + * @d: device for notification + * @h: handler to remove + * * Called by OSMs to let the core know that they no longer * are interested in the fate of the given device. */ @@ -794,9 +833,18 @@ return -ENOENT; } -/* - * Event registration API +/** + * i2o_event_register - register interest in an event + * @c: Controller to register interest with + * @tid: I2O task id + * @init_context: initiator context to use with this notifier + * @tr_context: transaction context to use with this notifier + * @evt_mask: mask of events + * + * Create and posts an event registration message to the task. No reply + * is waited for, or expected. Errors in posting will be reported. */ + int i2o_event_register(struct i2o_controller *c, u32 tid, u32 init_context, u32 tr_context, u32 evt_mask) { @@ -814,11 +862,13 @@ } /* - * Event ack API + * i2o_event_ack - acknowledge an event + * @c: controller + * @msg: pointer to the UTIL_EVENT_REGISTER reply we received * - * We just take a pointer to the original UTIL_EVENT_REGISTER reply - * message and change the function code since that's what spec - * describes an EventAck message looking like. + * We just take a pointer to the original UTIL_EVENT_REGISTER reply + * message and change the function code since that's what spec + * describes an EventAck message looking like. */ int i2o_event_ack(struct i2o_controller *c, u32 *msg) @@ -850,12 +900,12 @@ while(1) { - down_interruptible(&evt_sem); - if(signal_pending(current)) + if(down_interruptible(&evt_sem)) { dprintk(KERN_INFO "I2O event thread dead\n"); + printk("exiting..."); evt_running = 0; - return 0; + up_and_exit(&evt_dead, 0); } /* @@ -922,6 +972,10 @@ kmalloc(sizeof(struct i2o_device), GFP_KERNEL); int i; + if (d == NULL) { + printk(KERN_EMERG "i2oevtd: out of memory\n"); + break; + } memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); d->next = NULL; @@ -974,7 +1028,11 @@ printk(KERN_WARNING "%s: Warning notification received!" "Check configuration for errors!\n", c->name); break; - + + case I2O_EVT_IND_EVT_MASK_MODIFIED: + /* Well I guess that was us hey .. */ + break; + default: printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); break; @@ -1124,12 +1182,6 @@ m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; - /* - * Temporary Debugging - */ - if(m->function==0x15) - printk(KERN_ERR "%s: UTFR!\n", c->name); - i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; if(i && i->reply) i->reply(i,c,m); @@ -1219,9 +1271,9 @@ /** - * i2o_wait_message + * i2o_wait_message - obtain an i2o message from the IOP * @c: controller - * @why: explanation + * @why: explanation * * This function waits up to 5 seconds for a message slot to be * available. If no message is available it prints an error message @@ -1266,9 +1318,11 @@ char str[22]; int ret; int unit = d->lct_data.tid; - - printk(KERN_INFO "Target ID %d.\n", unit); + if(verbose==0) + return; + + printk(KERN_INFO "Target ID %d.\n", unit); if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) { buf[16]=0; @@ -1279,13 +1333,11 @@ buf[16]=0; printk(KERN_INFO " Device: %s\n", buf); } -#if 0 if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) { buf[16]=0; printk(KERN_INFO " Description: %s\n", buf); } -#endif if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) { buf[8]=0; @@ -1581,7 +1633,7 @@ /** - * i2o_reset_controller + * i2o_reset_controller - reset an IOP * @c: controller to reset * * Reset the IOP into INIT state and wait until IOP gets into RESET state. @@ -1601,7 +1653,10 @@ /* Quiesce all IOPs first */ for (iop = i2o_controller_chain; iop; iop = iop->next) - i2o_quiesce_controller(iop); + { + if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt) + i2o_quiesce_controller(iop); + } m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) @@ -1628,19 +1683,19 @@ /* Wait for a reply */ time=jiffies; - while(status[0]==0) + while(*status==0) { if((jiffies-time)>=20*HZ) { printk(KERN_ERR "IOP reset timeout.\n"); - kfree(status); + // Better to leak this for safety: kfree(status); return -ETIMEDOUT; } schedule(); barrier(); } - if (status[0]==I2O_CMD_IN_PROGRESS) + if (*status==I2O_CMD_IN_PROGRESS) { /* * Once the reset is sent, the IOP goes into the INIT state @@ -1799,7 +1854,7 @@ u32 msg[6]; int ret, size = sizeof(i2o_hrt); - /* Read first just the header to figure out the real size */ + /* First read just the header to figure out the real size */ do { if (c->hrt == NULL) { @@ -1816,7 +1871,18 @@ msg[4]= (0xD0000000 | size); /* Simple transaction */ msg[5]= virt_to_bus(c->hrt); /* Dump it here */ - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) { + ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL); + + if(ret == -ETIMEDOUT) + { + /* The HRT block we used is in limbo somewhere. When the iop wakes up + we will recover it */ + c->hrt = NULL; + return ret; + } + + if(ret<0) + { printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", c->name, -ret); return ret; @@ -1845,14 +1911,15 @@ static int i2o_systab_send(struct i2o_controller *iop) { u32 msg[12]; - u32 privmem[2]; - u32 privio[2]; int ret; + u32 *privbuf = kmalloc(16, GFP_KERNEL); + if(privbuf == NULL) + return -ENOMEM; - privmem[0] = iop->status_block->current_mem_base; - privmem[1] = iop->status_block->current_mem_size; - privio[0] = iop->status_block->current_io_base; - privio[1] = iop->status_block->current_io_size; + privbuf[0] = iop->status_block->current_mem_base; + privbuf[1] = iop->status_block->current_mem_size; + privbuf[2] = iop->status_block->current_io_base; + privbuf[3] = iop->status_block->current_io_size; msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; @@ -1864,20 +1931,33 @@ * Provide three SGL-elements: * System table (SysTab), Private memory space declaration and * Private i/o space declaration + * + * FIXME: provide these for controllers needing them */ msg[6] = 0x54000000 | sys_tbl_len; msg[7] = virt_to_bus(sys_tbl); msg[8] = 0x54000000 | 0; - msg[9] = virt_to_bus(privmem); + msg[9] = virt_to_bus(privbuf); msg[10] = 0xD4000000 | 0; - msg[11] = virt_to_bus(privio); + msg[11] = virt_to_bus(privbuf+8); - if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) - printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", + ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL); + + if(ret==-ETIMEDOUT) + { + printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name); + } + else if(ret<0) + { + printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", iop->name, -ret); + kfree(privbuf); + } else + { dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); - + kfree(privbuf); + } i2o_status_get(iop); // Entered READY state return ret; @@ -2162,7 +2242,16 @@ msg[6] = 0xD0000000|size; msg[7] = virt_to_bus(c->lct); - if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) { + ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL); + + if(ret == -ETIMEDOUT) + { + c->lct = NULL; + return ret; + } + + if(ret<0) + { printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", c->name, -ret); return ret; @@ -2206,8 +2295,11 @@ /* * Bring a controller online into OPERATIONAL state. */ + int i2o_online_controller(struct i2o_controller *iop) { + u32 v; + if (i2o_systab_send(iop) < 0) return -1; @@ -2223,6 +2315,15 @@ if (i2o_lct_get(iop) < 0) return -1; + /* Check battery status */ + + iop->battery = 0; + if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0) + { + if(v&16) + iop->battery = 1; + } + return 0; } @@ -2346,83 +2447,134 @@ return 0; } -/* - * This core API allows an OSM to post a message and then be told whether - * or not the system received a successful reply. It is useful when - * the OSM does not want to know the exact 3 +/** + * i2o_post_wait_mem - I2O query/reply with DMA buffers + * @c: controller + * @msg: message to send + * @len: length of message + * @timeout: time in seconds to wait + * @mem1: attached memory buffer 1 + * @mem2: attached memory buffer 2 + * + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. + * + * If the message times out then the value '-ETIMEDOUT' is returned. This + * is a special case. In this situation the message may (should) complete + * at an indefinite time in the future. When it completes it will use the + * memory buffers attached to the request. If -ETIMEDOUT is returned then + * the memory buffers must not be freed. Instead the event completion will + * free them for you. In all other cases the buffers are your problem. + * + * Pass NULL for unneeded buffers. */ -int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) + +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); - int status = 0; + int complete = 0; + int status; int flags = 0; - struct i2o_post_wait_data *p1, *p2; struct i2o_post_wait_data *wait_data = kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); if(!wait_data) return -ENOMEM; + /* + * Create a new notification object + */ + wait_data->status = &status; + wait_data->complete = &complete; + wait_data->mem[0] = mem1; + wait_data->mem[1] = mem2; /* - * The spin locking is needed to keep anyone from playing - * with the queue pointers and id while we do the same + * Queue the event with its unique id */ spin_lock_irqsave(&post_wait_lock, flags); + wait_data->next = post_wait_queue; post_wait_queue = wait_data; wait_data->id = (++post_wait_id) & 0x7fff; - spin_unlock_irqrestore(&post_wait_lock, flags); - wait_data->wq = &wq_i2o_post; - wait_data->status = -ETIMEDOUT; + spin_unlock_irqrestore(&post_wait_lock, flags); + + /* + * Fill in the message id + */ + msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); + /* + * Post the message to the controller. At some point later it + * will return. If we time out before it returns then + * complete will be zero. From the point post_this returns + * the wait_data may have been deleted. + */ if ((status = i2o_post_this(c, msg, len))==0) { - interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); - status = wait_data->status; + sleep_on_timeout(&wq_i2o_post, HZ * timeout); } - -#ifdef DRIVERDEBUG - if(status == -ETIMEDOUT) - printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name); -#endif - - /* - * Remove the entry from the queue. - * Since i2o_post_wait() may have been called again by - * a different thread while we were waiting for this - * instance to complete, we're not guaranteed that - * this entry is at the head of the queue anymore, so - * we need to search for it, find it, and delete it. - */ - p2 = NULL; + else + return -EIO; + + if(signal_pending(current)) + status = -EINTR; + spin_lock_irqsave(&post_wait_lock, flags); - for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { - if(p1 == wait_data) { - if(p2) - p2->next = p1->next; - else - post_wait_queue = p1->next; - - break; + barrier(); /* Be sure we see complete as it is locked */ + if(!complete) + { + /* + * Mark the entry dead. We cannot remove it. This is important. + * When it does terminate (which it must do if the controller hasnt + * died..) then it will otherwise scribble on stuff. + * !complete lets us safely check if the entry is still + * allocated and thus we can write into it + */ + wait_data->wq = NULL; + status = -ETIMEDOUT; + } + else + { + /* Debugging check - remove me soon */ + if(status == -ETIMEDOUT) + { + printk("TIMEDOUT BUG!\n"); + status = -EIO; } } + /* And the wait_data is not leaked either! */ spin_unlock_irqrestore(&post_wait_lock, flags); - - kfree(wait_data); - return status; } +/** + * i2o_post_wait - I2O query/reply + * @c: controller + * @msg: message to send + * @len: length of message + * @timeout: time in seconds to wait + * + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. + */ + +int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) +{ + return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL); +} + /* * i2o_post_wait is completed and we want to wake up the * sleeping proccess. Called by core's reply handler. */ + static void i2o_post_wait_complete(u32 context, int status) { - struct i2o_post_wait_data *p1 = NULL; - + struct i2o_post_wait_data **p1, *q; + unsigned long flags; + /* * We need to search through the post_wait * queue to see if the given message is still @@ -2435,18 +2587,49 @@ * Lock needed to keep anyone from moving queue pointers * around while we're looking through them. */ - spin_lock(&post_wait_lock); - for(p1 = post_wait_queue; p1; p1 = p1->next) { - if(p1->id == ((context >> 16) & 0x7fff)) { - p1->status = status; - wake_up_interruptible(p1->wq); + + spin_lock_irqsave(&post_wait_lock, flags); + + for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) + { + q = (*p1); + if(q->id == ((context >> 16) & 0x7fff)) { + /* + * Delete it + */ + + *p1 = q->next; + + /* + * Live or dead ? + */ + + if(q->wq) + { + /* Live entry - wakeup and set status */ + *q->status = status; + *q->complete = 1; + wake_up(q->wq); + } + else + { + /* + * Free resources. Caller is dead + */ + if(q->mem[0]) + kfree(q->mem[0]); + if(q->mem[1]) + kfree(q->mem[1]); + printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n"); + } + kfree(q); spin_unlock(&post_wait_lock); return; } } spin_unlock(&post_wait_lock); - printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); + printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n"); } /* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET @@ -2461,25 +2644,52 @@ void *oplist, int oplen, void *reslist, int reslen) { u32 msg[9]; - u8 *res = (u8 *)reslist; u32 *res32 = (u32*)reslist; u32 *restmp = (u32*)reslist; int len = 0; int i = 0; int wait_status; - + u32 *opmem, *resmem; + + /* Get DMAable memory */ + opmem = kmalloc(oplen, GFP_KERNEL); + if(opmem == NULL) + return -ENOMEM; + memcpy(opmem, oplist, oplen); + + resmem = kmalloc(reslen, GFP_KERNEL); + if(resmem == NULL) + { + kfree(opmem); + return -ENOMEM; + } + msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; msg[1] = cmd << 24 | HOST_TID << 12 | tid; msg[3] = 0; msg[4] = 0; msg[5] = 0x54000000 | oplen; /* OperationList */ - msg[6] = virt_to_bus(oplist); + msg[6] = virt_to_bus(opmem); msg[7] = 0xD0000000 | reslen; /* ResultList */ - msg[8] = virt_to_bus(reslist); + msg[8] = virt_to_bus(resmem); - if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) - return wait_status; /* -DetailedStatus */ + wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem); + + /* + * This only looks like a memory leak - don't "fix" it. + */ + if(wait_status == -ETIMEDOUT) + return wait_status; + /* Query failed */ + if(wait_status != 0) + { + kfree(resmem); + kfree(opmem); + return wait_status; + } + + memcpy(reslist, resmem, reslen); /* * Calculate number of bytes of Result LIST * We need to loop through each Result BLOCK and grab the length @@ -2500,13 +2710,13 @@ * If this is the only request,than we return an error */ if((res32[0]&0x0000FFFF) == 1) - return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + { + return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ + } } - len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ } - return (len << 2); /* bytes used by result list */ } @@ -2526,10 +2736,10 @@ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk)); - if (size < 0) - return size; - memcpy(buf, resblk+8, buflen); /* cut off header */ + + if(size>buflen) + return buflen; return size; } @@ -2570,6 +2780,8 @@ opblk, 12+buflen, resblk, sizeof(resblk)); kfree(opblk); + if(size>buflen) + return buflen; return size; } @@ -2614,6 +2826,8 @@ opblk, 10+ibuflen, resblk, reslen); kfree(opblk); + if(size>reslen) + return reslen; return size; } @@ -2662,6 +2876,8 @@ opblk, 10+buflen, resblk, sizeof(resblk)); kfree(opblk); + if(size>buflen) + return buflen; return size; } @@ -3113,8 +3329,6 @@ } -#ifdef MODULE - EXPORT_SYMBOL(i2o_controller_chain); EXPORT_SYMBOL(i2o_num_controllers); EXPORT_SYMBOL(i2o_find_controller); @@ -3131,6 +3345,7 @@ EXPORT_SYMBOL(i2o_post_this); EXPORT_SYMBOL(i2o_post_wait); +EXPORT_SYMBOL(i2o_post_wait_mem); EXPORT_SYMBOL(i2o_query_scalar); EXPORT_SYMBOL(i2o_set_scalar); @@ -3147,6 +3362,8 @@ EXPORT_SYMBOL(i2o_get_class_name); +#ifdef MODULE + MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); @@ -3206,17 +3423,13 @@ * If this is shutdown time, the thread has already been killed */ if(evt_running) { + printk("Terminating i2o threads..."); stat = kill_proc(evt_pid, SIGTERM, 1); if(!stat) { - int count = 10 * 100; - while(evt_running && count--) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "i2o: Event thread still running!\n"); + printk("waiting..."); + down(&evt_dead); } + printk("done.\n"); } #ifdef CONFIG_I2O_PCI_MODULE diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c --- v2.4.4/linux/drivers/i2o/i2o_lan.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_lan.c Sun May 20 12:11:38 2001 @@ -938,7 +938,7 @@ spin_unlock_irq(&priv->tx_lock); return 0; } -#endif CONFIG_NET_FC +#endif /* CONFIG_NET_FC */ /* * i2o_lan_packet_send(): Send a packet as is, including the MAC header. diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.4.4/linux/drivers/i2o/i2o_pci.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_pci.c Tue May 1 16:11:29 2001 @@ -160,6 +160,10 @@ c->bus.pci.irq = -1; + c->bus.pci.queue_buggy = 0; + c->bus.pci.dpt = 0; + c->bus.pci.short_req = 0; + c->irq_mask = (volatile u32 *)(mem+0x34); c->post_port = (volatile u32 *)(mem+0x40); c->reply_port = (volatile u32 *)(mem+0x44); @@ -175,6 +179,30 @@ c->type = I2O_TYPE_PCI; + /* + * Cards that fall apart if you hit them with large I/O + * loads... + */ + + if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630) + { + c->bus.pci.short_req=1; + printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n"); + } + if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) + { + c->bus.pci.queue_buggy=1; + printk(KERN_INFO "I2O: Promise workarounds activated.\n"); + } + + /* + * Cards that go bananas if you quiesce them before you reset + * them + */ + + if(dev->vendor == PCI_VENDOR_ID_DPT) + c->bus.pci.dpt=1; + /* * Enable Write Combining MTRR for IOP's memory region */ @@ -186,13 +214,12 @@ * since the region contains the Messaging unit which shouldn't be cached. */ c->bus.pci.mtrr_reg1 = -1; - if(dev->vendor == PCI_VENDOR_ID_INTEL) + if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT) { - printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); - c->bus.pci.mtrr_reg1 = - mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); - if(c->bus.pci.mtrr_reg1< 0) - printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); + printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); + c->bus.pci.mtrr_reg1 = mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); + if(c->bus.pci.mtrr_reg1< 0) + printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); } #endif diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c --- v2.4.4/linux/drivers/i2o/i2o_proc.c Fri Nov 17 16:51:47 2000 +++ linux/drivers/i2o/i2o_proc.c Tue May 1 16:09:53 2001 @@ -2356,7 +2356,7 @@ len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); - len += sprintf(buf+len, " [%s] HW CRC supression\n", + len += sprintf(buf+len, " [%s] HW CRC suppression\n", (work32[3]&0x00000004) ? "+" : "-"); len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", (work32[3]&0x00000100) ? "+" : "-"); @@ -2368,7 +2368,7 @@ (work32[3]&0x00000800) ? "+" : "-"); len += sprintf(buf+len, " [%s] HW ICMP checksum\n", (work32[3]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback supression enable\n", + len += sprintf(buf+len, " [%s] Loopback suppression enable\n", (work32[3]&0x00002000) ? "+" : "-"); len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c --- v2.4.4/linux/drivers/i2o/i2o_scsi.c Mon Oct 30 14:44:29 2000 +++ linux/drivers/i2o/i2o_scsi.c Tue May 1 16:09:53 2001 @@ -262,7 +262,7 @@ if(st) { - /* An error has occured */ + /* An error has occurred */ dprintk((KERN_DEBUG "SCSI error %08X", m[4])); diff -u --recursive --new-file v2.4.4/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c --- v2.4.4/linux/drivers/ide/alim15x3.c Fri Apr 27 14:15:01 2001 +++ linux/drivers/ide/alim15x3.c Sat May 19 17:43:06 2001 @@ -233,8 +233,8 @@ } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ -static byte m5229_revision = 0; -static byte chip_is_1543c_e = 0; +static byte m5229_revision; +static byte chip_is_1543c_e; byte ali_proc = 0; static struct pci_dev *isa_dev; @@ -689,7 +689,8 @@ * M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } } diff -u --recursive --new-file v2.4.4/linux/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c --- v2.4.4/linux/drivers/ide/amd7409.c Tue Nov 7 11:02:24 2000 +++ linux/drivers/ide/amd7409.c Sat May 19 17:43:06 2001 @@ -455,7 +455,8 @@ if (hwif->dma_base) { hwif->dmaproc = &amd7409_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c --- v2.4.4/linux/drivers/ide/cy82c693.c Tue Jun 20 07:52:36 2000 +++ linux/drivers/ide/cy82c693.c Sat May 19 17:43:06 2001 @@ -442,7 +442,8 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &cy82c693_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } #endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.4.4/linux/drivers/ide/hd.c linux/drivers/ide/hd.c --- v2.4.4/linux/drivers/ide/hd.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/ide/hd.c Sat Apr 28 11:27:53 2001 @@ -892,13 +892,7 @@ for (i=max_p - 1; i >=0 ; i--) { int minor = start + i; - kdev_t devi = MKDEV(MAJOR_NR, minor); - struct super_block *sb = get_super(devi); - - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c --- v2.4.4/linux/drivers/ide/hpt34x.c Tue Jun 20 07:52:36 2000 +++ linux/drivers/ide/hpt34x.c Sat May 19 17:43:06 2001 @@ -419,7 +419,11 @@ unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); - hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; + if (!noautodma) + hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; + else + hwif->autodma = 0; + hwif->dmaproc = &hpt34x_dmaproc; } else { hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c --- v2.4.4/linux/drivers/ide/hpt366.c Sat Jan 27 08:45:58 2001 +++ linux/drivers/ide/hpt366.c Sat May 19 17:43:06 2001 @@ -223,8 +223,8 @@ byte hpt366_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); -byte hpt363_shared_irq = 0; -byte hpt363_shared_pin = 0; +byte hpt363_shared_irq; +byte hpt363_shared_pin; static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev) { @@ -706,7 +706,10 @@ } else { hwif->dmaproc = &hpt366_dmaproc; } - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; + else + hwif->autodma = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.4.4/linux/drivers/ide/ide-cd.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/ide/ide-cd.c Fri May 25 12:44:11 2001 @@ -2780,12 +2780,12 @@ int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; - int rc; + int rc = -ENOMEM; MOD_INC_USE_COUNT; if (info->buffer == NULL) info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL); - if ((rc = cdrom_fops.open(ip, fp))) { + if ((info->buffer == NULL) || (rc = cdrom_fops.open(ip, fp))) { drive->usage--; MOD_DEC_USE_COUNT; } diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c --- v2.4.4/linux/drivers/ide/ide-pci.c Thu Apr 19 22:57:06 2001 +++ linux/drivers/ide/ide-pci.c Sun May 20 11:32:11 2001 @@ -581,7 +581,7 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) { printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n"); - if(dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && + if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) { printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n"); @@ -708,7 +708,8 @@ /* * Set up BM-DMA capability (PnP BIOS should have done this) */ - hwif->autodma = 0; /* default DMA off if we had to configure it here */ + 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); diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c --- v2.4.4/linux/drivers/ide/ide-pnp.c Wed May 24 18:38:26 2000 +++ linux/drivers/ide/ide-pnp.c Tue May 1 16:06:23 2001 @@ -49,7 +49,7 @@ /* ISA PnP device table entry */ struct pnp_dev_t { - unsigned int vendor, device; + unsigned short card_vendor, card_device, vendor, device; int (*init_fn)(struct pci_dev *dev, int enable); }; @@ -81,8 +81,9 @@ /* Add your devices here :)) */ struct pnp_dev_t idepnp_devices[] __initdata = { - /* Generic ESDI/IDE/ATA compatible hard disk controller */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), + /* Generic ESDI/IDE/ATA compatible hard disk controller */ + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), pnpide_generic_init }, { 0 } }; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.4/linux/drivers/ide/ide.c Wed Apr 11 19:06:12 2001 +++ linux/drivers/ide/ide.c Tue May 1 16:05:00 2001 @@ -179,6 +179,8 @@ static int ide_lock; #endif /* __mc68000__ || CONFIG_APUS */ +int noautodma = 0; + /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ @@ -1762,11 +1764,7 @@ for (p = 0; p < (1<part[p].nr_sects > 0) { kdev_t devp = MKDEV(major, minor+p); - struct super_block * sb = get_super(devp); - fsync_dev (devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers (devp); + invalidate_device(devp, 1); set_blocksize(devp, 1024); } drive->part[p].start_sect = 0; @@ -1983,9 +1981,7 @@ for (p = 0; p < (1<part[p].nr_sects > 0) { kdev_t devp = MKDEV(hwif->major, minor+p); - struct super_block * sb = get_super(devp); - if (sb) invalidate_inodes(sb); - invalidate_buffers (devp); + invalidate_device(devp, 0); } } #ifdef CONFIG_PROC_FS @@ -2893,6 +2889,12 @@ return 1; } #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + + if (!strcmp(s, "ide=nodma")) { + printk("IDE: Prevented DMA\n"); + noautodma = 1; + return 1; + } #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { diff -u --recursive --new-file v2.4.4/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c --- v2.4.4/linux/drivers/ide/opti621.c Tue Nov 7 11:02:24 2000 +++ linux/drivers/ide/opti621.c Tue May 1 16:05:00 2001 @@ -118,7 +118,7 @@ /* Uncommnent for disable read prefetch. * There is some readprefetch capatibility in hdparm, * but when I type hdparm -P 1 /dev/hda, I got errors - * and till reset drive is inacessible. + * and till reset drive is inaccessible. * This (hw) read prefetch is safe on my drive. */ diff -u --recursive --new-file v2.4.4/linux/drivers/ide/osb4.c linux/drivers/ide/osb4.c --- v2.4.4/linux/drivers/ide/osb4.c Sun Feb 4 10:05:30 2001 +++ linux/drivers/ide/osb4.c Tue May 1 16:05:00 2001 @@ -402,10 +402,16 @@ #ifdef DEBUG printk("%s: reg64 == 0x%08x\n", name, reg64); #endif - reg64 &= ~0x0000A000; -#ifdef CONFIG_SMP - reg64 |= 0x00008000; -#endif + +// reg64 &= ~0x0000A000; +//#ifdef CONFIG_SMP +// reg64 |= 0x00008000; +//#endif + /* Assume the APIC was set up properly by the BIOS for now . If it + wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control + APIC enable, routing and decode */ + + reg64 &= ~0x00002000; pci_write_config_dword(isa_dev, 0x64, reg64); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); @@ -441,7 +447,8 @@ #else /* CONFIG_BLK_DEV_IDEDMA */ if (hwif->dma_base) { - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &osb4_dmaproc; } else { hwif->autodma = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c --- v2.4.4/linux/drivers/ide/pdc202xx.c Thu Apr 19 22:57:06 2001 +++ linux/drivers/ide/pdc202xx.c Tue May 1 16:05:00 2001 @@ -101,13 +101,6 @@ return(pdc202xx_dma_verbose(drive_pci)); } -char *pdc202xx_interrupt_verbose (u8 sc1d) -{ - char *p = NULL; - p += sprintf(p,"0x%02x ", sc1d); - return (char *)p; -} - static char * pdc202xx_info (char *buf, struct pci_dev *dev) { char *p = buf; @@ -862,7 +855,8 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c --- v2.4.4/linux/drivers/ide/rz1000.c Thu Apr 13 22:54:26 2000 +++ linux/drivers/ide/rz1000.c Tue May 1 16:05:00 2001 @@ -94,4 +94,4 @@ init_rz1000 (dev, "RZ1001"); } -#endif CONFIG_BLK_DEV_IDEPCI +#endif /* CONFIG_BLK_DEV_IDEPCI */ diff -u --recursive --new-file v2.4.4/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c --- v2.4.4/linux/drivers/ide/sis5513.c Tue Jan 2 16:58:45 2001 +++ linux/drivers/ide/sis5513.c Sat May 19 17:43:06 2001 @@ -629,7 +629,8 @@ case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: case PCI_DEVICE_ID_SI_5591: - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -u --recursive --new-file v2.4.4/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c --- v2.4.4/linux/drivers/ide/slc90e66.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/ide/slc90e66.c Sat May 19 17:43:06 2001 @@ -372,10 +372,10 @@ if (!hwif->dma_base) return; -#ifndef CONFIG_BLK_DEV_IDEDMA hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ - hwif->autodma = 1; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &slc90e66_dmaproc; hwif->speedproc = &slc90e66_tune_chipset; #endif /* !CONFIG_BLK_DEV_IDEDMA */ diff -u --recursive --new-file v2.4.4/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c --- v2.4.4/linux/drivers/ieee1394/video1394.c Tue Jan 2 16:45:38 2001 +++ linux/drivers/ieee1394/video1394.c Thu May 24 14:55:17 2001 @@ -302,12 +302,12 @@ d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); - memset(d, 0, sizeof(struct dma_iso_ctx)); - if (d==NULL) { PRINT(KERN_ERR, ohci->id, "failed to allocate dma_iso_ctx"); return NULL; } + + memset(d, 0, sizeof(struct dma_iso_ctx)); d->ohci = (void *)ohci; d->ctx = ctx; diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h --- v2.4.4/linux/drivers/isdn/avmb1/avmcard.h Thu Apr 19 22:30:16 2001 +++ linux/drivers/isdn/avmb1/avmcard.h Sat May 19 17:54:14 2001 @@ -1,60 +1,8 @@ /* - * $Id: avmcard.h,v 1.8.6.1 2001/04/20 02:41:59 keil Exp $ + * $Id: avmcard.h,v 1.8.6.3 2001/05/17 21:15:33 kai Exp $ * * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: avmcard.h,v $ - * Revision 1.8.6.1 2001/04/20 02:41:59 keil - * changes from mainstream - * - * Revision 1.8 2000/10/10 17:44:19 kai - * changes from/for 2.2.18 - * - * Revision 1.7 2000/01/25 14:33:38 calle - * - Added Support AVM B1 PCI V4.0 (tested with prototype) - * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 - * - support for revision register - * - * Revision 1.6 1999/11/05 16:38:01 calle - * Cleanups before kernel 2.4: - * - Changed all messages to use card->name or driver->name instead of - * constant string. - * - Moved some data from struct avmcard into new struct avmctrl_info. - * Changed all lowlevel capi driver to match the new structur. - * - * Revision 1.5 1999/09/07 09:02:53 calle - * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and - * DATA_B3_IND is always directly after the CAPI message. The "Data" member - * ist never used inside the kernel. - * - * Revision 1.4 1999/08/04 10:10:08 calle - * Bugfix: corrected /proc functions, added structure for new AVM cards. - * - * Revision 1.3 1999/07/23 08:41:47 calle - * prepared for new AVM cards. - * - * Revision 1.2 1999/07/05 15:09:45 calle - * - renamed "appl_release" to "appl_released". - * - version und profile data now cleared on controller reset - * - extended /proc interface, to allow driver and controller specific - * informations to include by driver hackers. - * - * Revision 1.1 1999/07/01 15:26:22 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * */ #ifndef _AVMCARD_H_ @@ -62,7 +10,6 @@ #define AVMB1_PORTLEN 0x1f #define AVM_MAXVERSION 8 -#define AVM_NAPPS 30 #define AVM_NCCI_PER_CHANNEL 4 /* diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.4.4/linux/drivers/isdn/avmb1/b1.c Thu Apr 19 22:30:16 2001 +++ linux/drivers/isdn/avmb1/b1.c Sat May 19 17:54:14 2001 @@ -120,6 +120,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.20.6.4 $"; +static char *revision = "$Revision: 1.20.6.6 $"; /* ------------------------------------------------------------- */ @@ -374,7 +375,7 @@ cli(); b1_setinterrupt(port, card->irq, card->cardtype); b1_put_byte(port, SEND_INIT); - b1_put_word(port, AVM_NAPPS); + b1_put_word(port, CAPI_MAXAPPL); b1_put_word(port, AVM_NCCI_PER_CHANNEL*2); b1_put_word(port, ctrl->cnr - 1); restore_flags(flags); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.4.4/linux/drivers/isdn/avmb1/b1dma.c Thu Apr 19 22:30:16 2001 +++ linux/drivers/isdn/avmb1/b1dma.c Sat May 19 17:54:14 2001 @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.11.6.4 $"; +static char *revision = "$Revision: 1.11.6.6 $"; /* ------------------------------------------------------------- */ @@ -731,7 +732,7 @@ _put_byte(&p, 0); _put_byte(&p, 0); _put_byte(&p, SEND_INIT); - _put_word(&p, AVM_NAPPS); + _put_word(&p, CAPI_MAXAPPL); _put_word(&p, AVM_NCCI_PER_CHANNEL*30); _put_word(&p, card->cardnr - 1); skb_put(skb, (__u8 *)p - (__u8 *)skb->data); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.4.4/linux/drivers/isdn/avmb1/b1isa.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/b1isa.c Sat May 19 17:54:14 2001 @@ -95,7 +95,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10.6.4 $"; +static char *revision = "$Revision: 1.10.6.5 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.4.4/linux/drivers/isdn/avmb1/b1pci.c Thu Apr 19 22:30:16 2001 +++ linux/drivers/isdn/avmb1/b1pci.c Sat May 19 17:54:14 2001 @@ -125,7 +125,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.29.6.3 $"; +static char *revision = "$Revision: 1.29.6.4 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.4.4/linux/drivers/isdn/avmb1/b1pcmcia.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Sat May 19 17:54:14 2001 @@ -102,7 +102,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.12.6.3 $"; +static char *revision = "$Revision: 1.12.6.4 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.4.4/linux/drivers/isdn/avmb1/c4.c Thu Apr 19 22:30:16 2001 +++ linux/drivers/isdn/avmb1/c4.c Sat May 19 17:54:14 2001 @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include @@ -121,7 +122,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20.6.6 $"; +static char *revision = "$Revision: 1.20.6.8 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -851,7 +852,7 @@ _put_byte(&p, 0); _put_byte(&p, 0); _put_byte(&p, SEND_INIT); - _put_word(&p, AVM_NAPPS); + _put_word(&p, CAPI_MAXAPPL); _put_word(&p, AVM_NCCI_PER_CHANNEL*30); _put_word(&p, card->cardnr - 1); skb_put(skb, (__u8 *)p - (__u8 *)skb->data); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.4/linux/drivers/isdn/avmb1/capi.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/isdn/avmb1/capi.c Sat May 19 17:54:14 2001 @@ -1,238 +1,10 @@ /* - * $Id: capi.c,v 1.44.6.9 2001/04/08 17:51:42 kai Exp $ + * $Id: capi.c,v 1.44.6.11 2001/05/17 20:41:51 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: capi.c,v $ - * Revision 1.44.6.9 2001/04/08 17:51:42 kai - * merge various fixes from HEAD (found by the CHECKER project) - * - * Revision 1.44.6.8 2001/03/21 08:52:21 kai - * merge from main branch: fix buffer for revision string (calle) - * - * Revision 1.44.6.7 2001/03/15 15:11:24 kai - * *** empty log message *** - * - * Revision 1.44.6.6 2001/03/13 16:17:07 kai - * spelling fixes from 2.4.3-pre - * - * Revision 1.44.6.5 2001/02/13 11:43:29 kai - * more compatility changes for 2.2.19 - * - * Revision 1.44.6.4 2001/02/10 14:41:20 kai - * Changes from kernel tree - * - * Revision 1.44.6.3 2000/12/17 22:45:08 kai - * That's hopefully it for test13-4 - * - * Revision 1.44.6.2 2000/12/14 23:04:12 kai - * Makefile changes and the like for 2.4.0-test13-pre1 - * No compatiblity code for older kernels yet, but note the branch - * - * Revision 1.45 2000/12/02 19:47:29 kai - * Change the Makefiles to new style. - * There may be problems there that I missed, so this shouldn't go into - * an offical kernel any time soon. - * However, if I didn't commit it, we wouldn't find the bugs... - * - * Revision 1.44 2000/11/25 17:00:59 kai - * compatibility cleanup - final part for the time being - * - * Revision 1.43 2000/11/23 20:45:14 kai - * fixed module_init/exit stuff - * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. - * - * Revision 1.42 2000/11/19 17:03:55 kai - * compatibility cleanup - part 5 - * - * Revision 1.41 2000/11/01 14:05:02 calle - * - use module_init/module_exit from linux/init.h. - * - all static struct variables are initialized with "membername:" now. - * - avm_cs.c, let it work with newer pcmcia-cs. - * - * Revision 1.40 2000/10/24 15:15:04 calle - * Workaround: pppd calls restoretty before reseting the ldisc and - * ldisc "ppp_sync" didn't support this. So we call n_tty_ioctl - * in the driver ioctl function. (remember: driver ioctl function is - * only called if ldisc ioctl function did not handle the call) - * - * Revision 1.39 2000/07/24 13:42:50 calle - * - lock_kernel/unlock_kernel for _release functions. (from 2.4) - * - * Revision 1.38 2000/07/24 08:49:09 calle - * - Bugfix: capiminor_del_all_ack completely wrong :-( - * - * Revision 1.37 2000/07/20 10:22:27 calle - * - Made procfs function cleaner and removed variable "begin". - * - * Revision 1.36 2000/06/29 13:59:35 calle - * - call to devfs_register was wrong - * - * Revision 1.35 2000/06/19 15:11:24 keil - * avoid use of freed structs - * changes from 2.4.0-ac21 - * - * Revision 1.34 2000/06/18 16:09:54 keil - * more changes for 2.4 - * - * Revision 1.33 2000/05/18 16:35:43 calle - * Uaaahh. Bad memory leak fixed. - * - * Revision 1.32 2000/04/21 12:38:42 calle - * Bugfix: error in proc_ functions, begin-off => off-begin - * - * Revision 1.31 2000/04/03 13:29:24 calle - * make Tim Waugh happy (module unload races in 2.3.99-pre3). - * no real problem there, but now it is much cleaner ... - * - * Revision 1.30 2000/03/19 12:31:36 calle - * PPP over CAPI raw driver disabled for now, ppp_generic has been changed. - * - * Revision 1.29 2000/03/13 17:48:13 calle - * removed unused variable. - * - * Revision 1.28 2000/03/08 17:06:33 calle - * - changes for devfs and 2.3.49 - * - capifs now configurable (no need with devfs) - * - New Middleware ioctl CAPI_NCCI_GETUNIT - * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) - * - * Revision 1.27 2000/03/06 18:00:23 calle - * - Middleware extention now working with 2.3.49 (capifs). - * - Fixed typos in debug section of capi.c - * - Bugfix: Makefile corrected for b1pcmcia.c - * - * Revision 1.26 2000/03/03 16:48:38 calle - * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) - * It is now possible to create a connection with a CAPI2.0 applikation - * and than to handle the data connection from /dev/capi/ (capifs) and also - * using async or sync PPP on this connection. - * The two major device number 190 and 191 are not confirmed yet, - * but I want to save the code in cvs, before I go on. - * - * Revision 1.25 2000/03/03 16:37:11 kai - * incorporated some cosmetic changes from the official kernel tree back - * into CVS - * - * Revision 1.24 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.23 2000/02/26 01:00:53 keil - * changes from 2.3.47 - * - * Revision 1.22 1999/11/13 21:27:16 keil - * remove KERNELVERSION - * - * Revision 1.21 1999/09/10 17:24:18 calle - * Changes for proposed standard for CAPI2.0: - * - AK148 "Linux Exention" - * - * Revision 1.20 1999/09/07 09:02:53 calle - * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and - * DATA_B3_IND is always directly after the CAPI message. The "Data" member - * ist never used inside the kernel. - * - * Revision 1.19 1999/07/09 15:05:42 keil - * compat.h is now isdn_compat.h - * - * Revision 1.18 1999/07/06 07:42:01 calle - * - changes in /proc interface - * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. - * - * Revision 1.17 1999/07/01 15:26:30 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.16 1999/07/01 08:22:57 keil - * compatibility macros now in - * - * Revision 1.15 1999/06/21 15:24:11 calle - * extend information in /proc. - * - * Revision 1.14 1999/06/10 16:51:03 calle - * Bugfix: open/release of control device was not handled correct. - * - * Revision 1.13 1998/08/28 04:32:25 calle - * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1 - * driver running with 2.1.118. - * - * Revision 1.12 1998/05/26 22:39:34 he - * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) - * concap typo - * cleared dev.tbusy in isdn_net BCONN status callback - * - * Revision 1.11 1998/03/09 17:46:37 he - * merged in 2.1.89 changes - * - * Revision 1.10 1998/02/13 07:09:13 calle - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.9 1998/01/31 11:14:44 calle - * merged changes to 2.0 tree, prepare 2.1.82 to work. - * - * Revision 1.8 1997/11/04 06:12:08 calle - * capi.c: new read/write in file_ops since 2.1.60 - * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. - * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) - * compat.h: added #define LinuxVersionCode - * - * Revision 1.7 1997/10/11 10:29:34 calle - * llseek() parameters changed in 2.1.56. - * - * Revision 1.6 1997/10/01 09:21:15 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.5 1997/08/21 23:11:55 fritz - * Added changes for kernels >= 2.1.45 - * - * Revision 1.4 1997/05/27 15:17:50 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * Revision 1.3 1997/05/18 09:24:14 calle - * added verbose disconnect reason reporting to avmb1. - * some fixes in capi20 interface. - * changed info messages for B1-PCI - * - * Revision 1.2 1997/03/05 21:17:59 fritz - * Added capi_poll for compiling under 2.1.27 - * - * Revision 1.1 1997/03/04 21:50:29 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * */ #include @@ -271,7 +43,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.44.6.9 $"; +static char *revision = "$Revision: 1.44.6.11 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h --- v2.4.4/linux/drivers/isdn/avmb1/capidev.h Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/avmb1/capidev.h Sat May 19 17:54:14 2001 @@ -1,55 +1,9 @@ /* - * $Id: capidev.h,v 1.6 2000/11/25 17:00:59 kai Exp $ + * $Id: capidev.h,v 1.6.6.1 2001/05/17 20:41:51 kai Exp $ * * CAPI 2.0 Interface for Linux * * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: capidev.h,v $ - * Revision 1.6 2000/11/25 17:00:59 kai - * compatibility cleanup - final part for the time being - * - * Revision 1.5 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.4 1999/07/01 15:26:32 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.3 1999/07/01 08:22:58 keil - * compatibility macros now in - * - * Revision 1.2 1999/06/21 15:24:13 calle - * extend information in /proc. - * - * Revision 1.1 1997/03/04 21:50:30 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision * */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.4.4/linux/drivers/isdn/avmb1/capidrv.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/isdn/avmb1/capidrv.c Sat May 19 17:54:14 2001 @@ -1,211 +1,10 @@ /* - * $Id: capidrv.c,v 1.39.6.5 2001/04/08 17:51:42 kai Exp $ + * $Id: capidrv.c,v 1.39.6.6 2001/05/17 20:41:51 kai Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: capidrv.c,v $ - * Revision 1.39.6.5 2001/04/08 17:51:42 kai - * merge various fixes from HEAD (found by the CHECKER project) - * - * Revision 1.39.6.4 2001/03/21 08:52:21 kai - * merge from main branch: fix buffer for revision string (calle) - * - * Revision 1.39.6.3 2001/03/13 16:17:07 kai - * spelling fixes from 2.4.3-pre - * - * Revision 1.39.6.2 2001/02/13 11:43:29 kai - * more compatility changes for 2.2.19 - * - * Revision 1.39.6.1 2001/02/10 14:41:20 kai - * Changes from kernel tree - * - * Revision 1.39 2000/11/23 20:45:14 kai - * fixed module_init/exit stuff - * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. - * - * Revision 1.38 2000/11/14 08:43:07 calle - * Bugfix for v110. Connectparamters where setup for sync ... - * - * Revision 1.37 2000/11/01 14:05:02 calle - * - use module_init/module_exit from linux/init.h. - * - all static struct variables are initialized with "membername:" now. - * - avm_cs.c, let it work with newer pcmcia-cs. - * - * Revision 1.36 2000/06/26 15:13:41 keil - * features should be or'ed - * - * Revision 1.35 2000/06/19 15:11:25 keil - * avoid use of freed structs - * changes from 2.4.0-ac21 - * - * Revision 1.34 2000/06/19 13:13:55 calle - * Added Modemsupport! - * - * Revision 1.33 2000/05/06 00:52:36 kai - * merged changes from kernel tree - * fixed timer and net_device->name breakage - * - * Revision 1.32 2000/04/07 15:19:58 calle - * remove warnings - * - * Revision 1.31 2000/04/06 15:01:25 calle - * Bugfix: crash in capidrv.c when reseting a capi controller. - * - changed code order on remove of controller. - * - using tq_schedule for notifier in kcapi.c. - * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). - * strange: sometimes even MP hang on unload of isdn.o ... - * - * Revision 1.30 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.29 1999/12/06 17:13:06 calle - * Added controller watchdog. - * - * Revision 1.28 1999/11/05 16:22:37 calle - * Bugfix: Missing break in switch on ISDN_CMD_HANGUP. - * - * Revision 1.27 1999/09/16 15:13:04 calle - * forgot to change paramter type of contr for lower_callback ... - * - * Revision 1.26 1999/08/06 07:41:16 calle - * Added the "vbox patch". if (si1 == 1) si2 = 0; - * - * Revision 1.25 1999/08/04 10:10:11 calle - * Bugfix: corrected /proc functions, added structure for new AVM cards. - * - * Revision 1.24 1999/07/20 06:48:02 calle - * Bugfix: firmware version check for D2 trace was too restrictiv. - * - * Revision 1.23 1999/07/09 15:05:44 keil - * compat.h is now isdn_compat.h - * - * Revision 1.22 1999/07/06 07:24:14 calle - * Bugfix: call to kfree_skb in capidrv_signal was too early, - * thanks to Lars Heete . - * - * Revision 1.21 1999/07/01 15:26:34 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.20 1999/07/01 08:22:59 keil - * compatibility macros now in - * - * Revision 1.19 1999/06/29 16:16:54 calle - * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again. - * Also right unlocking (ISDN_CMD_UNLOCK) is done now. - * isdnlog should check returncode of read(2) calls. - * - * Revision 1.18 1999/06/21 15:24:15 calle - * extend information in /proc. - * - * Revision 1.17 1999/06/10 16:53:55 calle - * Removing of module b1pci will now remove card from lower level. - * - * Revision 1.16 1999/05/31 11:50:33 calle - * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed - * on failure, result in data block with DATA_B3 header transmitted - * - * Revision 1.15 1999/05/25 21:26:16 calle - * Include CAPI-Channelallocation (leased lines) from the 2.0 tree. - * - * Revision 1.14 1999/05/22 07:55:06 calle - * Added *V110* to AVM B1 driver. - * - * Revision 1.13 1998/06/26 15:12:55 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 1.12 1998/03/29 16:06:03 calle - * changes from 2.0 tree merged. - * - * Revision 1.3.2.10 1998/03/20 14:38:24 calle - * capidrv: prepared state machines for suspend/resume/hold - * capidrv: fix bug in state machine if B1/T1 is out of nccis - * b1capi: changed some errno returns. - * b1capi: detect if you try to add same T1 to different io address. - * b1capi: change number of nccis depending on number of channels. - * b1lli: cosmetics - * - * Revision 1.3.2.9 1998/03/20 09:01:12 calle - * Changes capi_register handling to get full support for 30 bchannels. - * - * Revision 1.3.2.8 1998/03/18 17:51:28 calle - * added controller number to error messages - * - * Revision 1.3.2.7 1998/02/27 15:40:47 calle - * T1 running with slow link. bugfix in capi_release. - * - * Revision 1.11 1998/02/13 07:09:15 calle - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.10 1998/02/02 19:52:23 calle - * Fixed vbox (audio) acceptb. - * - * Revision 1.9 1998/01/31 11:14:45 calle - * merged changes to 2.0 tree, prepare 2.1.82 to work. - * - * Revision 1.8 1997/11/04 06:12:09 calle - * capi.c: new read/write in file_ops since 2.1.60 - * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. - * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) - * compat.h: added #define LinuxVersionCode - * - * Revision 1.7 1997/10/11 10:36:34 calle - * Added isdnlog support. patch to isdnlog needed. - * - * Revision 1.6 1997/10/11 10:25:55 calle - * New interface for lowlevel drivers. BSENT with nr. of bytes sent, - * allow sending without ACK. - * - * Revision 1.5 1997/10/01 09:21:16 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.4 1997/07/13 12:22:43 calle - * bug fix for more than one controller in connect_req. - * debugoutput now with contrnr. - * - * Revision 1.3 1997/05/18 09:24:15 calle - * added verbose disconnect reason reporting to avmb1. - * some fixes in capi20 interface. - * changed info messages for B1-PCI - * - * Revision 1.2 1997/03/05 21:19:59 fritz - * Removed include of config.h (mkdep stated this is unneded). - * - * Revision 1.1 1997/03/04 21:50:31 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * */ #include @@ -234,7 +33,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.39.6.5 $"; +static char *revision = "$Revision: 1.39.6.6 $"; static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capidrv.h linux/drivers/isdn/avmb1/capidrv.h --- v2.4.4/linux/drivers/isdn/avmb1/capidrv.h Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/avmb1/capidrv.h Sat May 19 17:54:14 2001 @@ -1,30 +1,9 @@ /* - * $Id: capidrv.h,v 1.2 1998/03/29 16:06:06 calle Exp $ + * $Id: capidrv.h,v 1.2.8.1 2001/05/17 20:41:51 kai Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: capidrv.h,v $ - * Revision 1.2 1998/03/29 16:06:06 calle - * changes from 2.0 tree merged. - * - * Revision 1.1.2.1 1998/03/20 14:38:28 calle - * capidrv: prepared state machines for suspend/resume/hold - * capidrv: fix bug in state machine if B1/T1 is out of nccis - * b1capi: changed some errno returns. - * b1capi: detect if you try to add same T1 to different io address. - * b1capi: change number of nccis depending on number of channels. - * b1lli: cosmetics - * - * Revision 1.1 1997/03/04 21:50:33 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision * */ #ifndef __CAPIDRV_H__ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.4.4/linux/drivers/isdn/avmb1/capifs.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/capifs.c Thu May 24 15:42:58 2001 @@ -1,86 +1,9 @@ /* - * $Id: capifs.c,v 1.14.6.5 2001/03/21 08:52:21 kai Exp $ - * + * $Id: capifs.c,v 1.14.6.7 2001/05/24 08:29:08 kai Exp $ + * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin - * - * $Log: capifs.c,v $ - * Revision 1.14.6.5 2001/03/21 08:52:21 kai - * merge from main branch: fix buffer for revision string (calle) - * - * Revision 1.14.6.4 2001/03/15 15:11:24 kai - * *** empty log message *** - * - * Revision 1.14.6.3 2001/02/13 11:43:29 kai - * more compatility changes for 2.2.19 - * - * Revision 1.14.6.2 2001/02/10 14:41:20 kai - * Changes from kernel tree - * - * Revision 1.14.6.1 2000/11/28 12:02:45 kai - * MODULE_DEVICE_TABLE for 2.4 - * - * Revision 1.14.2.1 2000/11/26 17:47:53 kai - * added PCI_DEV_TABLE for 2.4 - * - * Revision 1.14 2000/11/23 20:45:14 kai - * fixed module_init/exit stuff - * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. - * - * Revision 1.13 2000/11/18 16:17:25 kai - * change from 2.4 tree - * - * Revision 1.12 2000/11/01 14:05:02 calle - * - use module_init/module_exit from linux/init.h. - * - all static struct variables are initialized with "membername:" now. - * - avm_cs.c, let it work with newer pcmcia-cs. - * - * Revision 1.11 2000/10/24 15:08:47 calle - * Too much includes. - * - * Revision 1.10 2000/10/12 10:12:35 calle - * Bugfix: second iput(inode) on umount, destroies a foreign inode. - * - * Revision 1.9 2000/08/20 07:30:13 keil - * changes for 2.4 - * - * Revision 1.8 2000/07/20 10:23:13 calle - * Include isdn_compat.h for people that don't use -p option of std2kern. - * - * Revision 1.7 2000/06/18 16:09:54 keil - * more changes for 2.4 - * - * Revision 1.6 2000/04/03 13:29:25 calle - * make Tim Waugh happy (module unload races in 2.3.99-pre3). - * no real problem there, but now it is much cleaner ... - * - * Revision 1.5 2000/03/13 17:49:52 calle - * make it running with 2.3.51. - * - * Revision 1.4 2000/03/08 17:06:33 calle - * - changes for devfs and 2.3.49 - * - capifs now configurable (no need with devfs) - * - New Middleware ioctl CAPI_NCCI_GETUNIT - * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) - * - * Revision 1.3 2000/03/06 18:00:23 calle - * - Middleware extention now working with 2.3.49 (capifs). - * - Fixed typos in debug section of capi.c - * - Bugfix: Makefile corrected for b1pcmcia.c - * - * Revision 1.2 2000/03/06 09:17:07 calle - * - capifs: fileoperations now in inode (change for 2.3.49) - * - Config.in: Middleware extention not a tristate, uups. - * - * Revision 1.1 2000/03/03 16:48:38 calle - * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) - * It is now possible to create a connection with a CAPI2.0 applikation - * and than to handle the data connection from /dev/capi/ (capifs) and also - * using async or sync PPP on this connection. - * The two major device number 190 and 191 are not confirmed yet, - * but I want to save the code in cvs, before I go on. - * * */ @@ -105,7 +28,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static char *revision = "$Revision: 1.14.6.5 $"; +static char *revision = "$Revision: 1.14.6.7 $"; struct capifs_ncci { struct inode *inode; @@ -142,6 +65,7 @@ static int capifs_root_readdir(struct file *,void *,filldir_t); static struct dentry *capifs_root_lookup(struct inode *,struct dentry *); static int capifs_revalidate(struct dentry *, int); +static struct inode *capifs_new_inode(struct super_block *sb); static struct file_operations capifs_root_operations = { read: generic_read_dir, @@ -285,24 +209,11 @@ kfree(sbi->nccis); kfree(sbi); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) - MOD_DEC_USE_COUNT; -#endif } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) -static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); -static void capifs_write_inode(struct inode *inode) { }; -#else static int capifs_statfs(struct super_block *sb, struct statfs *buf); -#endif -static void capifs_read_inode(struct inode *inode); static struct super_operations capifs_sops = { - read_inode: capifs_read_inode, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) - write_inode: capifs_write_inode, -#endif put_super: capifs_put_super, statfs: capifs_statfs, }; @@ -373,10 +284,6 @@ struct dentry * root; struct capifs_sb_info *sbi; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) - MOD_INC_USE_COUNT; - lock_super(s); -#endif /* Super block already completed? */ if (s->s_root) goto out; @@ -411,7 +318,14 @@ /* * Get the root inode and dentry, but defer checking for errors. */ - root_inode = iget(s, 1); /* inode 1 == root directory */ + root_inode = capifs_new_inode(s); + if (root_inode) { + root_inode->i_ino = 1; + root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + root_inode->i_op = &capifs_root_inode_operations; + root_inode->i_fop = &capifs_root_operations; + root_inode->i_nlink = 2; + } root = d_alloc_root(root_inode); /* @@ -452,34 +366,11 @@ mounts = s; out: /* Success ... somebody else completed the super block for us. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) - unlock_super(s); -#endif return s; fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) - unlock_super(s); - MOD_DEC_USE_COUNT; -#endif return NULL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) -static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) -{ - struct statfs tmp; - - tmp.f_type = CAPIFS_SUPER_MAGIC; - tmp.f_bsize = 1024; - tmp.f_blocks = 0; - tmp.f_bfree = 0; - tmp.f_bavail = 0; - tmp.f_files = 0; - tmp.f_ffree = 0; - tmp.f_namelen = NAME_MAX; - return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; -} -#else static int capifs_statfs(struct super_block *sb, struct statfs *buf) { buf->f_type = CAPIFS_SUPER_MAGIC; @@ -492,47 +383,20 @@ buf->f_namelen = NAME_MAX; return 0; } -#endif -static void capifs_read_inode(struct inode *inode) +static struct inode *capifs_new_inode(struct super_block *sb) { - ino_t ino = inode->i_ino; - struct capifs_sb_info *sbi = SBI(inode->i_sb); - - inode->i_mode = 0; - inode->i_nlink = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_blocks = 0; - inode->i_blksize = 1024; - inode->i_uid = inode->i_gid = 0; - - if ( ino == 1 ) { - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &capifs_root_inode_operations; - inode->i_fop = &capifs_root_operations; - inode->i_nlink = 2; - return; - } - - ino -= 2; - if ( ino >= sbi->max_ncci ) - return; /* Bogus */ - - init_special_inode(inode, S_IFCHR, 0); - - return; + struct inode *inode = new_inode(sb); + if (inode) { + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = 0; + inode->i_blksize = 1024; + inode->i_uid = inode->i_gid = 0; + } + return inode; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) -static struct file_system_type capifs_fs_type = { - "capifs", - 0, - capifs_read_super, - NULL -}; -#else static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0); -#endif void capifs_new_ncci(char type, unsigned int num, kdev_t device) { @@ -553,14 +417,16 @@ break; } } + if ( ino >= sbi->max_ncci ) + continue; - if ((np->inode = iget(sb, ino+2)) != 0) { + if ((np->inode = capifs_new_inode(sb)) != NULL) { struct inode *inode = np->inode; inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid; inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; - inode->i_mode = sbi->mode | S_IFCHR; - inode->i_rdev = np->kdev; - inode->i_nlink++; + inode->i_nlink = 1; + inode->i_ino = ino + 2; + init_special_inode(inode, sbi->mode|S_IFCHR, np->kdev); } } } @@ -612,11 +478,7 @@ MOD_DEC_USE_COUNT; return err; } -#ifdef MODULE - printk(KERN_NOTICE "capifs: Rev %s: loaded\n", rev); -#else - printk(KERN_NOTICE "capifs: Rev %s: started\n", rev); -#endif + printk(KERN_NOTICE "capifs: Rev %s\n", rev); MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.4.4/linux/drivers/isdn/avmb1/capiutil.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/capiutil.c Sat May 19 17:54:14 2001 @@ -1,93 +1,10 @@ /* - * $Id: capiutil.c,v 1.13.6.2 2001/03/15 15:11:24 kai Exp $ + * $Id: capiutil.c,v 1.13.6.3 2001/05/17 20:41:51 kai Exp $ * * CAPI 2.0 convert capi message to capi message struct * * From CAPI 2.0 Development Kit AVM 1995 (msg.c) * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: capiutil.c,v $ - * Revision 1.13.6.2 2001/03/15 15:11:24 kai - * *** empty log message *** - * - * Revision 1.13.6.1 2001/02/13 11:43:29 kai - * more compatility changes for 2.2.19 - * - * Revision 1.13 2000/11/23 20:45:14 kai - * fixed module_init/exit stuff - * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. - * - * Revision 1.12 2000/11/01 14:05:02 calle - * - use module_init/module_exit from linux/init.h. - * - all static struct variables are initialized with "membername:" now. - * - avm_cs.c, let it work with newer pcmcia-cs. - * - * Revision 1.11 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.10 1999/08/31 11:19:54 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.9 1999/07/09 15:05:46 keil - * compat.h is now isdn_compat.h - * - * Revision 1.8 1999/07/01 15:26:37 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.7 1999/07/01 08:23:01 keil - * compatibility macros now in - * - * Revision 1.6 1997/11/04 06:12:12 calle - * capi.c: new read/write in file_ops since 2.1.60 - * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. - * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) - * compat.h: added #define LinuxVersionCode - * - * Revision 1.5 1997/10/01 09:21:19 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.4 1997/08/10 07:43:55 calle - * forgot to export symbol capi_info2str for 2.1.x - * - * Revision 1.3 1997/05/18 09:24:18 calle - * added verbose disconnect reason reporting to avmb1. - * some fixes in capi20 interface. - * changed info messages for B1-PCI - * - * Revision 1.2 1997/03/05 21:22:13 fritz - * Fix: Symbols have to be exported unconditionally. - * - * Revision 1.1 1997/03/04 21:50:34 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision * */ #include diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.4.4/linux/drivers/isdn/avmb1/kcapi.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/kcapi.c Sat May 19 17:54:14 2001 @@ -148,7 +148,7 @@ #include #endif -static char *revision = "$Revision: 1.21.6.5 $"; +static char *revision = "$Revision: 1.21.6.6 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.4.4/linux/drivers/isdn/avmb1/t1isa.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/t1isa.c Sat May 19 17:54:14 2001 @@ -109,6 +109,7 @@ #include #include #include +#include #include #include #include "capicmd.h" @@ -116,7 +117,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.16.6.4 $"; +static char *revision = "$Revision: 1.16.6.6 $"; /* ------------------------------------------------------------- */ @@ -410,7 +411,7 @@ cli(); b1_setinterrupt(port, card->irq, card->cardtype); b1_put_byte(port, SEND_INIT); - b1_put_word(port, AVM_NAPPS); + b1_put_word(port, CAPI_MAXAPPL); b1_put_word(port, AVM_NCCI_PER_CHANNEL*30); b1_put_word(port, ctrl->cnr - 1); restore_flags(flags); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.4.4/linux/drivers/isdn/avmb1/t1pci.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/isdn/avmb1/t1pci.c Sat May 19 17:54:14 2001 @@ -94,7 +94,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13.6.3 $"; +static char *revision = "$Revision: 1.13.6.5 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c --- v2.4.4/linux/drivers/isdn/eicon/bri.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/eicon/bri.c Sat May 19 17:43:06 2001 @@ -21,8 +21,7 @@ * */ -#include - +#include "eicon.h" #include "sys.h" #include "idi.h" #include "divas.h" @@ -33,9 +32,6 @@ #include "adapter.h" #include "uxio.h" -#define PCI_COMMAND 0x04 -#define PCI_STATUS 0x06 -#define PCI_LATENCY 0x0D #define PCI_BADDR0 0x10 #define PCI_BADDR1 0x14 #define PCI_BADDR2 0x18 diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c --- v2.4.4/linux/drivers/isdn/eicon/common.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/eicon/common.c Sat May 19 17:43:06 2001 @@ -22,6 +22,7 @@ */ +#include "eicon.h" #include "sys.h" #include "idi.h" #include "constant.h" @@ -30,19 +31,14 @@ #include "pr_pc.h" #include "uxio.h" -#include - -#define MAX_ADDR_LEN #define DIVAS_LOAD_CMD 0x02 #define DIVAS_START_CMD 0x03 #define DIVAS_IRQ_RESET 0xC18 #define DIVAS_IRQ_RESET_VAL 0xFE -#define PCI_COMMAND 0x04 -#define PCI_STATUS 0x06 -#define PCI_LATENCY 0x0D -#define PCI_INTERRUPT 0x3C +#define PCI_LATENCY PCI_LATENCY_TIMER +#define PCI_INTERRUPT PCI_INTERRUPT_LINE #define TEST_INT_DIVAS 0x11 #define TEST_INT_DIVAS_BRI 0x12 @@ -93,7 +89,7 @@ } if (tablelength > 0) - bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength); + bcopy((void *)DIDD_Table, (void *)table, tablelength); return; } @@ -103,7 +99,7 @@ if (tablelength > sizeof(DIDD_Table)) tablelength = sizeof(DIDD_Table); - bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength); + bcopy((void *)table, (void *)DIDD_Table, tablelength); return; } @@ -573,7 +569,7 @@ b = card->cfg.irq; - UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT_LINE, &b); if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) { diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.4.4/linux/drivers/isdn/eicon/eicon.h Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/eicon/eicon.h Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $ +/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -147,9 +147,11 @@ #include #include #include +#include #include #include + typedef struct { __u16 length __attribute__ ((packed)); /* length of data/parameter field */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c --- v2.4.4/linux/drivers/isdn/eicon/kprintf.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/eicon/kprintf.c Sat May 19 17:43:06 2001 @@ -27,13 +27,11 @@ */ +#include "eicon.h" #include "sys.h" #include #undef MAX #undef MIN - -#include -#include #include "divas.h" #include "divalog.h" diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.4.4/linux/drivers/isdn/hysdn/boardergo.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/boardergo.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.5.6.3 2001/03/13 16:17:09 kai Exp $ +/* $Id: boardergo.c,v 1.5.6.4 2001/04/20 02:42:00 keil Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c --- v2.4.4/linux/drivers/isdn/hysdn/hycapi.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/hycapi.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hycapi.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $ +/* $Id: hycapi.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $ * * Linux driver for HYSDN cards, CAPI2.0-Interface. * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH @@ -41,7 +41,7 @@ #include "hysdn_defs.h" #include -static char hycapi_revision[]="$Revision: 1.11 $"; +static char hycapi_revision[]="$Revision: 1.8.6.2 $"; unsigned int hycapi_enable = 0xffffffff; MODULE_PARM(hycapi_enable, "i"); diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h --- v2.4.4/linux/drivers/isdn/hysdn/hysdn_defs.h Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/hysdn_defs.h Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_defs.h,v 1.5.6.1 2000/11/28 12:02:47 kai Exp $ +/* $Id: hysdn_defs.h,v 1.5.6.2 2001/04/20 02:42:00 keil Exp $ * Linux driver for HYSDN cards, global definitions and exported vars and functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c --- v2.4.4/linux/drivers/isdn/hysdn/hysdn_net.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/hysdn_net.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_net.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $ +/* $Id: hysdn_net.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $ * Linux driver for HYSDN cards, net (ethernet type) handling routines. * @@ -41,7 +41,7 @@ MODULE_PARM(hynet_enable, "i"); /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.10 $"; +char *hysdn_net_revision = "$Revision: 1.8.6.2 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.4.4/linux/drivers/isdn/hysdn/hysdn_procconf.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.8.6.1 2001/03/13 16:17:09 kai Exp $ +/* $Id: hysdn_procconf.c,v 1.8.6.2 2001/04/20 02:42:00 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -31,7 +31,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.8.6.1 $"; +static char *hysdn_procconf_revision = "$Revision: 1.8.6.2 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c --- v2.4.4/linux/drivers/isdn/hysdn/hysdn_sched.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/hysdn/hysdn_sched.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.5.6.1 2001/03/13 16:17:09 kai Exp $ +/* $Id: hysdn_sched.c,v 1.5.6.2 2001/04/20 02:42:00 keil Exp $ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. * diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.4/linux/drivers/isdn/isdn_common.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/isdn_common.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.10 2001/04/08 19:14:00 kai Exp $ +/* $Id: isdn_common.c,v 1.114.6.11 2001/04/20 02:41:58 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -51,7 +51,7 @@ isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.10 $"; +static char *isdn_revision = "$Revision: 1.114.6.11 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.4.4/linux/drivers/isdn/isdn_net.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/isdn_net.c Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.140.6.3 2001/02/07 11:31:30 kai Exp $ +/* $Id: isdn_net.c,v 1.140.6.4 2001/04/20 02:41:58 keil Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -190,7 +190,7 @@ static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); -char *isdn_net_revision = "$Revision: 1.144 $"; +char *isdn_net_revision = "$Revision: 1.140.6.4 $"; /* * Code for raw-networking over ISDN diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.4.4/linux/drivers/isdn/isdn_net.h Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/isdn_net.h Sat May 19 17:54:14 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.19 2000/06/21 09:54:29 keil Exp $ +/* $Id: isdn_net.h,v 1.19.6.1 2001/04/20 02:41:58 keil Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * diff -u --recursive --new-file v2.4.4/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.4.4/linux/drivers/isdn/isdn_ppp.c Wed Apr 18 11:49:14 2001 +++ linux/drivers/isdn/isdn_ppp.c Tue May 22 10:23:16 2001 @@ -819,7 +819,7 @@ kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); for (j = 0; j < i; j++) - kfree(ippp_table[i]); + kfree(ippp_table[j]); return -1; } memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); diff -u --recursive --new-file v2.4.4/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.4.4/linux/drivers/macintosh/via-cuda.c Sun Sep 17 09:48:05 2000 +++ linux/drivers/macintosh/via-cuda.c Tue May 1 16:05:00 2001 @@ -170,7 +170,7 @@ } /* Clear and enable interrupts, but only on PPC. On 68K it's done */ - /* for us by the the main VIA driver in arch/m68k/mac/via.c */ + /* for us by the main VIA driver in arch/m68k/mac/via.c */ #ifndef CONFIG_MAC via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ diff -u --recursive --new-file v2.4.4/linux/drivers/md/md.c linux/drivers/md/md.c --- v2.4.4/linux/drivers/md/md.c Fri Apr 6 10:42:55 2001 +++ linux/drivers/md/md.c Fri May 25 09:48:49 2001 @@ -1097,7 +1097,7 @@ } memset(rdev, 0, sizeof(*rdev)); - if (get_super(newdev)) { + if (is_mounted(newdev)) { printk("md: can not import %s, has active inodes!\n", partition_name(newdev)); err = -EBUSY; @@ -1735,7 +1735,7 @@ } /* this shouldn't be needed as above would have fired */ - if (!ro && get_super(dev)) { + if (!ro && is_mounted(dev)) { printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } @@ -2464,7 +2464,7 @@ int ret; fsync_dev(mddev_to_kdev(mddev)); - ret = md_error(mddev_to_kdev(mddev), dev); + ret = md_error(mddev, dev); return ret; } @@ -2938,13 +2938,11 @@ } -int md_error (kdev_t dev, kdev_t rdev) +int md_error (mddev_t *mddev, kdev_t rdev) { - mddev_t *mddev; mdk_rdev_t * rrdev; int rc; - mddev = kdev_to_mddev(dev); /* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); */ if (!mddev) { @@ -2999,7 +2997,7 @@ int sz = 0; unsigned long max_blocks, resync, res, dt, db, rt; - resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); + resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; max_blocks = mddev->sb->size; /* @@ -3044,7 +3042,7 @@ */ dt = ((jiffies - mddev->resync_mark) / HZ); if (!dt) dt++; - db = resync - mddev->resync_mark_cnt; + db = resync - (mddev->resync_mark_cnt/2); rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); @@ -3219,7 +3217,7 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) { - /* another "blocks" (1K) blocks have been synced */ + /* another "blocks" (512byte) blocks have been synced */ atomic_sub(blocks, &mddev->recovery_active); wake_up(&mddev->recovery_wait); if (!ok) { @@ -3232,7 +3230,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) { mddev_t *mddev2; - unsigned int max_blocks, currspeed, + unsigned int max_sectors, currspeed, j, window, err, serialize; kdev_t read_disk = mddev_to_kdev(mddev); unsigned long mark[SYNC_MARKS]; @@ -3269,7 +3267,7 @@ mddev->curr_resync = 1; - max_blocks = mddev->sb->size; + max_sectors = mddev->sb->size<<1; printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", @@ -3293,23 +3291,23 @@ /* * Tune reconstruction: */ - window = MAX_READAHEAD*(PAGE_SIZE/1024); - printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks); + window = MAX_READAHEAD*(PAGE_SIZE/512); + printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window/2,max_sectors/2); atomic_set(&mddev->recovery_active, 0); init_waitqueue_head(&mddev->recovery_wait); last_check = 0; - for (j = 0; j < max_blocks;) { - int blocks; + for (j = 0; j < max_sectors;) { + int sectors; - blocks = mddev->pers->sync_request(mddev, j); + sectors = mddev->pers->sync_request(mddev, j); - if (blocks < 0) { - err = blocks; + if (sectors < 0) { + err = sectors; goto out; } - atomic_add(blocks, &mddev->recovery_active); - j += blocks; + atomic_add(sectors, &mddev->recovery_active); + j += sectors; mddev->curr_resync = j; if (last_check + window > j) @@ -3327,7 +3325,7 @@ mark_cnt[next] = j - atomic_read(&mddev->recovery_active); last_mark = next; } - + if (md_signal_pending(current)) { /* @@ -3352,7 +3350,7 @@ if (md_need_resched(current)) schedule(); - currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1; + currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { current->nice = 19; @@ -3756,6 +3754,10 @@ continue; } mddev = alloc_mddev(MKDEV(MD_MAJOR,minor)); + if (mddev == NULL) { + printk("md: kmalloc failed - cannot start array %d\n", minor); + continue; + } if (md_setup_args.pers[minor]) { /* non-persistent */ mdu_array_info_t ainfo; diff -u --recursive --new-file v2.4.4/linux/drivers/md/raid1.c linux/drivers/md/raid1.c --- v2.4.4/linux/drivers/md/raid1.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/md/raid1.c Thu May 24 15:40:59 2001 @@ -298,7 +298,7 @@ md_spin_unlock_irq(&conf->device_lock); } -static int raid1_map (mddev_t *mddev, kdev_t *rdev, unsigned long size) +static int raid1_map (mddev_t *mddev, kdev_t *rdev) { raid1_conf_t *conf = mddev_to_conf(mddev); int i, disks = MD_SB_DISKS; @@ -388,7 +388,7 @@ * this branch is our 'one mirror IO has finished' event handler: */ if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + md_error (r1_bh->mddev, bh->b_dev); else /* * Set R1BH_Uptodate in our master buffer_head, so that @@ -602,7 +602,7 @@ bh_req = &r1_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); - bh_req->b_blocknr = bh->b_rsector / sectors; + bh_req->b_blocknr = bh->b_rsector; bh_req->b_dev = mirror->dev; bh_req->b_rdev = mirror->dev; /* bh_req->b_rsector = bh->n_rsector; */ @@ -646,7 +646,7 @@ /* * prepare mirrored mbh (fields ordered for max mem throughput): */ - mbh->b_blocknr = bh->b_rsector / sectors; + mbh->b_blocknr = bh->b_rsector; mbh->b_dev = conf->mirrors[i].dev; mbh->b_rdev = conf->mirrors[i].dev; mbh->b_rsector = bh->b_rsector; @@ -832,6 +832,7 @@ struct mirror_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; mdp_super_t *sb = mddev->sb; mdp_disk_t *failed_desc, *spare_desc, *added_desc; + mdk_rdev_t *spare_rdev, *failed_rdev; print_raid1_conf(conf); md_spin_lock_irq(&conf->device_lock); @@ -989,6 +990,16 @@ /* * do the switch finally */ + spare_rdev = find_rdev_nr(mddev, spare_desc->number); + failed_rdev = find_rdev_nr(mddev, failed_desc->number); + + /* There must be a spare_rdev, but there may not be a + * failed_rdev. That slot might be empty... + */ + spare_rdev->desc_nr = failed_desc->number; + if (failed_rdev) + failed_rdev->desc_nr = spare_desc->number; + xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); @@ -1127,7 +1138,6 @@ int disks = MD_SB_DISKS; struct buffer_head *bhl, *mbh; raid1_conf_t *conf; - int sectors = bh->b_size >> 9; conf = mddev_to_conf(mddev); bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ @@ -1157,7 +1167,7 @@ mbh->b_blocknr = bh->b_blocknr; mbh->b_dev = conf->mirrors[i].dev; mbh->b_rdev = conf->mirrors[i].dev; - mbh->b_rsector = bh->b_blocknr * sectors; + mbh->b_rsector = bh->b_blocknr; mbh->b_state = (1<b_count, 1); @@ -1184,14 +1194,15 @@ } } else { dev = bh->b_dev; - raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + raid1_map (mddev, &bh->b_dev); if (bh->b_dev == dev) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); - md_done_sync(mddev, bh->b_size>>10, 0); + md_done_sync(mddev, bh->b_size>>9, 0); } else { printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr; generic_make_request(READ, bh); } } @@ -1200,8 +1211,7 @@ case READ: case READA: dev = bh->b_dev; - - raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + raid1_map (mddev, &bh->b_dev); if (bh->b_dev == dev) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); raid1_end_bh_io(r1_bh, 0); @@ -1209,6 +1219,7 @@ printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr; generic_make_request (r1_bh->cmd, bh); } break; @@ -1294,7 +1305,7 @@ * issue suitable write requests */ -static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr) +static int raid1_sync_request (mddev_t *mddev, unsigned long sector_nr) { raid1_conf_t *conf = mddev_to_conf(mddev); struct mirror_info *mirror; @@ -1302,9 +1313,10 @@ struct buffer_head *bh; int bsize; int disk; + int block_nr; spin_lock_irq(&conf->segment_lock); - if (!block_nr) { + if (!sector_nr) { /* initialize ...*/ int buffs; conf->start_active = 0; @@ -1324,9 +1336,9 @@ if (conf->cnt_ready || conf->cnt_active) MD_BUG(); } - while ((block_nr<<1) >= conf->start_pending) { + while (sector_nr >= conf->start_pending) { PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", - block_nr<<1, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, + sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future); wait_event_lock_irq(conf->wait_done, !conf->cnt_active, @@ -1372,11 +1384,11 @@ r1_bh->cmd = SPECIAL; bh = &r1_bh->bh_req; - bh->b_blocknr = block_nr; - bsize = 1024; - while (!(bh->b_blocknr & 1) && bsize < PAGE_SIZE - && (bh->b_blocknr+2)*(bsize>>10) < mddev->sb->size) { - bh->b_blocknr >>= 1; + block_nr = sector_nr; + bsize = 512; + while (!(block_nr & 1) && bsize < PAGE_SIZE + && (block_nr+2)*(bsize>>9) < (mddev->sb->size *2)) { + block_nr >>= 1; bsize <<= 1; } bh->b_size = bsize; @@ -1392,13 +1404,14 @@ BUG(); bh->b_end_io = end_sync_read; bh->b_private = r1_bh; - bh->b_rsector = block_nr<<1; + bh->b_blocknr = sector_nr; + bh->b_rsector = sector_nr; init_waitqueue_head(&bh->b_wait); generic_make_request(READ, bh); md_sync_acct(bh->b_dev, bh->b_size/512); - return (bsize >> 10); + return (bsize >> 9); nomem: raid1_shrink_buffers(conf); @@ -1415,7 +1428,7 @@ * We don't do much here, just schedule handling by raid1d */ if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + md_error (r1_bh->mddev, bh->b_dev); else set_bit(R1BH_Uptodate, &r1_bh->state); raid1_reschedule_retry(r1_bh); @@ -1426,80 +1439,17 @@ struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + md_error (r1_bh->mddev, bh->b_dev); if (atomic_dec_and_test(&r1_bh->remaining)) { mddev_t *mddev = r1_bh->mddev; - unsigned long sect = bh->b_blocknr * (bh->b_size>>9); + unsigned long sect = bh->b_blocknr; int size = bh->b_size; raid1_free_buf(r1_bh); sync_request_done(sect, mddev_to_conf(mddev)); - md_done_sync(mddev,size>>10, uptodate); + md_done_sync(mddev,size>>9, uptodate); } } -/* - * This will catch the scenario in which one of the mirrors was - * mounted as a normal device rather than as a part of a raid set. - * - * check_consistency is very personality-dependent, eg. RAID5 cannot - * do this check, it uses another method. - */ -static int __check_consistency (mddev_t *mddev, int row) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int disks = MD_SB_DISKS; - kdev_t dev; - struct buffer_head *bh = NULL; - int i, rc = 0; - char *buffer = NULL; - - for (i = 0; i < disks; i++) { - printk("(checking disk %d)\n",i); - if (!conf->mirrors[i].operational) - continue; - printk("(really checking disk %d)\n",i); - dev = conf->mirrors[i].dev; - set_blocksize(dev, 4096); - if ((bh = bread(dev, row / 4, 4096)) == NULL) - break; - if (!buffer) { - buffer = (char *) __get_free_page(GFP_KERNEL); - if (!buffer) - break; - memcpy(buffer, bh->b_data, 4096); - } else if (memcmp(buffer, bh->b_data, 4096)) { - rc = 1; - break; - } - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - bh = NULL; - } - if (buffer) - free_page((unsigned long) buffer); - if (bh) { - dev = bh->b_dev; - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - } - return rc; -} - -static int check_consistency (mddev_t *mddev) -{ - if (__check_consistency(mddev, 0)) -/* - * we do not do this currently, as it's perfectly possible to - * have an inconsistent array when it's freshly created. Only - * newly written data has to be consistent. - */ - return 0; - - return 0; -} - #define INVALID_LEVEL KERN_WARNING \ "raid1: md%d: raid level not set to mirroring (%d)\n" @@ -1530,9 +1480,6 @@ #define NONE_OPERATIONAL KERN_ERR \ "raid1: no operational mirrors for md%d\n" -#define RUNNING_CKRAID KERN_ERR \ -"raid1: detected mirror differences -- running resync\n" - #define ARRAY_IS_ACTIVE KERN_INFO \ "raid1: raid set md%d active with %d out of %d mirrors\n" @@ -1714,17 +1661,6 @@ start_recovery = 1; } - if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { - /* - * we do sanity checks even if the device says - * it's clean ... - */ - if (check_consistency(mddev)) { - printk(RUNNING_CKRAID); - sb->state &= ~(1 << MD_SB_CLEAN); - } - } - { const char * name = "raid1d"; @@ -1794,7 +1730,6 @@ #undef OPERATIONAL #undef SPARE #undef NONE_OPERATIONAL -#undef RUNNING_CKRAID #undef ARRAY_IS_ACTIVE static int raid1_stop_resync (mddev_t *mddev) diff -u --recursive --new-file v2.4.4/linux/drivers/md/raid5.c linux/drivers/md/raid5.c --- v2.4.4/linux/drivers/md/raid5.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/md/raid5.c Thu May 24 15:40:59 2001 @@ -156,9 +156,9 @@ return 1; memset(bh, 0, sizeof (struct buffer_head)); init_waitqueue_head(&bh->b_wait); - page = alloc_page(priority); - bh->b_data = page_address(page); - if (!bh->b_data) { + if ((page = alloc_page(priority))) + bh->b_data = page_address(page); + else { kfree(bh); return 1; } @@ -412,7 +412,7 @@ spin_lock_irqsave(&conf->device_lock, flags); } } else { - md_error(mddev_to_kdev(conf->mddev), bh->b_dev); + md_error(conf->mddev, bh->b_dev); clear_bit(BH_Uptodate, &bh->b_state); } clear_bit(BH_Lock, &bh->b_state); @@ -440,7 +440,7 @@ md_spin_lock_irqsave(&conf->device_lock, flags); if (!uptodate) - md_error(mddev_to_kdev(conf->mddev), bh->b_dev); + md_error(conf->mddev, bh->b_dev); clear_bit(BH_Lock, &bh->b_state); set_bit(STRIPE_HANDLE, &sh->state); __release_stripe(conf, sh); @@ -886,7 +886,7 @@ } } if (syncing) { - md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,0); + md_done_sync(conf->mddev, (sh->size>>9) - sh->sync_redone,0); clear_bit(STRIPE_SYNCING, &sh->state); syncing = 0; } @@ -1051,15 +1051,15 @@ action[failed_num] = WRITE+1; locked++; set_bit(STRIPE_INSYNC, &sh->state); - if (conf->disks[i].operational) - md_sync_acct(conf->disks[i].dev, bh->b_size>>9); + if (conf->disks[failed_num].operational) + md_sync_acct(conf->disks[failed_num].dev, bh->b_size>>9); else if (conf->spare) md_sync_acct(conf->spare->dev, bh->b_size>>9); } } if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { - md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1); + md_done_sync(conf->mddev, (sh->size>>9) - sh->sync_redone,1); clear_bit(STRIPE_SYNCING, &sh->state); } @@ -1153,13 +1153,13 @@ return correct_size; } -static int raid5_sync_request (mddev_t *mddev, unsigned long block_nr) +static int raid5_sync_request (mddev_t *mddev, unsigned long sector_nr) { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; struct stripe_head *sh; int sectors_per_chunk = conf->chunk_size >> 9; - unsigned long stripe = (block_nr<<1)/sectors_per_chunk; - int chunk_offset = (block_nr<<1) % sectors_per_chunk; + unsigned long stripe = sector_nr/sectors_per_chunk; + int chunk_offset = sector_nr % sectors_per_chunk; int dd_idx, pd_idx; unsigned long first_sector; int raid_disks = conf->raid_disks; @@ -1167,9 +1167,9 @@ int redone = 0; int bufsize; - sh = get_active_stripe(conf, block_nr<<1, 0, 0); + sh = get_active_stripe(conf, sector_nr, 0, 0); bufsize = sh->size; - redone = block_nr-(sh->sector>>1); + redone = sector_nr - sh->sector; first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); sh->pd_idx = pd_idx; @@ -1182,7 +1182,7 @@ handle_stripe(sh); release_stripe(sh); - return (bufsize>>10)-redone; + return (bufsize>>9)-redone; } /* @@ -1256,76 +1256,6 @@ printk("raid5: resync finished.\n"); } -static int __check_consistency (mddev_t *mddev, int row) -{ - raid5_conf_t *conf = mddev->private; - kdev_t dev; - struct buffer_head *bh[MD_SB_DISKS], *tmp = NULL; - int i, ret = 0, nr = 0, count; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - - if (conf->working_disks != conf->raid_disks) - goto out; - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); - tmp->b_size = 4096; - tmp->b_page = alloc_page(GFP_KERNEL); - tmp->b_data = page_address(tmp->b_page); - if (!tmp->b_data) - goto out; - md_clear_page(tmp->b_data); - memset(bh, 0, MD_SB_DISKS * sizeof(struct buffer_head *)); - for (i = 0; i < conf->raid_disks; i++) { - dev = conf->disks[i].dev; - set_blocksize(dev, 4096); - bh[i] = bread(dev, row / 4, 4096); - if (!bh[i]) - break; - nr++; - } - if (nr == conf->raid_disks) { - bh_ptr[0] = tmp; - count = 1; - for (i = 1; i < nr; i++) { - bh_ptr[count++] = bh[i]; - if (count == MAX_XOR_BLOCKS) { - xor_block(count, &bh_ptr[0]); - count = 1; - } - } - if (count != 1) { - xor_block(count, &bh_ptr[0]); - } - if (memcmp(tmp->b_data, bh[0]->b_data, 4096)) - ret = 1; - } - for (i = 0; i < conf->raid_disks; i++) { - dev = conf->disks[i].dev; - if (bh[i]) { - bforget(bh[i]); - bh[i] = NULL; - } - fsync_dev(dev); - invalidate_buffers(dev); - } - free_page((unsigned long) tmp->b_data); -out: - if (tmp) - kfree(tmp); - return ret; -} - -static int check_consistency (mddev_t *mddev) -{ - if (__check_consistency(mddev, 0)) -/* - * We are not checking this currently, as it's legitimate to have - * an inconsistent array, at creation time. - */ - return 0; - - return 0; -} - static int raid5_run (mddev_t *mddev) { raid5_conf_t *conf; @@ -1485,12 +1415,6 @@ start_recovery = 1; } - if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN)) && - check_consistency(mddev)) { - printk(KERN_ERR "raid5: detected raid-5 superblock xor inconsistency -- running resync\n"); - sb->state &= ~(1 << MD_SB_CLEAN); - } - { const char * name = "raid5d"; @@ -1704,6 +1628,7 @@ struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; mdp_super_t *sb = mddev->sb; mdp_disk_t *failed_desc, *spare_desc, *added_desc; + mdk_rdev_t *spare_rdev, *failed_rdev; print_raid5_conf(conf); md_spin_lock_irq(&conf->device_lock); @@ -1875,6 +1800,16 @@ /* * do the switch finally */ + spare_rdev = find_rdev_nr(mddev, spare_desc->number); + failed_rdev = find_rdev_nr(mddev, failed_desc->number); + + /* There must be a spare_rdev, but there may not be a + * failed_rdev. That slot might be empty... + */ + spare_rdev->desc_nr = failed_desc->number; + if (failed_rdev) + failed_rdev->desc_nr = spare_desc->number; + xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-aimslab.c linux/drivers/media/radio/radio-aimslab.c --- v2.4.4/linux/drivers/media/radio/radio-aimslab.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-aimslab.c Sat May 19 17:43:06 2001 @@ -42,6 +42,7 @@ #endif static int io = CONFIG_RADIO_RTRACK_PORT; +static int radio_nr = -1; static int users = 0; static struct semaphore lock; @@ -345,7 +346,7 @@ rtrack_radio.priv=&rtrack_unit; - if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io, 2); return -EINVAL; @@ -371,6 +372,7 @@ MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-aztech.c linux/drivers/media/radio/radio-aztech.c --- v2.4.4/linux/drivers/media/radio/radio-aztech.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-aztech.c Sat May 19 17:43:06 2001 @@ -40,6 +40,7 @@ #endif static int io = CONFIG_RADIO_AZTECH_PORT; +static int radio_nr = -1; static int radio_wait_time = 1000; static int users = 0; static struct semaphore lock; @@ -297,7 +298,7 @@ init_MUTEX(&lock); aztech_radio.priv=&aztech_unit; - if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io,2); return -EINVAL; @@ -312,6 +313,7 @@ MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the Aztech radio card."); MODULE_PARM(io, "i"); +MODULE_PARM(radio_nr, "i"); MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-cadet.c linux/drivers/media/radio/radio-cadet.c --- v2.4.4/linux/drivers/media/radio/radio-cadet.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-cadet.c Sat May 19 17:43:06 2001 @@ -35,6 +35,7 @@ #define RDS_BUFFER 256 static int io=-1; /* default to isapnp activation */ +static int radio_nr = -1; static int users=0; static int curtuner=0; static int tunestat=0; @@ -616,7 +617,7 @@ } if (!request_region(io,2,"cadet")) return -EBUSY; - if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) { + if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) { release_region(io,2); return -EINVAL; } @@ -630,6 +631,7 @@ MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); +MODULE_PARM(radio_nr, "i"); static struct isapnp_device_id id_table[] __devinitdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-gemtek.c linux/drivers/media/radio/radio-gemtek.c --- v2.4.4/linux/drivers/media/radio/radio-gemtek.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-gemtek.c Sat May 19 17:43:06 2001 @@ -30,6 +30,7 @@ #endif static int io = CONFIG_RADIO_GEMTEK_PORT; +static int radio_nr = -1; static int users = 0; static spinlock_t lock; @@ -272,7 +273,7 @@ gemtek_radio.priv=&gemtek_unit; - if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io, 4); return -EINVAL; @@ -295,6 +296,7 @@ MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-maestro.c linux/drivers/media/radio/radio-maestro.c --- v2.4.4/linux/drivers/media/radio/radio-maestro.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-maestro.c Sat May 19 17:43:06 2001 @@ -61,6 +61,8 @@ #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) +static int radio_nr = -1; +MODULE_PARM(radio_nr, "i"); static int radio_open(struct video_device *, int); @@ -359,7 +361,7 @@ init_MUTEX(&radio_unit.lock); if(radio_power_on(&radio_unit)) { - if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) { + if(video_register_device(&maestro_radio, VFL_TYPE_RADIO, radio_nr)==-1) { printk("radio-maestro: can't register device!"); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-maxiradio.c linux/drivers/media/radio/radio-maxiradio.c --- v2.4.4/linux/drivers/media/radio/radio-maxiradio.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-maxiradio.c Sat May 19 17:43:06 2001 @@ -56,6 +56,9 @@ /* TEA5757 pin mappings */ const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ; +static int radio_nr = -1; +MODULE_PARM(radio_nr, "i"); + #define FREQ_LO 50*16000 #define FREQ_HI 150*16000 @@ -331,7 +334,7 @@ init_MUTEX(&radio_unit.lock); maxiradio_radio.priv = &radio_unit; - if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO)==-1) { + if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { printk("radio-maxiradio: can't register device!"); goto err_out_free_region; } diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c --- v2.4.4/linux/drivers/media/radio/radio-miropcm20.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/media/radio/radio-miropcm20.c Sat May 19 17:43:06 2001 @@ -30,6 +30,8 @@ #include "../../sound/aci.h" static int users = 0; +static int radio_nr = -1; +MODULE_PARM(radio_nr, "i"); struct pcm20_device { @@ -258,7 +260,7 @@ static int __init pcm20_init(void) { - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1) return -EINVAL; if(attach_aci_rds()<0) { diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-rtrack2.c linux/drivers/media/radio/radio-rtrack2.c --- v2.4.4/linux/drivers/media/radio/radio-rtrack2.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-rtrack2.c Sat May 19 17:43:06 2001 @@ -23,6 +23,7 @@ #endif static int io = CONFIG_RADIO_RTRACK2_PORT; +static int radio_nr = -1; static int users = 0; static spinlock_t lock; @@ -238,7 +239,7 @@ rtrack2_radio.priv=&rtrack2_unit; spin_lock_init(&lock); - if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io, 4); return -EINVAL; @@ -257,6 +258,7 @@ MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c --- v2.4.4/linux/drivers/media/radio/radio-sf16fmi.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-sf16fmi.c Sat May 19 17:43:06 2001 @@ -37,6 +37,7 @@ #endif static int io = CONFIG_RADIO_SF16FMI_PORT; +static int radio_nr = -1; static int users = 0; static struct semaphore lock; @@ -304,7 +305,7 @@ init_MUTEX(&lock); - if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io, 2); return -EINVAL; @@ -321,6 +322,7 @@ MODULE_DESCRIPTION("A driver for the SF16MI radio."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-terratec.c linux/drivers/media/radio/radio-terratec.c --- v2.4.4/linux/drivers/media/radio/radio-terratec.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-terratec.c Sat May 19 17:43:06 2001 @@ -50,6 +50,7 @@ /*******************************************************************/ static int io = CONFIG_RADIO_TERRATEC_PORT; +static int radio_nr = -1; static int users = 0; static spinlock_t lock; @@ -318,7 +319,7 @@ spin_lock_init(&lock); - if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io,2); return -EINVAL; @@ -339,6 +340,7 @@ MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-trust.c linux/drivers/media/radio/radio-trust.c --- v2.4.4/linux/drivers/media/radio/radio-trust.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-trust.c Sat May 19 17:43:06 2001 @@ -31,6 +31,7 @@ #endif static int io = CONFIG_RADIO_TRUST_PORT; +static int radio_nr = -1; static int ioval = 0xf; static int users = 0; static __u16 curvol; @@ -303,7 +304,7 @@ printk(KERN_ERR "trust: port 0x%x already in use\n", io); return -EBUSY; } - if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1) + if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1) { release_region(io, 2); return -EINVAL; @@ -332,6 +333,7 @@ MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-typhoon.c linux/drivers/media/radio/radio-typhoon.c --- v2.4.4/linux/drivers/media/radio/radio-typhoon.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-typhoon.c Sat May 19 17:43:06 2001 @@ -321,10 +321,12 @@ MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); MODULE_PARM(mutefreq, "i"); MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; static int io = -1; +static int radio_nr = -1; #ifdef MODULE static unsigned long mutefreq = 0; @@ -356,7 +358,7 @@ } typhoon_radio.priv = &typhoon_unit; - if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1) { release_region(io, 8); return -EINVAL; diff -u --recursive --new-file v2.4.4/linux/drivers/media/radio/radio-zoltrix.c linux/drivers/media/radio/radio-zoltrix.c --- v2.4.4/linux/drivers/media/radio/radio-zoltrix.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-zoltrix.c Sat May 19 17:43:06 2001 @@ -39,6 +39,7 @@ #endif static int io = CONFIG_RADIO_ZOLTRIX_PORT; +static int radio_nr = -1; static int users = 0; struct zol_device { @@ -365,7 +366,7 @@ return -EBUSY; } - if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1) + if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1) { release_region(io, 2); return -EINVAL; @@ -394,6 +395,7 @@ MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); +MODULE_PARM(radio_nr, "i"); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/adv7175.c linux/drivers/media/video/adv7175.c --- v2.4.4/linux/drivers/media/video/adv7175.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/adv7175.c Sat May 19 17:43:06 2001 @@ -0,0 +1,478 @@ +#define DEBUGLEVEL 0 +/* + adv7175 - adv7175a video encoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + Copyright (C) 1999 Wolfgang Scherr + Copyright (C) 2000 Serguei Miridonov + - some corrections for Pinnacle Systems Inc. DC10plus card. + + 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 + +#if (DEBUGLEVEL > 0) +#define DEBUG(x...) x /* Debug driver */ +#else +#define DEBUG(x...) +#endif + +/* ----------------------------------------------------------------------- */ + +struct adv7175 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_ADV7175 0xd4 +#define I2C_ADV7176 0x54 + +static char adv7175_name[] = "adv7175"; +static char adv7176_name[] = "adv7176"; +static char unknown_name[] = "UNKNOWN"; + +#if (DEBUGLEVEL > 0) +static char *inputs[] = { "pass_through", "play_back", "color_bar" }; +static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" }; +#endif + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int adv7175_write(struct adv7175 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static unsigned char adv7175_read(struct adv7175 *dev, unsigned char subaddr) +{ + unsigned char data; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_sendbyte(dev->bus, dev->addr + 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +static int adv7175_write_block(struct adv7175 *dev, + unsigned const char *data, unsigned int len) +{ + int ack = 0; + unsigned subaddr; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +/* ----------------------------------------------------------------------- */ +// Output filter: S-Video Composite + +#define MR050 0x11 //0x09 +#define MR060 0x14 //0x0c + +//--------------------------------------------------------------------------- + +#define TR0MODE 0x46 +#define TR0RST 0x80 + +#define TR1CAPT 0x80 +#define TR1PLAY 0x00 + +static const unsigned char init_common[] = { + + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ + + 0x07, TR0MODE, /* TR0, 16bit */ + 0x08, 0x21, /* */ + 0x09, 0x00, /* */ + 0x0a, 0x00, /* */ + 0x0b, 0x00, /* */ + 0x0c, TR1CAPT, /* TR1 */ + 0x0d, 0x4f, /* MR2 */ + 0x0e, 0x00, /* */ + 0x0f, 0x00, /* */ + 0x10, 0x00, /* */ + 0x11, 0x00, /* */ + 0x12, 0x00, /* MR3 */ + 0x24, 0x00, /* */ +}; + +static const unsigned char init_pal[] = { + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ +}; + +static const unsigned char init_ntsc[] = { + 0x00, MR060, /* MR0, NTSC enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x55, /* subc. freq. */ + 0x03, 0x55, /* subc. freq. */ + 0x04, 0x55, /* subc. freq. */ + 0x05, 0x25, /* subc. freq. */ + 0x06, 0x1a, /* subc. phase */ +}; + +static int adv7175_attach(struct i2c_device *device) +{ + int i; + struct adv7175 *encoder; + char *dname; + + MOD_INC_USE_COUNT; + + device->data = encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL); + if (encoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + + memset(encoder, 0, sizeof(struct adv7175)); + if ((device->addr == I2C_ADV7175) || (device->addr == (I2C_ADV7175 + 2))) { + dname = adv7175_name; + } else if ((device->addr == I2C_ADV7176) || (device->addr == (I2C_ADV7176 + 2))) { + dname = adv7176_name; + } else { + // We should never get here!!! + dname = unknown_name; + } + strcpy(device->name, dname); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_PAL; + encoder->input = 0; + encoder->enable = 1; + + i = adv7175_write_block(encoder, init_common, sizeof(init_common)); + if (i >= 0) { + i = adv7175_write(encoder, 0x07, TR0MODE | TR0RST); + i = adv7175_write(encoder, 0x07, TR0MODE); + i = adv7175_read(encoder, 0x12); + printk(KERN_INFO "%s_attach: %s rev. %d at 0x%02x\n", + device->name, dname, i & 1, device->addr); + } + if (i < 0) { + printk(KERN_ERR "%s_attach: init error %d\n", device->name, + i); + } + + return 0; +} + + +static int adv7175_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int adv7175_command(struct i2c_device *device, unsigned int cmd, + void *arg) +{ + struct adv7175 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC + // | VIDEO_ENCODER_SECAM + // | VIDEO_ENCODER_CCIR + ; + cap->inputs = 2; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int iarg = *(int *) arg; + + if (encoder->norm != iarg) { + switch (iarg) { + + case VIDEO_MODE_NTSC: + adv7175_write_block(encoder, + init_ntsc, + sizeof + (init_ntsc)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + + case VIDEO_MODE_PAL: + adv7175_write_block(encoder, + init_pal, + sizeof + (init_pal)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + + case VIDEO_MODE_SECAM: // WARNING! ADV7176 does not support SECAM. + // This is an attempt to convert SECAM->PAL (typically + // it does not work due to genlock: when decoder + // is in SECAM and encoder in in PAL the subcarrier + // can not be syncronized with horizontal frequency) + adv7175_write_block(encoder, + init_pal, + sizeof + (init_pal)); + if (encoder->input == 0) + adv7175_write(encoder, 0x0d, 0x49); // Disable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + break; + default: + printk(KERN_ERR + "%s: illegal norm: %d\n", + device->name, iarg); + return -EINVAL; + + } + DEBUG(printk + (KERN_INFO "%s: switched to %s\n", + device->name, norms[iarg])); + encoder->norm = iarg; + } + } + break; + + case ENCODER_SET_INPUT: + { + int iarg = *(int *) arg; + + /* RJ: *iarg = 0: input is from SAA7110 + *iarg = 1: input is from ZR36060 + *iarg = 2: color bar */ + + if (encoder->input != iarg) { + switch (iarg) { + + case 0: + adv7175_write(encoder, 0x01, 0x00); + adv7175_write(encoder, 0x0c, TR1CAPT); /* TR1 */ + if (encoder->norm == + VIDEO_MODE_SECAM) + adv7175_write(encoder, 0x0d, 0x49); // Disable genlock + else + adv7175_write(encoder, 0x0d, 0x4f); // Enable genlock + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + case 1: + adv7175_write(encoder, 0x01, 0x00); + adv7175_write(encoder, 0x0c, TR1PLAY); /* TR1 */ + adv7175_write(encoder, 0x0d, 0x49); + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + case 2: + adv7175_write(encoder, 0x01, 0x80); + adv7175_write(encoder, 0x0d, 0x49); + adv7175_write(encoder, 0x07, + TR0MODE | TR0RST); + adv7175_write(encoder, 0x07, + TR0MODE); + //udelay(10); + break; + + default: + printk(KERN_ERR + "%s: illegal input: %d\n", + device->name, iarg); + return -EINVAL; + + } + DEBUG(printk + (KERN_INFO "%s: switched to %s\n", + device->name, inputs[iarg])); + encoder->input = iarg; + } + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + adv7175_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xbf) | (encoder-> + enable ? 0x00 : + 0x40)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_adv7175 = { + "adv7175", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_ADV7175, I2C_ADV7175 + 3, + + adv7175_attach, + adv7175_detach, + adv7175_command +}; + +static struct i2c_driver i2c_driver_adv7176 = { + "adv7175", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_ADV7176, I2C_ADV7176 + 3, + + adv7175_attach, + adv7175_detach, + adv7175_command +}; + +EXPORT_NO_SYMBOLS; + +static int adv7175_init(void) +{ + int res_adv7175 = 0, res_adv7176 = 0; + res_adv7175 = i2c_register_driver(&i2c_driver_adv7175); + res_adv7176 = i2c_register_driver(&i2c_driver_adv7176); + return (res_adv7175 | res_adv7176); // Any idea how to make it better? +} + +static void adv7175_exit(void) +{ + i2c_unregister_driver(&i2c_driver_adv7176); + i2c_unregister_driver(&i2c_driver_adv7175); +} + +module_init(adv7175_init); +module_exit(adv7175_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/bt819.c linux/drivers/media/video/bt819.c --- v2.4.4/linux/drivers/media/video/bt819.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bt819.c Sat May 19 17:43:06 2001 @@ -0,0 +1,496 @@ +/* + bt819 - BT819A VideoStream Decoder (Rockwell Part) + + Copyright (C) 1999 Mike Bernson + Copyright (C) 1998 Dave Perks + + Modifications for LML33/DC10plus unified driver + Copyright (C) 2000 Serguei Miridonov + + This code was modify/ported from the saa7111 driver written + by Dave Perks. + + 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 + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct bt819 { + struct i2c_bus *bus; + int addr; + unsigned char reg[32]; + + int initialized; + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +struct timing { + int hactive; + int hdelay; + int vactive; + int vdelay; + int hscale; + int vscale; +}; + +struct timing timing_data[] = { + {864 - 24, 2, 623, 1, 0x0504, 0x0000}, + {858 - 24, 2, 523, 1, 0x00f8, 0x0000}, +// { 858-68, 64, 523, 1, 0x00f8, 0x0000 }, +}; + +#define I2C_BT819 0x8a + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int bt819_write(struct bt819 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int bt819_setbit(struct bt819 *dev, int subaddr, int bit, int data) +{ + return bt819_write(dev, subaddr, (dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); +} + +static int bt819_write_block(struct bt819 *dev, unsigned const char *data, + unsigned int len) +{ + int ack; + unsigned subaddr; + + ack = 0; + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), + I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = + i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +static int bt819_read(struct bt819 *dev, unsigned char subaddr) +{ + int data; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +static int bt819_init(struct i2c_device *device) +{ + struct bt819 *decoder; + + static unsigned char init[] = { + //0x1f, 0x00, /* Reset */ + 0x01, 0x59, /* 0x01 input format */ + 0x02, 0x00, /* 0x02 temporal decimation */ + 0x03, 0x12, /* 0x03 Cropping msb */ + 0x04, 0x16, /* 0x04 Vertical Delay, lsb */ + 0x05, 0xe0, /* 0x05 Vertical Active lsb */ + 0x06, 0x80, /* 0x06 Horizontal Delay lsb */ + 0x07, 0xd0, /* 0x07 Horizontal Active lsb */ + 0x08, 0x00, /* 0x08 Horizontal Scaling msb */ + 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */ + 0x0a, 0x00, /* 0x0a Brightness control */ + 0x0b, 0x30, /* 0x0b Miscellaneous control */ + 0x0c, 0xd8, /* 0x0c Luma Gain lsb */ + 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */ + 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ + 0x0f, 0x00, /* 0x0f Hue control */ + 0x12, 0x04, /* 0x12 Output Format */ + 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x60, */ + 0x14, 0x00, /* 0x14 Vertial Scaling lsb */ + 0x16, 0x04, /* 0x16 Video Timing Polarity 0x02, */ + 0x18, 0x68, /* 0x18 AGC Delay */ + 0x19, 0x5d, /* 0x19 Burst Gate Delay */ + 0x1a, 0x80, /* 0x1a ADC Interface */ + }; + + struct timing *timing; + + decoder = device->data; + timing = &timing_data[decoder->norm]; + + init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing->vactive >> 8) & 0x03) << 4) | + (((timing->hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03); + init[4 * 2 - 1] = timing->vdelay & 0xff; + init[5 * 2 - 1] = timing->vactive & 0xff; + init[6 * 2 - 1] = timing->hdelay & 0xff; + init[7 * 2 - 1] = timing->hactive & 0xff; + init[8 * 2 - 1] = timing->hscale >> 8; + init[9 * 2 - 1] = timing->hscale & 0xff; + + bt819_write(decoder, 0x1f, 0x00); + mdelay(1); + return bt819_write_block(decoder, init, sizeof(init)); + +} + +/* ----------------------------------------------------------------------- */ + +static int bt819_attach(struct i2c_device *device) +{ + int i; + struct bt819 *decoder; + + MOD_INC_USE_COUNT; + + device->data = decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL); + if (decoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + memset(decoder, 0, sizeof(struct bt819)); + strcpy(device->name, "bt819"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + decoder->initialized = 0; + + i = bt819_init(device); + if (i < 0) { + printk(KERN_ERR "%s: bt819_attach: init status %d\n", + decoder->bus->name, i); + } else { + printk(KERN_INFO "%s: bt819_attach: chip version %x\n", + decoder->bus->name, bt819_read(decoder, + 0x17) & 0x0f); + } + return 0; +} + +static int bt819_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int bt819_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + int temp; + + struct bt819 *decoder = device->data; + //return 0; + + if (!decoder->initialized) { // First call to bt819_init could be + bt819_init(device); // without #FRST = 0 + decoder->initialized = 1; + } + + switch (cmd) { + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + cap->flags + = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC | VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = bt819_read(decoder, 0x00); + res = 0; + if ((status & 0x80)) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & 0x10)) { + res |= DECODER_STATUS_PAL; + } else { + res |= DECODER_STATUS_NTSC; + } + break; + } + res |= DECODER_STATUS_COLOR; + *iarg = res; + + DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n", + decoder->bus->name, *iarg)); + } + break; + + case DECODER_SET_NORM: + { + int *iarg = arg; + struct timing *timing; + + DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n", + decoder->bus->name, *iarg)); + + if (*iarg == VIDEO_MODE_NTSC) { + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 0); + bt819_write(decoder, 0x18, 0x68); + bt819_write(decoder, 0x19, 0x5d); + //bt819_setbit(decoder, 0x1a, 5, 1); + timing = &timing_data[VIDEO_MODE_NTSC]; + } else { + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 1); + bt819_write(decoder, 0x18, 0x7f); + bt819_write(decoder, 0x19, 0x72); + //bt819_setbit(decoder, 0x1a, 5, 0); + timing = &timing_data[VIDEO_MODE_PAL]; + } + + bt819_write(decoder, 0x03, + (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing-> + vactive >> 8) & 0x03) << 4) | + (((timing-> + hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03)); + bt819_write(decoder, 0x04, timing->vdelay & 0xff); + bt819_write(decoder, 0x05, timing->vactive & 0xff); + bt819_write(decoder, 0x06, timing->hdelay & 0xff); + bt819_write(decoder, 0x07, timing->hactive & 0xff); + bt819_write(decoder, 0x08, timing->hscale >> 8); + bt819_write(decoder, 0x09, timing->hscale & 0xff); + decoder->norm = *iarg; + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n", + decoder->bus->name, *iarg)); + + if (*iarg < 0 || *iarg > 7) { + return -EINVAL; + } + + if (decoder->input != *iarg) { + decoder->input = *iarg; + /* select mode */ + if (decoder->input == 0) { + bt819_setbit(decoder, 0x0b, 6, 0); + bt819_setbit(decoder, 0x1a, 1, 1); + } else { + bt819_setbit(decoder, 0x0b, 6, 1); + bt819_setbit(decoder, 0x1a, 1, 0); + } + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n", + decoder->bus->name, *iarg)); + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + DEBUG(printk + (KERN_INFO "%s-bt819: enable output %x\n", + decoder->bus->name, *iarg)); + + if (decoder->enable != enable) { + decoder->enable = enable; + + if (decoder->enable) { + bt819_setbit(decoder, 0x16, 7, 0); + } else { + bt819_setbit(decoder, 0x16, 7, 1); + } + } + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + DEBUG(printk + (KERN_INFO + "%s-bt819: set picture brightness %d contrast %d colour %d\n", + decoder->bus->name, pic->brightness, + pic->contrast, pic->colour)); + + + if (decoder->bright != pic->brightness) { + /* We want -128 to 127 we get 0-65535 */ + decoder->bright = pic->brightness; + bt819_write(decoder, 0x0a, + (decoder->bright >> 8) - 128); + } + + if (decoder->contrast != pic->contrast) { + /* We want 0 to 511 we get 0-65535 */ + decoder->contrast = pic->contrast; + bt819_write(decoder, 0x0c, + (decoder-> + contrast >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 2, + ((decoder-> + contrast >> 15) & 0x01)); + } + + if (decoder->sat != pic->colour) { + /* We want 0 to 511 we get 0-65535 */ + decoder->sat = pic->colour; + bt819_write(decoder, 0x0d, + (decoder->sat >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 1, + ((decoder-> + sat >> 15) & 0x01)); + + temp = (decoder->sat * 201) / 237; + bt819_write(decoder, 0x0e, + (temp >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 0, + (temp >> 15) & 0x01); + } + + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + bt819_write(decoder, 0x0f, + 128 - (decoder->hue >> 8)); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_bt819 = { + "bt819", /* name */ + I2C_DRIVERID_VIDEODECODER, /* ID */ + I2C_BT819, I2C_BT819 + 1, + + bt819_attach, + bt819_detach, + bt819_command +}; + +EXPORT_NO_SYMBOLS; + +static int bt819_setup(void) +{ + return i2c_register_driver(&i2c_driver_bt819); +} + +static void bt819_exit(void) +{ + i2c_unregister_driver(&i2c_driver_bt819); +} + +module_init(bt819_setup); +module_exit(bt819_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/bt856.c linux/drivers/media/video/bt856.c --- v2.4.4/linux/drivers/media/video/bt856.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bt856.c Sat May 19 17:43:06 2001 @@ -0,0 +1,303 @@ +/* + bt856 - BT856A Digital Video Encoder (Rockwell Part) + + Copyright (C) 1999 Mike Bernson + Copyright (C) 1998 Dave Perks + + Modifications for LML33/DC10plus unified driver + Copyright (C) 2000 Serguei Miridonov + + This code was modify/ported from the saa7111 driver written + by Dave Perks. + + 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 + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct bt856 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_BT856 0x88 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int bt856_write(struct bt856 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int bt856_setbit(struct bt856 *dev, int subaddr, int bit, int data) +{ + return bt856_write(dev, subaddr,(dev->reg[subaddr] & ~(1 << bit)) | (data ? (1 << bit) : 0)); +} + +/* ----------------------------------------------------------------------- */ + +static int bt856_attach(struct i2c_device *device) +{ + struct bt856 *encoder; + + /* This chip is not on the buz card but at the same address saa7185 */ + //if (memcmp(device->bus->name, "buz", 3) == 0 || memcmp(device->bus->name, "zr36057", 6) == 0) + // return 1; + + MOD_INC_USE_COUNT; + device->data = encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL); + + if (encoder == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + + memset(encoder, 0, sizeof(struct bt856)); + strcpy(device->name, "bt856"); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_NTSC; + encoder->enable = 1; + + DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->bus->name)); + + bt856_write(encoder, 0xdc, 0x18); + bt856_write(encoder, 0xda, 0); + bt856_write(encoder, 0xde, 0); + + bt856_setbit(encoder, 0xdc, 3, 1); + //bt856_setbit(encoder, 0xdc, 6, 0); + bt856_setbit(encoder, 0xdc, 4, 1); + + switch (encoder->norm) { + + case VIDEO_MODE_NTSC: + bt856_setbit(encoder, 0xdc, 2, 0); + break; + + case VIDEO_MODE_PAL: + bt856_setbit(encoder, 0xdc, 2, 1); + break; + } + + bt856_setbit(encoder, 0xdc, 1, 1); + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + return 0; +} + + +static int bt856_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int bt856_command(struct i2c_device *device, unsigned int cmd, + void *arg) +{ + struct bt856 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + DEBUG(printk + (KERN_INFO "%s-bt856: get capabilities\n", + encoder->bus->name)); + + cap->flags + = VIDEO_ENCODER_PAL + | VIDEO_ENCODER_NTSC | VIDEO_ENCODER_CCIR; + cap->inputs = 2; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n", + encoder->bus->name, *iarg)); + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + bt856_setbit(encoder, 0xdc, 2, 0); + break; + + case VIDEO_MODE_PAL: + bt856_setbit(encoder, 0xdc, 2, 1); + bt856_setbit(encoder, 0xda, 0, 0); + //bt856_setbit(encoder, 0xda, 0, 1); + break; + + default: + return -EINVAL; + + } + encoder->norm = *iarg; + } + break; + + case ENCODER_SET_INPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n", + encoder->bus->name, *iarg)); + + /* We only have video bus. + *iarg = 0: input is from bt819 + *iarg = 1: input is from ZR36060 */ + + switch (*iarg) { + + case 0: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 0); + break; + case 1: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 1); + break; + case 2: // Color bar + bt856_setbit(encoder, 0xdc, 3, 0); + bt856_setbit(encoder, 0xde, 4, 1); + break; + default: + return -EINVAL; + + } + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n", + encoder->bus->name, *iarg)); + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + + DEBUG(printk + (KERN_INFO "%s-bt856: enable output %d\n", + encoder->bus->name, encoder->enable)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_bt856 = { + "bt856", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_BT856, I2C_BT856 + 1, + bt856_attach, + bt856_detach, + bt856_command +}; + +EXPORT_NO_SYMBOLS; + +static int bt856_init(void) +{ + return i2c_register_driver(&i2c_driver_bt856); +} + +static void bt856_exit(void) +{ + i2c_unregister_driver(&i2c_driver_bt856); +} + +module_init(bt856_init); +module_exit(bt856_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- v2.4.4/linux/drivers/media/video/bttv-driver.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/bttv-driver.c Sat May 19 17:43:06 2001 @@ -69,6 +69,9 @@ static unsigned int gbuffers = 2; static unsigned int gbufsize = BTTV_MAX_FBUF; static unsigned int combfilter = 0; +static int video_nr = -1; +static int radio_nr = -1; +static int vbi_nr = -1; unsigned int bttv_debug = 0; unsigned int bttv_verbose = 1; unsigned int bttv_gpio = 0; @@ -94,6 +97,10 @@ MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); MODULE_PARM(combfilter,"i"); +MODULE_PARM(video_nr,"i"); +MODULE_PARM(radio_nr,"i"); +MODULE_PARM(vbi_nr,"i"); + MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); @@ -2435,16 +2442,16 @@ { audio(btv, AUDIO_MUTE, 1); - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) { video_unregister_device(&btv->video_dev); return -1; } if (btv->has_radio) { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) { video_unregister_device(&btv->vbi_dev); video_unregister_device(&btv->video_dev); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c --- v2.4.4/linux/drivers/media/video/bw-qcam.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/bw-qcam.c Sat May 19 17:43:06 2001 @@ -83,10 +83,12 @@ static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines=4; /* Yield after this many during capture */ +static int video_nr = -1; #if LINUX_VERSION_CODE >= 0x020117 MODULE_PARM(maxpoll,"i"); MODULE_PARM(yieldlines,"i"); +MODULE_PARM(video_nr,"i"); #endif extern __inline__ int read_lpstatus(struct qcam_device *q) @@ -962,7 +964,7 @@ printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); - if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) + if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) { parport_unregister_device(qcam->pdev); kfree(qcam); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c --- v2.4.4/linux/drivers/media/video/c-qcam.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/c-qcam.c Sat May 19 17:43:06 2001 @@ -69,6 +69,7 @@ static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; static int force_rgb = 0; +static int video_nr = -1; static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) { @@ -815,7 +816,7 @@ parport_release(qcam->pdev); - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) { printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", qcam->pport->name); @@ -881,6 +882,7 @@ MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); MODULE_PARM(probe, "i"); MODULE_PARM(force_rgb, "i"); +MODULE_PARM(video_nr,"i"); module_init(cqcam_init); module_exit(cqcam_cleanup); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- v2.4.4/linux/drivers/media/video/cpia.c Fri Apr 6 10:42:55 2001 +++ linux/drivers/media/video/cpia.c Sat May 19 17:43:06 2001 @@ -52,7 +52,10 @@ extern int cpia_usb_init(void); #endif +static int video_nr = -1; + #ifdef MODULE +MODULE_PARM(video_nr,"i"); MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); MODULE_SUPPORTED_DEVICE("video"); @@ -540,6 +543,8 @@ static int cpia_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { + return -EINVAL; +#if 0 struct cam_data *cam = data; struct cam_params new_params; int retval, find_colon; @@ -1250,6 +1255,7 @@ up(&cam->param_lock); return retval; +#endif } static void create_proc_cpia_cam(struct cam_data *cam) @@ -3180,7 +3186,7 @@ camera->lowlevel_data = lowlevel; /* register v4l device */ - if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) { + if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { kfree(camera); unlock_kernel(); printk(KERN_DEBUG "video_register_device failed\n"); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c --- v2.4.4/linux/drivers/media/video/planb.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/planb.c Sat May 19 17:43:06 2001 @@ -69,9 +69,11 @@ static volatile struct planb_registers *planb_regs; static int def_norm = PLANB_DEF_NORM; /* default norm */ +static int video_nr = -1; MODULE_PARM(def_norm, "i"); MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); +MODULE_PARM(video_nr,"i"); /* ------------------ PlanB Exported Functions ------------------ */ static long planb_write(struct video_device *, const char *, unsigned long, int); @@ -2168,7 +2170,7 @@ pb->intr_mask = PLANB_FRM_IRQ; enable_irq(pb->irq); - if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) + if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0) return -1; return 0; diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/pms.c linux/drivers/media/video/pms.c --- v2.4.4/linux/drivers/media/video/pms.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/pms.c Thu May 24 15:14:08 2001 @@ -41,6 +41,7 @@ struct video_picture picture; int height; int width; + struct semaphore lock; }; struct i2c_info @@ -64,6 +65,7 @@ static int io_port = 0x250; static int data_port = 0x251; static int mem_base = 0xC8000; +static int video_nr = -1; @@ -738,8 +740,10 @@ return -EFAULT; if(v<0 || v>3) return -EINVAL; + down(&pd->lock); pms_videosource(v&1); pms_vcrinput(v>>1); + up(&pd->lock); return 0; } case VIDIOCGTUNER: @@ -779,6 +783,7 @@ return -EFAULT; if(v.tuner) return -EINVAL; + down(&pd->lock); switch(v.mode) { case VIDEO_MODE_AUTO: @@ -802,8 +807,10 @@ pms_format(2); break; default: + up(&pd->lock); return -EINVAL; } + up(&pd->lock); return 0; } case VIDIOCGPICT: @@ -827,10 +834,12 @@ * Now load the card. */ + down(&pd->lock); pms_brightness(p.brightness>>8); pms_hue(p.hue>>8); pms_colour(p.colour>>8); pms_contrast(p.contrast>>8); + up(&pd->lock); return 0; } case VIDIOCSWIN: @@ -848,8 +857,9 @@ return -EINVAL; pd->width=vw.width; pd->height=vw.height; + down(&pd->lock); pms_resolution(pd->width, pd->height); - /* Ok we figured out what to use from our wide choice */ + up(&pd->lock); /* Ok we figured out what to use from our wide choice */ return 0; } case VIDIOCGWIN: @@ -892,8 +902,9 @@ struct pms_device *pd=(struct pms_device *)v; int len; - /* FIXME: semaphore this */ + down(&pd->lock); len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count); + up(&pd->lock); return len; } @@ -1036,15 +1047,17 @@ return -ENODEV; } memcpy(&pms_device, &pms_template, sizeof(pms_template)); + init_MUTEX(&pms_device.lock); pms_device.height=240; pms_device.width=320; pms_swsense(75); pms_resolution(320,240); - return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER); + return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr); } MODULE_PARM(io_port,"i"); MODULE_PARM(mem_base,"i"); +MODULE_PARM(video_nr,"i"); static void __exit shutdown_mediavision(void) { diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c --- v2.4.4/linux/drivers/media/video/saa5249.c Fri Nov 17 17:56:51 2000 +++ linux/drivers/media/video/saa5249.c Sat May 19 17:43:06 2001 @@ -205,7 +205,7 @@ * Register it */ - if((err=video_register_device(vd, VFL_TYPE_VTX))<0) + if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0) { kfree(t); kfree(vd); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/saa7110.c linux/drivers/media/video/saa7110.c --- v2.4.4/linux/drivers/media/video/saa7110.c Wed Dec 29 17:08:55 1999 +++ linux/drivers/media/video/saa7110.c Sat May 19 17:43:06 2001 @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -398,7 +399,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7110 = +static struct i2c_driver i2c_driver_saa7110 = { "saa7110", /* name */ @@ -412,18 +413,16 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7110_init(void) -#endif +static int saa7110_init(void) { return i2c_register_driver(&i2c_driver_saa7110); } -#ifdef MODULE -void cleanup_module(void) +static void saa7110_exit(void) { i2c_unregister_driver(&i2c_driver_saa7110); } -#endif + + +module_init(saa7110_init); +module_exit(saa7110_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/saa7111.c linux/drivers/media/video/saa7111.c --- v2.4.4/linux/drivers/media/video/saa7111.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/media/video/saa7111.c Sat May 19 17:43:06 2001 @@ -1,46 +1,41 @@ /* - saa7111 - Philips SAA7111A video decoder driver version 0.0.3 + saa7111 - Philips SAA7111A video decoder driver version 0.0.3 - Copyright (C) 1998 Dave Perks + Copyright (C) 1998 Dave Perks - 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. - */ + Slight changes for video timing and attachment output by + Wolfgang Scherr + + 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 #define DEBUG(x) /* Debug driver */ @@ -67,7 +62,8 @@ /* ----------------------------------------------------------------------- */ -static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) +static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, + unsigned char data) { int ack; @@ -82,9 +78,10 @@ return ack; } -static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) +static int saa7111_write_block(struct saa7111 *dev, + unsigned const char *data, unsigned int len) { - int ack = 0; + int ack = -1; unsigned subaddr; while (len > 1) { @@ -96,7 +93,10 @@ len -= 2; while (len > 1 && *data == ++subaddr) { data++; - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + ack = + i2c_sendbyte(dev->bus, + (dev->reg[subaddr] = + *data++), I2C_DELAY); len -= 2; } i2c_stop(dev->bus); @@ -128,20 +128,19 @@ int i; struct saa7111 *decoder; - static const unsigned char init[] = - { + static const unsigned char init[] = { 0x00, 0x00, /* 00 - ID byte */ 0x01, 0x00, /* 01 - reserved */ - /*front end */ + /*front end */ 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ 0x04, 0x00, /* 04 - GAI1=256 */ 0x05, 0x00, /* 05 - GAI2=256 */ - /* decoder */ - 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ - 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ + /* decoder */ + 0x06, 0xf3, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ + 0x07, 0x13, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ 0x0a, 0x80, /* 0a - BRIG=128 */ @@ -160,11 +159,14 @@ 0x17, 0x00, /* 17 - VBI */ }; + MOD_INC_USE_COUNT; + device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); - if (decoder == NULL) { + if (decoder == NULL) + { + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; memset(decoder, 0, sizeof(struct saa7111)); strcpy(device->name, "saa7111"); @@ -180,9 +182,11 @@ i = saa7111_write_block(decoder, init, sizeof(init)); if (i < 0) { - printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); + printk(KERN_ERR "%s_attach: init status %d\n", + device->name, i); } else { - printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); + printk(KERN_INFO "%s_attach: chip version %x\n", + device->name, saa7111_read(decoder, 0x00) >> 4); } return 0; } @@ -195,7 +199,8 @@ return 0; } -static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) +static int saa7111_command(struct i2c_device *device, unsigned int cmd, + void *arg) { struct saa7111 *decoder = device->data; @@ -209,9 +214,12 @@ for (i = 0; i < 32; i += 16) { int j; - printk("KERN_DEBUG %s: %03x", device->name, i); + printk("KERN_DEBUG %s: %03x", device->name, + i); for (j = 0; j < 16; ++j) { - printk(" %02x", saa7111_read(decoder, i + j)); + printk(" %02x", + saa7111_read(decoder, + i + j)); } printk("\n"); } @@ -226,8 +234,7 @@ cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC - | VIDEO_DECODER_AUTO - | VIDEO_DECODER_CCIR; + | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR; cap->inputs = 8; cap->outputs = 1; } @@ -274,15 +281,21 @@ switch (*iarg) { case VIDEO_MODE_NTSC: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x40); break; case VIDEO_MODE_PAL: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x00); break; case VIDEO_MODE_AUTO: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0x3f) | 0x80); break; default: @@ -300,12 +313,20 @@ if (*iarg < 0 || *iarg > 7) { return -EINVAL; } + if (decoder->input != *iarg) { decoder->input = *iarg; /* select mode */ - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8) | + decoder->input); /* bypass chrominance trap for modes 4..7 */ - saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); + saa7111_write(decoder, 0x09, + (decoder-> + reg[0x09] & 0x7f) | + ((decoder->input > + 3) ? 0x80 : 0)); } } break; @@ -330,19 +351,34 @@ decoder->enable = enable; // RJ: If output should be disabled (for playing videos), we also need a open PLL. - // The input is set to 0 (where no input source is connected), although this - // is not necessary. - // - // If output should be enabled, we have to reverse the above. +// The input is set to 0 (where no input source is connected), although this +// is not necessary. +// +// If output should be enabled, we have to reverse the above. if (decoder->enable) { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8) | + decoder->input); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0xfb)); + saa7111_write(decoder, 0x11, + (decoder-> + reg[0x11] & 0xf3) | + 0x0c); } else { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); + saa7111_write(decoder, 0x02, + (decoder-> + reg[0x02] & 0xf8)); + saa7111_write(decoder, 0x08, + (decoder-> + reg[0x08] & 0xfb) | + 0x04); + saa7111_write(decoder, 0x11, + (decoder-> + reg[0x11] & 0xf3)); } } } @@ -355,22 +391,26 @@ if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; - saa7111_write(decoder, 0x0a, decoder->bright >> 8); + saa7111_write(decoder, 0x0a, + decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 127 we get 0-65535 */ decoder->contrast = pic->contrast; - saa7111_write(decoder, 0x0b, decoder->contrast >> 9); + saa7111_write(decoder, 0x0b, + decoder->contrast >> 9); } if (decoder->sat != pic->colour) { /* We want 0 to 127 we get 0-65535 */ decoder->sat = pic->colour; - saa7111_write(decoder, 0x0c, decoder->sat >> 9); + saa7111_write(decoder, 0x0c, + decoder->sat >> 9); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; - saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); + saa7111_write(decoder, 0x0d, + (decoder->hue - 32768) >> 8); } } break; @@ -384,8 +424,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7111 = -{ +static struct i2c_driver i2c_driver_saa7111 = { "saa7111", /* name */ I2C_DRIVERID_VIDEODECODER, /* ID */ I2C_SAA7111, I2C_SAA7111 + 1, @@ -397,22 +436,15 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7111_init(void) -#endif +static int saa7111_init(void) { return i2c_register_driver(&i2c_driver_saa7111); } - - -#ifdef MODULE - -void cleanup_module(void) +static void saa7111_exit(void) { i2c_unregister_driver(&i2c_driver_saa7111); } -#endif +module_init(saa7111_init); +module_exit(saa7111_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/saa7185.c linux/drivers/media/video/saa7185.c --- v2.4.4/linux/drivers/media/video/saa7185.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/media/video/saa7185.c Sat May 19 17:43:06 2001 @@ -1,30 +1,34 @@ /* - saa7185 - Philips SAA7185B video encoder driver version 0.0.3 + saa7185 - Philips SAA7185B video encoder driver version 0.0.3 - Copyright (C) 1998 Dave Perks + Copyright (C) 1998 Dave Perks - 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. - */ + Slight changes for video timing and attachment output by + Wolfgang Scherr + + 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 @@ -41,9 +45,10 @@ #include #include + #include -#define DEBUG(x) x /* Debug driver */ +#define DEBUG(x) /* Debug driver */ /* ----------------------------------------------------------------------- */ @@ -66,13 +71,31 @@ /* ----------------------------------------------------------------------- */ -static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) +static int saa7185_read(struct saa7185 *dev) { int ack; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + ack = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, + unsigned char data) +{ + int ack; + + DEBUG(printk + (KERN_DEBUG "SAA7185: %02x set to %02x\n", subaddr, data); + ) + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); @@ -82,9 +105,10 @@ return ack; } -static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) +static int saa7185_write_block(struct saa7185 *dev, + unsigned const char *data, unsigned int len) { - int ack = 0; + int ack = -1; unsigned subaddr; while (len > 1) { @@ -107,8 +131,7 @@ /* ----------------------------------------------------------------------- */ -static const unsigned char init_common[] = -{ +static const unsigned char init_common[] = { 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ 0x42, 0x6b, /* OVLY0=107 */ @@ -155,7 +178,7 @@ 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ - 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ + 0x6e, 0x0e, /* HTRIG=0x005, approx. centered, at least for PAL */ 0x6f, 0x00, /* HTRIG upper bits */ 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ @@ -182,8 +205,7 @@ 0x7d, 0x20, /* LAL=244, FAL=22 */ }; -static const unsigned char init_pal[] = -{ +static const unsigned char init_pal[] = { 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ 0x63, 0xcb, /* FSC0 */ @@ -192,8 +214,7 @@ 0x66, 0x2a, /* FSC3 */ }; -static const unsigned char init_ntsc[] = -{ +static const unsigned char init_ntsc[] = { 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ 0x63, 0x1f, /* FSC0 */ @@ -207,11 +228,14 @@ int i; struct saa7185 *encoder; + MOD_INC_USE_COUNT; + device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); if (encoder == NULL) { + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; + memset(encoder, 0, sizeof(struct saa7185)); strcpy(device->name, "saa7185"); @@ -222,23 +246,33 @@ i = saa7185_write_block(encoder, init_common, sizeof(init_common)); if (i >= 0) { - i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + i = saa7185_write_block(encoder, init_ntsc, + sizeof(init_ntsc)); } if (i < 0) { - printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); + printk(KERN_ERR "%s_attach: init error %d\n", device->name, + i); + } else { + printk(KERN_INFO "%s_attach: chip version %d\n", + device->name, saa7185_read(encoder) >> 5); } + return 0; } static int saa7185_detach(struct i2c_device *device) { - kfree(device->data); + struct saa7185 *encoder = device->data; + saa7185_write(encoder, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */ + //saa7185_write(encoder, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */ + kfree(encoder); MOD_DEC_USE_COUNT; return 0; } -static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) +static int saa7185_command(struct i2c_device *device, unsigned int cmd, + void *arg) { struct saa7185 *encoder = device->data; @@ -251,8 +285,7 @@ cap->flags = VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC - | VIDEO_ENCODER_SECAM - | VIDEO_ENCODER_CCIR; + | VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR; cap->inputs = 1; cap->outputs = 1; } @@ -265,11 +298,13 @@ switch (*iarg) { case VIDEO_MODE_NTSC: - saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + saa7185_write_block(encoder, init_ntsc, + sizeof(init_ntsc)); break; case VIDEO_MODE_PAL: - saa7185_write_block(encoder, init_pal, sizeof(init_pal)); + saa7185_write_block(encoder, init_pal, + sizeof(init_pal)); break; case VIDEO_MODE_SECAM: @@ -285,12 +320,6 @@ { int *iarg = arg; -#if 0 - /* not much choice of inputs */ - if (*iarg != 0) { - return -EINVAL; - } -#else /* RJ: *iarg = 0: input is from SA7111 *iarg = 1: input is from ZR36060 */ @@ -298,19 +327,25 @@ case 0: /* Switch RTCE to 1 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xf7) | 0x08); + saa7185_write(encoder, 0x6e, 0x01); break; case 1: /* Switch RTCE to 0 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xf7) | 0x00); + /* SW: a slight sync problem... */ + saa7185_write(encoder, 0x6e, 0x00); break; default: return -EINVAL; } -#endif } break; @@ -330,7 +365,11 @@ int *iarg = arg; encoder->enable = !!*iarg; - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); + saa7185_write(encoder, 0x61, + (encoder-> + reg[0x61] & 0xbf) | (encoder-> + enable ? 0x00 : + 0x40)); } break; @@ -343,8 +382,7 @@ /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_saa7185 = -{ +static struct i2c_driver i2c_driver_saa7185 = { "saa7185", /* name */ I2C_DRIVERID_VIDEOENCODER, /* ID */ I2C_SAA7185, I2C_SAA7185 + 1, @@ -356,22 +394,15 @@ EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int saa7185_init(void) -#endif +static int saa7185_init(void) { return i2c_register_driver(&i2c_driver_saa7185); } - - -#ifdef MODULE - -void cleanup_module(void) +static void saa7185_exit(void) { i2c_unregister_driver(&i2c_driver_saa7185); } -#endif +module_init(saa7185_init); +module_exit(saa7185_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c --- v2.4.4/linux/drivers/media/video/stradis.c Thu Apr 19 09:34:05 2001 +++ linux/drivers/media/video/stradis.c Sat May 19 17:43:06 2001 @@ -63,6 +63,9 @@ static int saa_num = 0; /* number of SAA7146s in use */ +static int video_nr = -1; +MODULE_PARM(video_nr,"i"); + #define nDebNormal 0x00480000 #define nDebNoInc 0x00480000 #define nDebVideo 0xd0480000 @@ -2073,7 +2076,7 @@ return result; } pci_set_master(dev); - if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER) < 0) { + if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) { iounmap(saa->saa7146_mem); return -1; } diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/tda9875.c linux/drivers/media/video/tda9875.c --- v2.4.4/linux/drivers/media/video/tda9875.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/media/video/tda9875.c Sat May 19 17:43:06 2001 @@ -80,8 +80,8 @@ #define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ #define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ -#define TDA9875_CH1V 0x0c /*Chanel 1 volume (mute)*/ -#define TDA9875_CH2V 0x0d /*Chanel 2 volume (mute)*/ +#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/ +#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/ #define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ #define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ @@ -182,8 +182,8 @@ tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/ tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/ - tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Chanel volume 1 mute*/ - tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Chanel volume 2 mute */ + tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Channel volume 1 mute*/ + tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Channel volume 2 mute */ tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/ tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/ tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/ diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c --- v2.4.4/linux/drivers/media/video/tvaudio.c Mon Feb 19 14:43:36 2001 +++ linux/drivers/media/video/tvaudio.c Tue May 1 16:05:00 2001 @@ -124,7 +124,7 @@ /* ---------------------------------------------------------------------- */ -/* i2c adresses */ +/* i2c addresses */ static unsigned short normal_i2c[] = { I2C_TDA8425 >> 1, diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c --- v2.4.4/linux/drivers/media/video/videodev.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/videodev.c Sat May 19 18:13:15 2001 @@ -30,6 +30,7 @@ #include #include +#include #include @@ -394,7 +395,7 @@ if (vfd == d->vdev) { remove_proc_entry(d->name, video_dev_proc_entry); list_del (&d->proc_list); - kfree (d); + kfree(d); break; } } @@ -406,9 +407,10 @@ /** * video_register_device - register video4linux devices - * @vfd: video device structure we want to register + * @vfd: video device structure we want to register * @type: type of device to register - * FIXME: needs a semaphore on 2.3.x + * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... + * -1 == first free) * * The registration code assigns minor numbers based on the type * requested. -ENFILE is returned in all the device slots for this @@ -427,14 +429,17 @@ * * %VFL_TYPE_RADIO - A radio card */ - -int video_register_device(struct video_device *vfd, int type) + +static DECLARE_MUTEX(videodev_register_lock); + +int video_register_device(struct video_device *vfd, int type, int nr) { int i=0; int base; int err; int end; char *name_base; + char name[16]; switch(type) { @@ -461,49 +466,58 @@ default: return -1; } - - for(i=base;iminor=i; - /* The init call may sleep so we book the slot out - then call */ - MOD_INC_USE_COUNT; - if(vfd->initialize) - { - err=vfd->initialize(vfd); - if(err<0) - { - video_device[i]=NULL; - MOD_DEC_USE_COUNT; - return err; - } - } - sprintf (name, "v4l/%s%d", name_base, i - base); - /* - * Start the device root only. Anything else - * has serious privacy issues. - */ - vfd->devfs_handle = - devfs_register (NULL, name, DEVFS_FL_DEFAULT, - VIDEO_MAJOR, vfd->minor, - S_IFCHR | S_IRUSR | S_IWUSR, - &video_fops, NULL); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - sprintf (name, "%s%d", name_base, i - base); - videodev_proc_create_dev (vfd, name); -#endif - - - return 0; + /* pick a minor number */ + down(&videodev_register_lock); + if (-1 == nr) { + /* use first free */ + for(i=base;iminor=i; + up(&videodev_register_lock); + + /* The init call may sleep so we book the slot out + then call */ + MOD_INC_USE_COUNT; + if(vfd->initialize) { + err=vfd->initialize(vfd); + if(err<0) { + video_device[i]=NULL; + MOD_DEC_USE_COUNT; + return err; } } - return -ENFILE; + sprintf (name, "v4l/%s%d", name_base, i - base); + /* + * Start the device root only. Anything else + * has serious privacy issues. + */ + vfd->devfs_handle = + devfs_register (NULL, name, DEVFS_FL_DEFAULT, + VIDEO_MAJOR, vfd->minor, + S_IFCHR | S_IRUSR | S_IWUSR, + &video_fops, + NULL); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + sprintf (name, "%s%d", name_base, i - base); + videodev_proc_create_dev (vfd, name); +#endif + return 0; } /** @@ -546,7 +560,7 @@ * Initialise video for linux */ -int __init videodev_init(void) +static int __init videodev_init(void) { struct video_init *vfli = video_init_list; @@ -573,25 +587,28 @@ return 0; } -#ifdef MODULE -int init_module(void) -{ - return videodev_init(); -} - -void cleanup_module(void) +static void __exit videodev_exit(void) { +#ifdef MODULE #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) videodev_proc_destroy (); #endif +#endif devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture"); } -#endif +module_init(videodev_init) +module_exit(videodev_exit) EXPORT_SYMBOL(video_register_device); EXPORT_SYMBOL(video_unregister_device); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/w9966.c linux/drivers/media/video/w9966.c --- v2.4.4/linux/drivers/media/video/w9966.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/w9966.c Thu May 24 15:14:08 2001 @@ -0,0 +1,996 @@ +/* + Winbond w9966cf Webcam parport driver. + + Version 0.32 + + 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 + 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. +*/ +/* + Supported devices: + *Lifeview FlyCam Supra (using the Philips saa7111a chip) + + Does any other model using the w9966 interface chip exist ? + + 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 + + Please support me by sending feedback! + + Changes: + + Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE + and owner support for newer module locks +*/ + +#include +#include +#include +#include +#include + +//#define DEBUG // Undef me for production + +#ifdef DEBUG +#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a) +#else +#define DPRINTF(x...) +#endif + +/* + * Defines, simple typedefs etc. + */ + +#define W9966_DRIVERNAME "W9966CF Webcam" +#define W9966_MAXCAMS 4 // Maximum number of cameras +#define W9966_RBUFFER 2048 // Read buffer (must be an even number) +#define W9966_SRAMSIZE 131072 // 128kb +#define W9966_SRAMID 0x02 // check w9966cf.pdf + +// Empirically determined window limits +#define W9966_WND_MIN_X 16 +#define W9966_WND_MIN_Y 14 +#define W9966_WND_MAX_X 705 +#define W9966_WND_MAX_Y 253 +#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) +#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) + +// Keep track of our current state +#define W9966_STATE_PDEV 0x01 +#define W9966_STATE_CLAIMED 0x02 +#define W9966_STATE_VDEV 0x04 + +#define W9966_I2C_W_ID 0x48 +#define W9966_I2C_R_ID 0x49 +#define W9966_I2C_R_DATA 0x08 +#define W9966_I2C_R_CLOCK 0x04 +#define W9966_I2C_W_DATA 0x02 +#define W9966_I2C_W_CLOCK 0x01 + +struct w9966_dev { + unsigned char dev_state; + unsigned char i2c_state; + unsigned short 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; +}; + +/* + * Module specific properties + */ + +MODULE_AUTHOR("Jakob Kemi "); +MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); + +#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 int parmode = 0; +MODULE_PARM(parmode, "i"); +MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); + +static int video_nr = -1; +MODULE_PARM(video_nr, "i"); + +/* + * Private data + */ + +static struct w9966_dev w9966_cams[W9966_MAXCAMS]; + +/* + * Private function declares + */ + +static inline void w9966_setState(struct w9966_dev* cam, int mask, int val); +static inline int w9966_getState(struct w9966_dev* cam, int mask, int val); +static inline void w9966_pdev_claim(struct w9966_dev *vdev); +static inline void w9966_pdev_release(struct w9966_dev *vdev); + +static int w9966_rReg(struct w9966_dev* cam, int reg); +static int w9966_wReg(struct w9966_dev* cam, int reg, int data); +static int w9966_rReg_i2c(struct w9966_dev* cam, int reg); +static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data); +static int w9966_findlen(int near, int size, int maxlen); +static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor); +static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h); + +static int w9966_init(struct w9966_dev* cam, struct parport* port); +static void w9966_term(struct w9966_dev* cam); + +static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state); +static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state); +static inline int w9966_i2c_getsda(struct w9966_dev* cam); +static inline int w9966_i2c_getscl(struct w9966_dev* cam); +static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); +static int w9966_i2c_rbyte(struct w9966_dev* cam); + +static int w9966_v4l_open(struct video_device *vdev, int mode); +static void w9966_v4l_close(struct video_device *vdev); +static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); +static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock); + +/* + * Private function defines + */ + + +// Set camera phase flags, so we know what to uninit when terminating +static inline void w9966_setState(struct w9966_dev* cam, int mask, int val) +{ + cam->dev_state = (cam->dev_state & ~mask) ^ val; +} + +// Get camera phase flags +static inline int w9966_getState(struct w9966_dev* cam, int mask, int val) +{ + return ((cam->dev_state & mask) == val); +} + +// Claim parport for ourself +static inline void w9966_pdev_claim(struct w9966_dev* cam) +{ + if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) + return; + parport_claim_or_block(cam->pdev); + w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); +} + +// Release parport for others to use +static inline void w9966_pdev_release(struct w9966_dev* cam) +{ + if (w9966_getState(cam, W9966_STATE_CLAIMED, 0)) + return; + parport_release(cam->pdev); + w9966_setState(cam, W9966_STATE_CLAIMED, 0); +} + +// Read register from W9966 interface-chip +// Expects a claimed pdev +// -1 on error, else register data (byte) +static int w9966_rReg(struct w9966_dev* cam, int reg) +{ + // ECP, read, regtransfer, REG, REG, REG, REG, REG + const unsigned char addr = 0x80 | (reg & 0x1f); + unsigned char val; + + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) + return -1; + if (parport_write(cam->pport, &addr, 1) != 1) + return -1; + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) + return -1; + if (parport_read(cam->pport, &val, 1) != 1) + return -1; + + return val; +} + +// Write register to W9966 interface-chip +// Expects a claimed pdev +// -1 on error +static int w9966_wReg(struct w9966_dev* cam, int reg, int data) +{ + // ECP, write, regtransfer, REG, REG, REG, REG, REG + const unsigned char addr = 0xc0 | (reg & 0x1f); + const unsigned char val = data; + + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) + return -1; + if (parport_write(cam->pport, &addr, 1) != 1) + return -1; + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) + return -1; + if (parport_write(cam->pport, &val, 1) != 1) + return -1; + + return 0; +} + +// Initialize camera device. Setup all internal flags, set a +// default video mode, setup ccd-chip, register v4l device etc.. +// Also used for 'probing' of hardware. +// -1 on error +static int w9966_init(struct w9966_dev* cam, struct parport* port) +{ + if (cam->dev_state != 0) + return -1; + + cam->pport = port; + cam->brightness = 128; + cam->contrast = 64; + cam->color = 64; + cam->hue = 0; + +// Select requested transfer mode + switch(parmode) + { + default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) + 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 + cam->ppmode = IEEE1284_MODE_ECP; + break; + case 1: // hw- or sw-ecp + cam->ppmode = IEEE1284_MODE_ECP; + break; + case 2: // hw- or sw-epp + cam->ppmode = IEEE1284_MODE_EPP; + break; + } + +// Tell the parport driver that we exists + cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); + if (cam->pdev == NULL) { + DPRINTF("parport_register_device() failed\n"); + return -1; + } + w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); + + w9966_pdev_claim(cam); + +// Setup a default capture mode + if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { + DPRINTF("w9966_setup() failed.\n"); + return -1; + } + + w9966_pdev_release(cam); + +// Fill in the video_device struct and register us to v4l + memset(&cam->vdev, 0, sizeof(struct video_device)); + strcpy(cam->vdev.name, W9966_DRIVERNAME); + cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; + cam->vdev.hardware = VID_HARDWARE_W9966; + cam->vdev.open = &w9966_v4l_open; + cam->vdev.close = &w9966_v4l_close; + cam->vdev.read = &w9966_v4l_read; + cam->vdev.ioctl = &w9966_v4l_ioctl; + cam->vdev.priv = (void*)cam; + cam->vdev.owner = THIS_MODULE; + + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) + return -1; + + w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); + + // All ok + printk( + "w9966cf: Found and initialized a webcam on %s.\n", + cam->pport->name + ); + return 0; +} + + +// Terminate everything gracefully +static void w9966_term(struct w9966_dev* cam) +{ +// Unregister from v4l + if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { + video_unregister_device(&cam->vdev); + w9966_setState(cam, W9966_STATE_VDEV, 0); + } + +// Terminate from IEEE1284 mode and release pdev block + if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { + w9966_pdev_claim(cam); + parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); + w9966_pdev_release(cam); + } + +// Unregister from parport + if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { + parport_unregister_device(cam->pdev); + w9966_setState(cam, W9966_STATE_PDEV, 0); + } +} + + +// Find a good length for capture window (used both for W and H) +// A bit ugly but pretty functional. The capture length +// have to match the downscale +static int w9966_findlen(int near, int size, int maxlen) +{ + int bestlen = size; + int besterr = abs(near - bestlen); + int len; + + for(len = size+1;len < maxlen;len++) + { + int err; + if ( ((64*size) %len) != 0) + continue; + + err = abs(near - len); + + // Only continue as long as we keep getting better values + if (err > besterr) + break; + + besterr = err; + bestlen = len; + } + + return bestlen; +} + +// Modify capture window (if necessary) +// and calculate downscaling +// Return -1 on error +static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor) +{ + int maxlen = max - min; + int len = *end - *beg + 1; + int newlen = w9966_findlen(len, size, maxlen); + int err = newlen - len; + + // Check for bad format + if (newlen > maxlen || newlen < size) + return -1; + + // Set factor (6 bit fixed) + *factor = (64*size) / newlen; + if (*factor == 64) + *factor = 0x00; // downscale is disabled + else + *factor |= 0x80; // set downscale-enable bit + + // Modify old beginning and end + *beg -= err / 2; + *end += err - (err / 2); + + // Move window if outside borders + if (*beg < min) { + *end += min - *beg; + *beg += min - *beg; + } + if (*end > max) { + *beg -= *end - max; + *end -= *end - max; + } + + return 0; +} + +// Setup the cameras capture window etc. +// Expects a claimed pdev +// return -1 on error +static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) +{ + unsigned int i; + unsigned int enh_s, enh_e; + unsigned char scale_x, scale_y; + unsigned char regs[0x1c]; + unsigned char 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, + 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 + }; + + + if (w*h*2 > W9966_SRAMSIZE) + { + DPRINTF("capture window exceeds SRAM size!.\n"); + w = 200; h = 160; // Pick default values + } + + w &= ~0x1; + if (w < 2) w = 2; + if (h < 1) h = 1; + if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W; + if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H; + + cam->width = w; + cam->height = h; + + enh_s = 0; + enh_e = w*h*2; + +// Modify capture window if necessary and calculate downscaling + if ( + w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || + w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0 + ) return -1; + + DPRINTF( + "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", + w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80 + ); + +// Setup registers + regs[0x00] = 0x00; // Set normal operation + regs[0x01] = 0x18; // Capture mode + regs[0x02] = scale_y; // V-scaling + regs[0x03] = scale_x; // H-scaling + + // Capture window + regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits) + regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits) + regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits) + regs[0x07] = (y1 & 0x300)>>8; // Y-start (2 high bits) + regs[0x08] = (x2 & 0x0ff); // X-end (8 low bits) + regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits) + regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits) + + regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb) + + // Enhancement layer + regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7) + regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15) + regs[0x0f] = (enh_s& 0x70000)>>16; // Enh. start (16-17/18??) + regs[0x10] = (enh_e& 0x000ff); // Enh. end (0-7) + regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15) + regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??) + + // Misc + regs[0x13] = 0x40; // VEE control (raw 4:2:2) + regs[0x17] = 0x00; // ??? + regs[0x18] = cam->i2c_state = 0x00; // Serial bus + regs[0x19] = 0xff; // I/O port direction control + regs[0x1a] = 0xff; // I/O port data register + regs[0x1b] = 0x10; // ??? + + // SAA7111 chip settings + saa7111_regs[0x0a] = cam->brightness; + saa7111_regs[0x0b] = cam->contrast; + saa7111_regs[0x0c] = cam->color; + saa7111_regs[0x0d] = cam->hue; + +// Reset (ECP-fifo & serial-bus) + if (w9966_wReg(cam, 0x00, 0x03) == -1) + return -1; + +// Write regs to w9966cf chip + for (i = 0; i < 0x1c; i++) + if (w9966_wReg(cam, i, regs[i]) == -1) + return -1; + +// Write regs to saa7111 chip + for (i = 0; i < 0x20; i++) + if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1) + return -1; + + return 0; +} + +/* + * Ugly and primitive i2c protocol functions + */ + +// Sets the data line on the i2c bus. +// Expects a claimed pdev. +static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state) +{ + if (state) + cam->i2c_state |= W9966_I2C_W_DATA; + else + cam->i2c_state &= ~W9966_I2C_W_DATA; + + w9966_wReg(cam, 0x18, cam->i2c_state); + udelay(5); +} + +// Sets the clock line on the i2c bus. +// Expects a claimed pdev. -1 on error +static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state) +{ + int timeout; + if (state) + cam->i2c_state |= W9966_I2C_W_CLOCK; + else + cam->i2c_state &= ~W9966_I2C_W_CLOCK; + + w9966_wReg(cam, 0x18, cam->i2c_state); + udelay(5); + + // we go to high, we also expect the peripheral to ack. + if (state) { + timeout = jiffies + 100; + while (!w9966_i2c_getscl(cam)) { + if (jiffies > timeout) + return -1; + } + } + return 0; +} + +// Get peripheral data line +// Expects a claimed pdev. +static inline int w9966_i2c_getsda(struct w9966_dev* cam) +{ + const unsigned char state = w9966_rReg(cam, 0x18); + return ((state & W9966_I2C_R_DATA) > 0); +} + +// Get peripheral clock line +// Expects a claimed pdev. +static inline int w9966_i2c_getscl(struct w9966_dev* cam) +{ + const unsigned char state = w9966_rReg(cam, 0x18); + return ((state & W9966_I2C_R_CLOCK) > 0); +} + +// Write a byte with ack to the i2c bus. +// Expects a claimed pdev. -1 on error +static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) +{ + int i; + for (i = 7; i >= 0; i--) + { + w9966_i2c_setsda(cam, (data >> i) & 0x01); + + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + w9966_i2c_setscl(cam, 0); + } + + w9966_i2c_setsda(cam, 1); + + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + w9966_i2c_setscl(cam, 0); + + return 0; +} + +// Read a data byte with ack from the i2c-bus +// Expects a claimed pdev. -1 on error +static int w9966_i2c_rbyte(struct w9966_dev* cam) +{ + unsigned char data = 0x00; + int i; + + w9966_i2c_setsda(cam, 1); + + for (i = 0; i < 8; i++) + { + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + data = data << 1; + if (w9966_i2c_getsda(cam)) + data |= 0x01; + + w9966_i2c_setscl(cam, 0); + } + return data; +} + +// Read a register from the i2c device. +// Expects claimed pdev. -1 on error +static int w9966_rReg_i2c(struct w9966_dev* cam, int reg) +{ + int data; + + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + if ( + w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || + w9966_i2c_wbyte(cam, reg) == -1 + ) + return -1; + + w9966_i2c_setsda(cam, 1); + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + if ( + w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 || + (data = w9966_i2c_rbyte(cam)) == -1 + ) + return -1; + + w9966_i2c_setsda(cam, 0); + + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + w9966_i2c_setsda(cam, 1); + + 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) +{ + w9966_i2c_setsda(cam, 0); + w9966_i2c_setscl(cam, 0); + + if ( + w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || + w9966_i2c_wbyte(cam, reg) == -1 || + w9966_i2c_wbyte(cam, data) == -1 + ) + return -1; + + w9966_i2c_setsda(cam, 0); + if (w9966_i2c_setscl(cam, 1) == -1) + return -1; + + w9966_i2c_setsda(cam, 1); + + return 0; +} + +/* + * Video4linux interfacing + */ + +static int w9966_v4l_open(struct video_device *vdev, int flags) +{ + return 0; +} + +static void w9966_v4l_close(struct video_device *vdev) +{ +} + +static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability vcap = { + W9966_DRIVERNAME, // name + VID_TYPE_CAPTURE | VID_TYPE_SCALES, // type + 1, 0, // vid, aud channels + W9966_WND_MAX_W, // max w + W9966_WND_MAX_H, // max h + 2, 1 // min w, min h + }; + + if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel vch; + if(copy_from_user(&vch, arg, sizeof(vch)) != 0) + return -EFAULT; + + if(vch.channel != 0) // We only support one channel (#0) + return -EINVAL; + + strcpy(vch.name, "CCD-input"); + vch.flags = 0; // We have no tuner or audio + vch.tuners = 0; + vch.type = VIDEO_TYPE_CAMERA; + vch.norm = 0; // ??? + + if(copy_to_user(arg, &vch, sizeof(vch)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel vch; + if(copy_from_user(&vch, arg, sizeof(vch) ) != 0) + return -EFAULT; + + if(vch.channel != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner vtune; + if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0) + return -EFAULT; + + if(vtune.tuner != 0); + return -EINVAL; + + strcpy(vtune.name, "no tuner"); + vtune.rangelow = 0; + vtune.rangehigh = 0; + vtune.flags = VIDEO_TUNER_NORM; + vtune.mode = VIDEO_MODE_AUTO; + vtune.signal = 0xffff; + + if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner vtune; + if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0) + return -EFAULT; + + if (vtune.tuner != 0) + return -EINVAL; + + if (vtune.mode != VIDEO_MODE_AUTO) + return -EINVAL; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture vpic = { + cam->brightness << 8, // brightness + (cam->hue + 128) << 8, // hue + cam->color << 9, // color + cam->contrast << 9, // contrast + 0x8000, // whiteness + 16, VIDEO_PALETTE_YUV422// bpp, palette format + }; + + if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0) + return -EFAULT; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture vpic; + if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0) + return -EFAULT; + + if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422) + return -EINVAL; + + cam->brightness = vpic.brightness >> 8; + cam->hue = (vpic.hue >> 8) - 128; + cam->color = vpic.colour >> 9; + cam->contrast = vpic.contrast >> 9; + + w9966_pdev_claim(cam); + + if ( + w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 || + w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 || + w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 || + w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1 + ) { + w9966_pdev_release(cam); + return -EFAULT; + } + + w9966_pdev_release(cam); + return 0; + } + case VIDIOCSWIN: + { + int ret; + struct video_window vwin; + + if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0) + return -EFAULT; + if (vwin.flags != 0) + return -EINVAL; + if (vwin.clipcount != 0) + return -EINVAL; + if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W) + return -EINVAL; + if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H) + return -EINVAL; + + // Update camera regs + w9966_pdev_claim(cam); + ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height); + w9966_pdev_release(cam); + + if (ret != 0) { + DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); + return -EFAULT; + } + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vwin; + memset(&vwin, 0, sizeof(vwin)); + + vwin.width = cam->width; + vwin.height = cam->height; + + if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0) + return -EFAULT; + + return 0; + } + // Unimplemented + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +// Capture data +static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock) +{ + struct w9966_dev *cam = (struct w9966_dev *)vdev->priv; + unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 + unsigned char* dest = (unsigned char*)buf; + unsigned long dleft = count; + + // Why would anyone want more than this?? + if (count > cam->width * cam->height * 2) + return -EINVAL; + + w9966_pdev_claim(cam); + w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer + w9966_wReg(cam, 0x00, 0x00); // Return to normal operation + w9966_wReg(cam, 0x01, 0x98); // Enable capture + + // write special capture-addr and negotiate into data transfer + if ( + (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )|| + (parport_write(cam->pport, &addr, 1) != 1 )|| + (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 ) + ) { + w9966_pdev_release(cam); + return -EFAULT; + } + + 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) { + w9966_pdev_release(cam); + return -EFAULT; + } + if (copy_to_user(dest, tbuf, tsize) != 0) { + w9966_pdev_release(cam); + return -EFAULT; + } + dest += tsize; + dleft -= tsize; + } + + w9966_wReg(cam, 0x01, 0x18); // Disable capture + w9966_pdev_release(cam); + + return count; +} + + +// Called once for every parport on init +static void w9966_attach(struct parport *port) +{ + int i; + + for (i = 0; i < W9966_MAXCAMS; i++) + { + 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 (w9966_init(&w9966_cams[i], port) != 0) + w9966_term(&w9966_cams[i]); + break; // return + } + } +} + +// Called once for every parport on termination +static void w9966_detach(struct parport *port) +{ + int i; + for (i = 0; i < W9966_MAXCAMS; i++) + if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) + w9966_term(&w9966_cams[i]); +} + + +static struct parport_driver w9966_ppd = { + W9966_DRIVERNAME, + w9966_attach, + w9966_detach, + NULL +}; + +// Module entry point +static int __init w9966_mod_init(void) +{ + int i; + for (i = 0; i < W9966_MAXCAMS; i++) + w9966_cams[i].dev_state = 0; + + return parport_register_driver(&w9966_ppd); +} + +// Module cleanup +static void __exit w9966_mod_term(void) +{ + parport_unregister_driver(&w9966_ppd); +} + +module_init(w9966_mod_init); +module_exit(w9966_mod_term); diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.4/linux/drivers/media/video/zr36120.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/zr36120.c Mon May 21 17:06:00 2001 @@ -57,11 +57,15 @@ static unsigned int triton1=0; /* triton1 chipset? */ static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; +static int video_nr = -1; +static int vbi_nr = -1; MODULE_AUTHOR("Pauline Middelink "); MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); MODULE_PARM(triton1,"i"); MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i"); +MODULE_PARM(video_nr,"i"); +MODULE_PARM(vbi_nr,"i"); static int zoran_cards; static struct zoran zorans[ZORAN_MAX]; @@ -1194,8 +1198,10 @@ vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); if (vcp==NULL) return -ENOMEM; - if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) + if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) { + vfree(vcp); return -EFAULT; + } on = ztv->running; if (on) @@ -1990,13 +1996,13 @@ ztv->video_dev = zr36120_template; strcpy(ztv->video_dev.name, ztv->i2c.name); ztv->video_dev.priv = ztv; - if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) + if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) return -1; ztv->vbi_dev = vbi_template; strcpy(ztv->vbi_dev.name, ztv->i2c.name); ztv->vbi_dev.priv = ztv; - if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) { + if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) { video_unregister_device(&ztv->video_dev); return -1; } diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c --- v2.4.4/linux/drivers/mtd/ftl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/ftl.c Sat Apr 28 11:27:54 2001 @@ -915,9 +915,6 @@ static release_t ftl_close(struct inode *inode, struct file *file) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - struct super_block *sb = get_super(inode->i_rdev); -#endif int minor = MINOR(inode->i_rdev); partition_t *part = myparts[minor >> 4]; int i; @@ -925,11 +922,7 @@ DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); /* Flush all writes */ - fsync_dev(inode->i_rdev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (sb) invalidate_inodes(sb); -#endif - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); /* Wait for any pending erase operations to complete */ if (part->mtd->sync) diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c --- v2.4.4/linux/drivers/mtd/mtdblock.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/mtdblock.c Sat Apr 28 11:27:54 2001 @@ -355,19 +355,12 @@ { int dev; struct mtdblk_dev *mtdblk; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - struct super_block * sb = get_super(inode->i_rdev); -#endif DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); if (inode == NULL) release_return(-ENODEV); - fsync_dev(inode->i_rdev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (sb) invalidate_inodes(sb); -#endif - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); dev = MINOR(inode->i_rdev); mtdblk = mtdblks[dev]; diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/mtdchar.c linux/drivers/mtd/mtdchar.c --- v2.4.4/linux/drivers/mtd/mtdchar.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/mtdchar.c Mon May 21 17:06:29 2001 @@ -310,8 +310,10 @@ if (!databuf) return -ENOMEM; - if (copy_from_user(databuf, buf.ptr, buf.length)) + if (copy_from_user(databuf, buf.ptr, buf.length)) { + kfree(databuf); return -EFAULT; + } ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf); diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/nftl.c linux/drivers/mtd/nftl.c --- v2.4.4/linux/drivers/mtd/nftl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/nftl.c Sat Apr 28 11:27:54 2001 @@ -997,17 +997,13 @@ static int nftl_release(struct inode *inode, struct file *fp) { - struct super_block *sb = get_super(inode->i_rdev); struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - fsync_dev(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); diff -u --recursive --new-file v2.4.4/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.4/linux/drivers/net/8139too.c Thu Apr 19 09:32:48 2001 +++ linux/drivers/net/8139too.c Mon May 7 14:13:19 2001 @@ -149,7 +149,7 @@ #include -#define RTL8139_VERSION "0.9.16" +#define RTL8139_VERSION "0.9.17" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -728,7 +728,7 @@ struct rtl8139_private *tp; u8 tmp8; int rc; - unsigned int i, have_pci_pm = 1; + unsigned int i; u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; @@ -770,10 +770,6 @@ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - /* ugly hueristic, but it's a chicken-and-egg problem */ - if (pio_len < RTL8139B_IO_SIZE) - have_pci_pm = 0; - #ifdef USE_IO_OPS /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { @@ -824,30 +820,7 @@ #endif /* USE_IO_OPS */ /* Bring old chips out of low-power mode. */ - if (have_pci_pm) { - u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - if ((rtl_chip_info[tp->chipset].flags & HasLWake) && - (tmp8 & LWAKE)) - new_tmp8 &= ~LWAKE; - new_tmp8 |= Cfg1_PM_Enable; - if (new_tmp8 != tmp8) { - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tmp8); - RTL_W8 (Cfg9346, Cfg9346_Lock); - } - if (rtl_chip_info[tp->chipset].flags & HasLWake) { - tmp8 = RTL_R8 (Config4); - if (tmp8 & LWPTN) - RTL_W8 (Config4, tmp8 & ~LWPTN); - } - } else { - RTL_W8 (HltClk, 'R'); - tmp8 = RTL_R8 (Config1); - tmp8 &= ~(SLEEP | PWRDN); - RTL_W8 (Config1, tmp8); - } - - rtl8139_chip_reset (ioaddr); + RTL_W8 (HltClk, 'R'); /* check for missing/broken hardware */ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { @@ -877,6 +850,32 @@ tp->chipset, rtl_chip_info[tp->chipset].name); + if (tp->chipset >= CH_8139B) { + u8 new_tmp8 = tmp8 = RTL_R8 (Config1); + DPRINTK("PCI PM wakeup\n"); + if ((rtl_chip_info[tp->chipset].flags & HasLWake) && + (tmp8 & LWAKE)) + new_tmp8 &= ~LWAKE; + new_tmp8 |= Cfg1_PM_Enable; + if (new_tmp8 != tmp8) { + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8); + RTL_W8 (Cfg9346, Cfg9346_Lock); + } + if (rtl_chip_info[tp->chipset].flags & HasLWake) { + tmp8 = RTL_R8 (Config4); + if (tmp8 & LWPTN) + RTL_W8 (Config4, tmp8 & ~LWPTN); + } + } else { + DPRINTK("Old chip wakeup\n"); + tmp8 = RTL_R8 (Config1); + tmp8 &= ~(SLEEP | PWRDN); + RTL_W8 (Config1, tmp8); + } + + rtl8139_chip_reset (ioaddr); + DPRINTK ("EXIT, returning 0\n"); *dev_out = dev; return 0; @@ -1358,11 +1357,16 @@ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; - printk(KERN_INFO"%s: Setting %s%s-duplex based on" + if (mii_reg5) { + printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", tp->full_duplex ? "full" : "half", mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } } if (tp->chipset >= CH_8139B) { @@ -1542,11 +1546,18 @@ || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); + + if (mii_reg5) { + printk (KERN_INFO + "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", + dev->name, + tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } #if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); diff -u --recursive --new-file v2.4.4/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.4.4/linux/drivers/net/8390.c Thu Apr 19 09:34:52 2001 +++ linux/drivers/net/8390.c Wed May 16 10:25:38 2001 @@ -453,6 +453,8 @@ { if (!netif_running(dev)) { printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); + /* rmk - acknowledge the interrupts */ + outb_p(interrupts, e8390_base + EN0_ISR); interrupts = 0; break; } diff -u --recursive --new-file v2.4.4/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.4/linux/drivers/net/Config.in Sun Apr 22 15:43:21 2001 +++ linux/drivers/net/Config.in Sat May 19 17:55:11 2001 @@ -35,6 +35,9 @@ fi if [ "$CONFIG_PPC" = "y" ]; then tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE + if [ "$CONFIG_MACE" != "n" ]; then + bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT + fi tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E @@ -143,10 +146,11 @@ tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS fi - dep_tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 $CONFIG_PCI $CONFIG_EXPERIMENTAL + dep_tristate ' Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI dep_mbool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL + dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL @@ -261,6 +265,9 @@ dep_bool ' Aironet 4500/4800 I365 broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_I365 $CONFIG_EXPERIMENTAL fi dep_tristate ' Aironet 4500/4800 PROC interface ' CONFIG_AIRONET4500_PROC $CONFIG_AIRONET4500 m + +# New directory for Wireless LAN devices - cards above will move there + source drivers/net/wireless/Config.in fi endmenu diff -u --recursive --new-file v2.4.4/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.4/linux/drivers/net/Makefile Thu Apr 19 22:46:05 2001 +++ linux/drivers/net/Makefile Wed May 16 10:25:38 2001 @@ -8,7 +8,7 @@ obj-n := obj- := -mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wan +mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wireless wan O_TARGET := net.o @@ -30,6 +30,7 @@ endif subdir-$(CONFIG_NET_PCMCIA) += pcmcia +subdir-$(CONFIG_NET_RADIO) += wireless subdir-$(CONFIG_TULIP) += tulip subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring @@ -75,6 +76,7 @@ obj-$(CONFIG_ACENIC) += acenic.o obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_STNIC) += stnic.o 8390.o +obj-$(CONFIG_FEALNX) += fealnx.o ifeq ($(CONFIG_SK98LIN),y) obj-y += sk98lin/sk98lin.o diff -u --recursive --new-file v2.4.4/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.4.4/linux/drivers/net/acenic.h Thu Apr 12 12:11:39 2001 +++ linux/drivers/net/acenic.h Sun May 20 12:11:38 2001 @@ -1,6 +1,7 @@ #ifndef _ACENIC_H_ #define _ACENIC_H_ +#include /* * Generate TX index update each time, when TX ring is closed. diff -u --recursive --new-file v2.4.4/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.4.4/linux/drivers/net/acenic_firmware.h Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/acenic_firmware.h Tue May 1 22:03:44 2001 @@ -17,7 +17,7 @@ #define tigonFwSbssLen 0x38 #define tigonFwBssAddr 0x00015dd0 #define tigonFwBssLen 0x2080 -#ifndef CONFIG_ACENIC_OMIT_TIGON_I +#ifdef CONFIG_ACENIC_OMIT_TIGON_I #define tigonFwText 0 #define tigonFwData 0 #define tigonFwRodata 0 diff -u --recursive --new-file v2.4.4/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c --- v2.4.4/linux/drivers/net/appletalk/cops.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/appletalk/cops.c Wed May 16 10:31:27 2001 @@ -1,7 +1,7 @@ /* cops.c: LocalTalk driver for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist * * With more than a little help from; * - Alan Cox @@ -34,7 +34,7 @@ */ static const char *version = -"cops.c:v0.04 6/7/98 Jay Schulist \n"; +"cops.c:v0.04 6/7/98 Jay Schulist \n"; /* * Sources: * COPS Localtalk SDK. This provides almost all of the information diff -u --recursive --new-file v2.4.4/linux/drivers/net/appletalk/cops.h linux/drivers/net/appletalk/cops.h --- v2.4.4/linux/drivers/net/appletalk/cops.h Fri Mar 3 12:54:44 2000 +++ linux/drivers/net/appletalk/cops.h Wed May 16 10:31:27 2001 @@ -1,7 +1,7 @@ /* cops.h: LocalTalk driver for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #ifndef __LINUX_COPSLTALK_H diff -u --recursive --new-file v2.4.4/linux/drivers/net/appletalk/cops_ffdrv.h linux/drivers/net/appletalk/cops_ffdrv.h --- v2.4.4/linux/drivers/net/appletalk/cops_ffdrv.h Mon Dec 11 13:00:20 2000 +++ linux/drivers/net/appletalk/cops_ffdrv.h Wed May 16 10:31:27 2001 @@ -21,7 +21,7 @@ /* cops_ffdrv.h: LocalTalk driver firmware dump for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #include diff -u --recursive --new-file v2.4.4/linux/drivers/net/appletalk/cops_ltdrv.h linux/drivers/net/appletalk/cops_ltdrv.h --- v2.4.4/linux/drivers/net/appletalk/cops_ltdrv.h Mon Dec 11 13:00:20 2000 +++ linux/drivers/net/appletalk/cops_ltdrv.h Wed May 16 10:31:27 2001 @@ -20,7 +20,7 @@ /* cops_ltdrv.h: LocalTalk driver firmware dump for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #include diff -u --recursive --new-file v2.4.4/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c --- v2.4.4/linux/drivers/net/appletalk/ipddp.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/net/appletalk/ipddp.c Wed May 16 10:31:27 2001 @@ -4,7 +4,7 @@ * * Authors: * - DDP-IP Encap by: Bradford W. Johnson - * - DDP-IP Decap by: Jay Schulist + * - DDP-IP Decap by: Jay Schulist * * Derived from: * - Almost all code already existed in net/appletalk/ddp.c I just @@ -14,7 +14,7 @@ * Written 1993-94 by Donald Becker. * - dummy.c: A dummy net driver. By Nick Holloway. * - MacGate: A user space Daemon for Appletalk-IP Decap for - * Linux by Jay Schulist + * Linux by Jay Schulist * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. @@ -69,7 +69,7 @@ printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", dev->name); if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", dev->name); /* Fill in the device structure with ethernet-generic values. */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.4.4/linux/drivers/net/bmac.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/bmac.c Wed May 16 09:58:36 2001 @@ -76,9 +76,6 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; - int reset_and_enabled; - int rx_allocated; - int tx_allocated; unsigned short hash_use_count[64]; unsigned short hash_table_mask[4]; struct net_device *next_bmac; @@ -126,6 +123,7 @@ }; static struct net_device *bmac_devs; +static unsigned char *bmac_emergency_rxbuf; #ifdef CONFIG_PMAC_PBOOK static int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -151,9 +149,9 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *bmac_stats(struct net_device *dev); static void bmac_set_multicast(struct net_device *dev); -static int bmac_reset_and_enable(struct net_device *dev, int enable); +static void bmac_reset_and_enable(struct net_device *dev); static void bmac_start_chip(struct net_device *dev); -static int bmac_init_chip(struct net_device *dev); +static void bmac_init_chip(struct net_device *dev); static void bmac_init_registers(struct net_device *dev); static void bmac_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); @@ -185,17 +183,6 @@ } static void -dbdma_stop(volatile struct dbdma_regs *dmap) -{ - dbdma_st32((volatile unsigned long *)&dmap->control, - DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH)); - eieio(); - - while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH)) - eieio(); -} - -static void dbdma_continue(volatile struct dbdma_regs *dmap) { dbdma_st32((volatile unsigned long *)&dmap->control, @@ -467,12 +454,11 @@ } } -static int +static void bmac_init_chip(struct net_device *dev) { bmac_init_phy(dev); bmac_init_registers(dev); - return 1; } #ifdef CONFIG_PMAC_PBOOK @@ -503,7 +489,7 @@ break; case PBOOK_WAKE: /* see if this is enough */ - bmac_reset_and_enable(bmac_devs, 1); + bmac_reset_and_enable(bmac_devs); enable_irq(bmac_devs->irq); enable_irq(bp->tx_dma_intr); enable_irq(bp->rx_dma_intr); @@ -569,9 +555,12 @@ } static void -bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp) +bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp) { - dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0); + unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf; + + dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, + virt_to_bus(addr), 0); } /* Bit-reverse one byte of an ethernet hardware address. */ @@ -586,7 +575,7 @@ } -static int +static void bmac_init_tx_ring(struct bmac_data *bp) { volatile struct dbdma_regs *td = bp->tx_dma; @@ -605,9 +594,6 @@ dbdma_reset(td); out_le32(&td->wait_sel, 0x00200020); out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds)); - - return 1; - } static int @@ -615,22 +601,20 @@ { volatile struct dbdma_regs *rd = bp->rx_dma; int i; + struct sk_buff *skb; /* initialize list of sk_buffs for receiving and set up recv dma */ - if (!bp->rx_allocated) { - for (i = 0; i < N_RX_RING; i++) { - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - if (bp->rx_bufs[i] == NULL) - return 0; - skb_reserve(bp->rx_bufs[i], 2); + memset((char *)bp->rx_cmds, 0, + (N_RX_RING + 1) * sizeof(struct dbdma_cmd)); + for (i = 0; i < N_RX_RING; i++) { + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(skb, 2); } - bp->rx_allocated = 1; + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); } - memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < N_RX_RING; i++) - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); - bp->rx_empty = 0; bp->rx_fill = i; @@ -706,27 +690,36 @@ cp = &bp->rx_cmds[i]; stat = ld_le16(&cp->xfer_status); residual = ld_le16(&cp->res_count); - if ((stat & ACTIVE) == 0) break; + if ((stat & ACTIVE) == 0) + break; nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; bp->stats.rx_length_errors++; bp->stats.rx_errors++; - } else skb = bp->rx_bufs[i]; + } else { + skb = bp->rx_bufs[i]; + bp->rx_bufs[i] = NULL; + } if (skb != NULL) { nb -= ETHERCRC; skb_put(skb, nb); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - skb_reserve(bp->rx_bufs[i], 2); - bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]); + dev->last_rx = jiffies; ++bp->stats.rx_packets; bp->stats.rx_bytes += nb; } else { ++bp->stats.rx_dropped; } + dev->last_rx = jiffies; + if ((skb = bp->rx_bufs[i]) == NULL) { + bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); + if (skb != NULL) + skb_reserve(bp->rx_bufs[i], 2); + } + bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); last = i; @@ -772,7 +765,13 @@ if (txintcount < 10) { XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); } - if (!(stat & ACTIVE)) break; + if (!(stat & ACTIVE)) { + /* + * status field might not have been filled by DBDMA + */ + if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr))) + break; + } if (bp->tx_bufs[bp->tx_empty]) { ++bp->stats.tx_packets; @@ -1215,7 +1214,7 @@ } } -static int bmac_reset_and_enable(struct net_device *dev, int enable) +static void bmac_reset_and_enable(struct net_device *dev) { struct bmac_data *bp = dev->priv; unsigned long flags; @@ -1223,22 +1222,19 @@ unsigned char *data; save_flags(flags); cli(); - bp->reset_and_enabled = 0; bmac_reset_chip(dev); - if (enable) { - if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) - return 0; - if (!bmac_init_chip(dev)) - return 0; - bmac_start_chip(dev); - bmwrite(dev, INTDISABLE, EnableNormal); - bp->reset_and_enabled = 1; - - /* - * It seems that the bmac can't receive until it's transmitted - * a packet. So we give it a dummy packet to transmit. - */ - skb = dev_alloc_skb(ETHERMINPACKET); + bmac_init_tx_ring(bp); + bmac_init_rx_ring(bp); + bmac_init_chip(dev); + bmac_start_chip(dev); + bmwrite(dev, INTDISABLE, EnableNormal); + + /* + * It seems that the bmac can't receive until it's transmitted + * a packet. So we give it a dummy packet to transmit. + */ + skb = dev_alloc_skb(ETHERMINPACKET); + if (skb != NULL) { data = skb_put(skb, ETHERMINPACKET); memset(data, 0, ETHERMINPACKET); memcpy(data, dev->dev_addr, 6); @@ -1246,13 +1242,14 @@ bmac_transmit_packet(skb, dev); } restore_flags(flags); - return 1; } static int __init bmac_probe(void) { struct device_node *bmac; + MOD_INC_USE_COUNT; + for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next) bmac_probe1(bmac, 0); for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0; @@ -1265,7 +1262,10 @@ pmu_register_sleep_notifier(&bmac_sleep_notifier); #endif } - return 0; + + MOD_DEC_USE_COUNT; + + return bmac_devs? 0: -ENODEV; } static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) @@ -1290,6 +1290,14 @@ } } + if (bmac_emergency_rxbuf == NULL) { + bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL); + if (bmac_emergency_rxbuf == NULL) { + printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n"); + return; + } + } + dev = init_etherdev(NULL, PRIV_BYTES); if (!dev) { printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", @@ -1390,9 +1398,7 @@ { /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ - if (!bmac_reset_and_enable(dev, 1)) - return -ENOMEM; - + bmac_reset_and_enable(dev); dev->flags |= IFF_RUNNING; return 0; } @@ -1428,7 +1434,6 @@ bp->rx_bufs[i] = NULL; } } - bp->rx_allocated = 0; XXDEBUG(("bmac: free tx bufs\n")); for (i = 0; itx_bufs[i] != NULL) { @@ -1436,7 +1441,6 @@ bp->tx_bufs[i] = NULL; } } - bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); return 0; @@ -1607,6 +1611,11 @@ { struct bmac_data *bp; struct net_device *dev; + + if (bmac_emergency_rxbuf != NULL) { + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; + } if (bmac_devs == 0) return; diff -u --recursive --new-file v2.4.4/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.4/linux/drivers/net/dmfe.c Wed Apr 25 16:14:08 2001 +++ linux/drivers/net/dmfe.c Sat May 19 18:05:23 2001 @@ -1,82 +1,56 @@ /* - dmfe.c: Version 1.30 06/11/2000 + dmfe.c: Version 1.36p1 2001-05-12 for Linux kernel 2.4.x - A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. - Copyright (C) 1997 Sten Wang - (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. + A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast + ethernet driver for Linux. + Copyright (C) 1997 Sten Wang - 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 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. + 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. + DAVICOM Web-Site: www.davicom.com.tw - Compiler command: - "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall - -Wstrict-prototypes -O6 -c dmfe.c" - OR - "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net -Wall - -Wstrict-prototypes -O6 -c dmfe.c" + Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw + Maintainer: Tobias Ringstrom - The following steps teach you how to active DM9102 board: - 1. Used the upper compiler command to compile dmfe.c - 2. insert dmfe module into kernel - "insmod dmfe" ;;Auto Detection Mode - "insmod dmfe mode=0" ;;Force 10M Half Duplex - "insmod dmfe mode=1" ;;Force 100M Half Duplex - "insmod dmfe mode=4" ;;Force 10M Full Duplex - "insmod dmfe mode=5" ;;Force 100M Full Duplex - 3. config a dm9102 network interface - "ifconfig eth0 172.22.3.18" - 4. active the IP routing table - "route add -net 172.22.3.0 eth0" - 5. Well done. Your DM9102 adapter actived now. + (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. - Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw + Marcelo Tosatti : + Made it compile in 2.3 (device to net_device) - Date: 10/28,1998 + Alan Cox : + Cleaned up for kernel merge. + Removed the back compatibility support + Reformatted, fixing spelling etc as I went + Removed IRQ 0-15 assumption - (C)Copyright 1997-1998 DAVICOM Semiconductor, Inc. All Rights Reserved. + Jeff Garzik : + Updated to use new PCI driver API. + Resource usage cleanups. + Report driver version to user. - Marcelo Tosatti : - Made it compile in 2.3 (device to net_device) - - Alan Cox : - Cleaned up for kernel merge. - Removed the back compatibility support - Reformatted, fixing spelling etc as I went - Removed IRQ 0-15 assumption + Tobias Ringstrom : + Cleaned up and added SMP safety. Thanks go to Jeff Garzik, + Andrew Morton and Frank Davis for the SMP safety fixes. - Jeff Garzik : - Updated to use new PCI driver API. - Resource usage cleanups. - Report driver version to user. + TODO - Tobias Ringstr÷m : - Added additional proper locking - Rewrote the transmit code to actually use the ring buffer, - and to generate a lot fewer interrupts. + Implement pci_driver::suspend() and pci_driver::resume() + power management methods. - Frank Davis - Added SMP-safe locking mechanisms in addition to Andrew Morton's work + Check and fix on 64bit and big endian boxes. - TODO + Test and make sure PCI latency is now correct for all cases. +*/ - Implement pci_driver::suspend() and pci_driver::resume() - power management methods. - - Check and fix on 64bit and big endian boxes. - - Test and make sure PCI latency is now correct for all cases. - - */ - -#define DMFE_VERSION "1.30p3 (April 17, 2001)" +#define DMFE_VERSION "1.36p1 (May 12, 2001)" #include @@ -87,7 +61,7 @@ #include #include #include -#include +#include #include #include #include @@ -103,54 +77,58 @@ #include #include -static char version[] __initdata = -KERN_INFO "Davicom DM91xx net driver, version " DMFE_VERSION "\n"; - - /* Board/System/Debug information/definition ---------------- */ -#define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */ -#define PCI_DM9102_ID 0x91021282 /* Davicom DM9102 ID */ -#define PCI_DM9100_ID 0x91001282 /* Davicom DM9100 ID */ +#define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */ +#define PCI_DM9102_ID 0x91021282 /* Davicom DM9102 ID */ +#define PCI_DM9100_ID 0x91001282 /* Davicom DM9100 ID */ +#define PCI_DM9009_ID 0x90091282 /* Davicom DM9009 ID */ #define DMFE_SUCC 0 #define DM9102_IO_SIZE 0x80 #define DM9102A_IO_SIZE 0x100 -#define TX_FREE_DESC_CNT 0xc /* Tx packet count */ -#define TX_MAX_SEND_CNT 0x1 /* Maximum tx packet per time */ -#define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */ -#define RX_DESC_CNT 0x10 /* Allocated Rx descriptors */ -#define TX_IRQ_THR 12 -#define DESC_ALL_CNT TX_DESC_CNT+RX_DESC_CNT +#define TX_MAX_SEND_CNT 0x1 /* Maximum tx packet per time */ +#define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */ +#define RX_DESC_CNT 0x20 /* Allocated Rx descriptors */ +#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2) /* Max TX packet count */ +#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3) /* TX wakeup count */ +#define DESC_ALL_CNT (TX_DESC_CNT + RX_DESC_CNT) #define TX_BUF_ALLOC 0x600 #define RX_ALLOC_SIZE 0x620 #define DM910X_RESET 1 -#define CR6_DEFAULT 0x00280000 /* SF, HD */ -#define CR7_DEFAULT 0x1a2cd -#define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */ -#define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */ +#define CR0_DEFAULT 0x00E00000 /* TX & RX burst mode */ +#define CR6_DEFAULT 0x00080000 /* HD */ +#define CR7_DEFAULT 0x180c1 +#define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */ +#define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */ #define MAX_PACKET_SIZE 1514 #define DMFE_MAX_MULTICAST 14 -#define RX_MAX_TRAFFIC 0x14000 +#define RX_COPY_SIZE 100 #define MAX_CHECK_PACKET 0x8000 +#define DM9801_NOISE_FLOOR 8 +#define DM9802_NOISE_FLOOR 5 #define DMFE_10MHF 0 #define DMFE_100MHF 1 #define DMFE_10MFD 4 #define DMFE_100MFD 5 #define DMFE_AUTO 8 +#define DMFE_1M_HPNA 0x10 + +#define DMFE_TXTH_72 0x400000 /* TX TH 72 byte */ +#define DMFE_TXTH_96 0x404000 /* TX TH 96 byte */ +#define DMFE_TXTH_128 0x0000 /* TX TH 128 byte */ +#define DMFE_TXTH_256 0x4000 /* TX TH 256 byte */ +#define DMFE_TXTH_512 0x8000 /* TX TH 512 byte */ +#define DMFE_TXTH_1K 0xC000 /* TX TH 1K byte */ + +#define DMFE_TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ +#define DMFE_TX_TIMEOUT (HZ * 1.5) /* tx packet time-out time 1.5 s" */ +#define DMFE_TX_KICK (HZ * 0.5) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_TIMER_WUT (HZ) /* timer wakeup time : 1 second */ -#define DMFE_TX_TIMEOUT ((HZ*3)/2) /* tx packet time-out time 1.5 s" */ +#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk(KERN_ERR ": %s %x\n", msg, vaule) -#define DMFE_DBUG(dbug_now, msg, value) \ - if (dmfe_debug || dbug_now) \ - printk("DBUG: %s %x\n", msg, value) - -#define SHOW_MEDIA_TYPE(mode) \ - printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n", \ - mode & 1 ? "100" : "10", \ - mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -164,20 +142,17 @@ #define PHY_DATA_0 0x00000 #define MDCLKH 0x10000 -#define SROM_CLK_WRITE(data, ioaddr) \ - outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ - udelay(5); \ - outl(data | CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, ioaddr); \ - udelay(5); \ - outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ - udelay(5); +#define PHY_POWER_DOWN 0x800 -#define __CHK_IO_SIZE(pci_id, dev_rev) \ - ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \ - DM9102A_IO_SIZE : DM9102_IO_SIZE -#define CHK_IO_SIZE(pci_dev, dev_rev) \ - __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) +#define SROM_V41_CODE 0x14 +#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5); + +#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE +#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) + +/* Sten Check */ +#define DEVICE net_device /* Structure/enum declaration ------------------------------- */ struct tx_desc { @@ -197,19 +172,26 @@ }; struct dmfe_board_info { - u32 chip_id; /* Chip vendor/Device ID */ - u32 chip_revision; /* Chip revision */ - struct net_device *next_dev; /* next device */ - spinlock_t lock; /* Spinlock */ - struct pci_dev *net_dev; /* PCI device */ + u32 chip_id; /* Chip vendor/Device ID */ + u32 chip_revision; /* Chip revision */ + struct DEVICE *next_dev; /* next device */ + struct pci_dev * net_dev; /* PCI device */ + spinlock_t lock; - unsigned long ioaddr; /* I/O base address */ + u32 ioaddr; /* I/O base address */ u32 cr0_data; u32 cr5_data; u32 cr6_data; u32 cr7_data; u32 cr15_data; - + + /* pointer for memory physical address */ + dma_addr_t buf_pool_dma_ptr; /* Tx buffer pool memory */ + dma_addr_t buf_pool_dma_start; /* Tx buffer pool align dword */ + dma_addr_t desc_pool_dma_ptr; /* descriptor pool memory */ + dma_addr_t first_tx_desc_dma; + dma_addr_t first_rx_desc_dma; + /* descriptor pointer */ unsigned char *buf_pool_ptr; /* Tx buffer pool memory */ unsigned char *buf_pool_start; /* Tx buffer pool align dword */ @@ -220,52 +202,82 @@ struct rx_desc *first_rx_desc; struct rx_desc *rx_insert_ptr; struct rx_desc *rx_ready_ptr; /* packet come pointer */ - int tx_int_pkt_num; /* number of packets to transmit until - * a transmit interrupt is requested */ - u32 tx_live_cnt; /* number of used/live tx slots */ - u32 rx_avail_cnt; /* available rx descriptor count */ - u32 interval_rx_cnt; /* rx packet count a callback time */ - - u16 phy_id2; /* Phyxcer ID2 */ - - u8 media_mode; /* user specify media mode */ - u8 op_mode; /* real work media mode */ + u32 tx_packet_cnt; /* transmitted packet count */ + u32 tx_queue_cnt; /* wait to send packet count */ + u32 rx_avail_cnt; /* available rx descriptor count */ + u32 interval_rx_cnt; /* rx packet count a callback time */ + + u16 HPNA_command; /* For HPNA register 16 */ + u16 HPNA_timer; /* For HPNA remote device check */ + u16 dbug_cnt; + u16 NIC_capability; /* NIC media capability */ + u16 PHY_reg4; /* Saved Phyxcer register 4 value */ + + u8 HPNA_present; /* 0:none, 1:DM9801, 2:DM9802 */ + u8 chip_type; /* Keep DM9102A chip type */ + u8 media_mode; /* user specify media mode */ + u8 op_mode; /* real work media mode */ u8 phy_addr; - u8 link_failed; /* Ever link failed */ - u8 wait_reset; /* Hardware failed, need to reset */ - u8 in_reset_state; /* Now driver in reset routine */ - u8 rx_error_cnt; /* recieved abnormal case count */ - u8 dm910x_chk_mode; /* Operating mode check */ + u8 link_failed; /* Ever link failed */ + u8 wait_reset; /* Hardware failed, need to reset */ + u8 dm910x_chk_mode; /* Operating mode check */ + u8 first_in_callback; /* Flag to record state */ struct timer_list timer; - struct net_device_stats stats; /* statistic counter */ + + /* System defined statistic counter */ + struct net_device_stats stats; + + /* Driver defined statistic counter */ + unsigned long tx_fifo_underrun; + unsigned long tx_loss_carrier; + unsigned long tx_no_carrier; + unsigned long tx_late_collision; + unsigned long tx_excessive_collision; + unsigned long tx_jabber_timeout; + unsigned long reset_count; + unsigned long reset_cr8; + unsigned long reset_fatal; + unsigned long reset_TXtimeout; + + /* NIC SROM data */ unsigned char srom[128]; }; enum dmfe_offsets { - DCR0 = 0, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, DCR5 = 0x28, - DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, DCR10 = 0x50, DCR11 = 0x58, - DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70, DCR15 = 0x78 + DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, + DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, + DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70, + DCR15 = 0x78 }; enum dmfe_CR6_bits { - CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, CR6_FDM = 0x200, - CR6_TXSC = 0x2000, CR6_STI = 0x100000, CR6_SFT = 0x200000, CR6_RXA = 0x40000000, - CR6_NO_PURGE = 0x20000000 + CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, + CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000, + CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000 }; /* Global variable declaration ----------------------------- */ -static int dmfe_debug; -static unsigned char dmfe_media_mode = 8; -static u32 dmfe_cr6_user_set; +static int __devinitdata printed_version; +static char version[] __devinitdata = + KERN_INFO "Davicom DM9xxx net driver, version " DMFE_VERSION "\n"; + +static int dmfe_debug = 0; +static unsigned char dmfe_media_mode = DMFE_AUTO; +static u32 dmfe_cr6_user_set = 0; /* For module input parameter */ -static int debug; -static u32 cr6set; +static int debug = 0; +static u32 cr6set = 0; static unsigned char mode = 8; static u8 chkmode = 1; +static u8 HPNA_mode = 0; /* Default: Low Power/High Speed */ +static u8 HPNA_rx_cmd = 0; /* Default: Disable Rx remote command */ +static u8 HPNA_tx_cmd = 0; /* Default: Don't issue remote command */ +static u8 HPNA_NoiseFloor = 0; /* Default: HPNA NoiseFloor */ +static u8 SF_mode = 0; /* Special Function: 1:VLAN, 2:RX Flow Control + 4: TX pause packet */ -static unsigned long CrcTable[256] = -{ +unsigned long CrcTable[256] = { 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, @@ -333,83 +345,73 @@ }; /* function declaration ------------------------------------- */ -static int dmfe_open(struct net_device *); -static int dmfe_start_xmit(struct sk_buff *, struct net_device *); -static int dmfe_stop(struct net_device *); -static struct net_device_stats *dmfe_get_stats(struct net_device *); -static void dmfe_set_filter_mode(struct net_device *); -static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int); -static u16 read_srom_word(long, int); -static void dmfe_interrupt(int, void *, struct pt_regs *); +static int dmfe_open(struct DEVICE *); +static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *); +static int dmfe_stop(struct DEVICE *); +static struct net_device_stats * dmfe_get_stats(struct DEVICE *); +static void dmfe_set_filter_mode(struct DEVICE *); +static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int); +static u16 read_srom_word(long ,int); +static void dmfe_interrupt(int , void *, struct pt_regs *); static void dmfe_descriptor_init(struct dmfe_board_info *, u32); static void allocated_rx_buffer(struct dmfe_board_info *); static void update_cr6(u32, u32); -static void send_filter_frame(struct net_device *, int); -static void dm9132_id_table(struct net_device *, int); +static void send_filter_frame(struct DEVICE * ,int); +static void dm9132_id_table(struct DEVICE * ,int); static u16 phy_read(u32, u8, u8, u32); static void phy_write(u32, u8, u8, u16, u32); static void phy_write_1bit(u32, u32); static u16 phy_read_1bit(u32); -static void dmfe_sense_speed(struct dmfe_board_info *); +static u8 dmfe_sense_speed(struct dmfe_board_info *); static void dmfe_process_mode(struct dmfe_board_info *); static void dmfe_timer(unsigned long); -static void dmfe_rx_packet(struct net_device *, struct dmfe_board_info *); +static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *); +static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *); static void dmfe_reused_skb(struct dmfe_board_info *, struct sk_buff *); -static void dmfe_dynamic_reset(struct net_device *); +static void dmfe_dynamic_reset(struct DEVICE *); static void dmfe_free_rxbuffer(struct dmfe_board_info *); -static void dmfe_init_dm910x(struct net_device *); +static void dmfe_init_dm910x(struct DEVICE *); static unsigned long cal_CRC(unsigned char *, unsigned int, u8); +static void dmfe_parse_srom(struct dmfe_board_info *); +static void dmfe_program_DM9801(struct dmfe_board_info *, int); +static void dmfe_program_DM9802(struct dmfe_board_info *); +static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * ); +static void dmfe_set_phyxcer(struct dmfe_board_info *); -/* DM910X network board routine ---------------------------- */ +/* DM910X network baord routine ---------------------------- */ /* - * Search DM910X board, allocate space and register it + * Search DM910X board ,allocate space and register it */ - -static int __init dmfe_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit dmfe_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { unsigned long pci_iobase; u8 pci_irqline; - struct dmfe_board_info *db; /* Point a board information structure */ + struct dmfe_board_info *db; /* board information structure */ int i; struct net_device *dev; - u32 dev_rev; - u16 pci_command; + u32 dev_rev, pci_pmr; -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; if (!printed_version++) printk(version); -#endif - DMFE_DBUG(0, "dmfe_probe()", 0); + DMFE_DBUG(0, "dmfe_init_one()", 0); /* Enable Master/IO access, Disable memory access */ i = pci_enable_device(pdev); - if (i) return i; - + if (i) + return i; pci_set_master(pdev); - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - pci_command &= ~PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); pci_iobase = pci_resource_start(pdev, 0); pci_irqline = pdev->irq; - /* Interrupt check */ - if (pci_irqline == 0) { - printk(KERN_ERR "dmfe(%s): Interrupt wrong : IRQ=%d\n", - pdev->slot_name, pci_irqline); - goto err_out; - } - /* iobase check */ - if (pci_iobase == 0 || pci_resource_len(pdev, 0) == 0) { - printk(KERN_ERR "dmfe(%s): I/O base is zero\n", pdev->slot_name); - goto err_out; + if (pci_iobase == 0) { + printk(KERN_ERR ": I/O base is zero\n"); + return -ENODEV; } #if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ @@ -427,15 +429,36 @@ /* Init network device */ dev = alloc_etherdev(sizeof(*db)); if (dev == NULL) - goto err_out; + return -ENOMEM; SET_MODULE_OWNER(dev); - if (pci_request_regions(pdev, "dmfe")) - goto err_out_netdev; + /* IO range check */ + if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) { + printk(KERN_ERR ": Allocated I/O size too small\n"); + goto err_out; + } + if (!request_region(pci_iobase, + pci_resource_len (pdev, 0), + dev->name)) { + printk(KERN_ERR ": I/O conflict : IO=%lx Range=%x\n", + pci_iobase, CHK_IO_SIZE(pdev, dev_rev)); + goto err_out; + } + + /* Init system & device */ db = dev->priv; - pci_set_drvdata(pdev, dev); - spin_lock_init(&db->lock); + + /* Allocated Tx/Rx descriptor memory */ + db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); + db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); + + db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr; + db->first_tx_desc_dma = db->desc_pool_dma_ptr; + db->buf_pool_start = db->buf_pool_ptr; + db->buf_pool_dma_start = db->buf_pool_dma_ptr; + + pdev->driver_data = dev; db->chip_id = ent->driver_data; db->ioaddr = pci_iobase; @@ -445,12 +468,21 @@ dev->base_addr = pci_iobase; dev->irq = pci_irqline; + pci_set_drvdata(pdev, dev); dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; dev->stop = &dmfe_stop; dev->get_stats = &dmfe_get_stats; dev->set_multicast_list = &dmfe_set_filter_mode; dev->do_ioctl = &dmfe_do_ioctl; + spin_lock_init(&db->lock); + + pci_read_config_dword(pdev, 0x50, &pci_pmr); + pci_pmr &= 0x70000; + if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) ) + db->chip_type = 1; /* DM9102A E3 */ + else + db->chip_type = 0; /* read 64 word srom data */ for (i = 0; i < 64; i++) @@ -460,9 +492,8 @@ for (i = 0; i < 6; i++) dev->dev_addr[i] = db->srom[20 + i]; - i = register_netdev(dev); - if (i) - goto err_out_res; + i = register_netdev (dev); + if (i) goto err_out; printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,", dev->name, @@ -474,11 +505,9 @@ return 0; -err_out_res: - pci_release_regions(pdev); -err_out_netdev: - kfree(dev); err_out: + pci_set_drvdata(pdev, NULL); + kfree(dev); return -ENODEV; } @@ -486,17 +515,22 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct dmfe_board_info *db; + struct dmfe_board_info *db = dev->priv; DMFE_DBUG(0, "dmfe_remove_one()", 0); - - db = dev->priv; - - unregister_netdev(dev); - pci_release_regions(pdev); - kfree(dev); /* free board information */ - pci_set_drvdata(pdev, NULL); + if (dev) { + pci_free_consistent(db->net_dev, sizeof(struct tx_desc) * + DESC_ALL_CNT + 0x20, db->desc_pool_ptr, + db->desc_pool_dma_ptr); + pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4, + db->buf_pool_ptr, db->buf_pool_dma_ptr); + unregister_netdev(dev); + release_region(dev->base_addr, + CHK_IO_SIZE(pdev, db->chip_revision)); + kfree(dev); /* free board information */ + pci_set_drvdata(pdev, NULL); + } DMFE_DBUG(0, "dmfe_remove_one() exit", 0); } @@ -506,107 +540,103 @@ * Open the interface. * The interface is opened whenever "ifconfig" actives it. */ - -static int dmfe_open(struct net_device *dev) + +static int dmfe_open(struct DEVICE *dev) { int ret; struct dmfe_board_info *db = dev->priv; DMFE_DBUG(0, "dmfe_open", 0); - ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); + ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); if (ret) return ret; - /* Allocated Tx/Rx descriptor memory */ - db->desc_pool_ptr = kmalloc(sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, GFP_KERNEL | GFP_DMA); - if (db->desc_pool_ptr == NULL) - return -ENOMEM; - if ((u32) db->desc_pool_ptr & 0x1f) - db->first_tx_desc = (struct tx_desc *) (((u32) db->desc_pool_ptr & ~0x1f) + 0x20); - else - db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr; - - /* Allocated Tx buffer memory */ - db->buf_pool_ptr = kmalloc(TX_BUF_ALLOC * TX_DESC_CNT + 4, GFP_KERNEL | GFP_DMA); - if (db->buf_pool_ptr == NULL) { - kfree(db->desc_pool_ptr); - return -ENOMEM; - } - if ((u32) db->buf_pool_ptr & 0x3) - db->buf_pool_start = (char *) (((u32) db->buf_pool_ptr & ~0x3) + 0x4); - else - db->buf_pool_start = db->buf_pool_ptr; - /* system variable init */ db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set; - db->tx_int_pkt_num = TX_IRQ_THR; - db->tx_live_cnt = 0; + db->tx_packet_cnt = 0; + db->tx_queue_cnt = 0; db->rx_avail_cnt = 0; - db->link_failed = 0; + db->link_failed = 1; db->wait_reset = 0; - db->in_reset_state = 0; - db->rx_error_cnt = 0; - if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) { - //db->cr6_data &= ~CR6_SFT; /* Used Tx threshold */ - //db->cr6_data |= CR6_NO_PURGE; /* No purge if rx unavailable */ - db->cr0_data = 0xc00000; /* TX/RX desc burst mode */ - db->dm910x_chk_mode = 4; /* Enter the normal mode */ - } else { + db->first_in_callback = 0; + db->NIC_capability = 0xf; /* All capability*/ + db->PHY_reg4 = 0x1e0; + + /* CR6 operation mode decision */ + if ( !chkmode || (db->chip_id == PCI_DM9132_ID) || + (db->chip_revision >= 0x02000030) ) { + db->cr6_data |= DMFE_TXTH_256; + db->cr0_data = CR0_DEFAULT; + db->dm910x_chk_mode=4; /* Enter the normal mode */ + } else { + db->cr6_data |= CR6_SFT; /* Store & Forward mode */ db->cr0_data = 0; db->dm910x_chk_mode = 1; /* Enter the check mode */ } - /* Initialize DM910X board */ + /* Initilize DM910X board */ dmfe_init_dm910x(dev); + /* Active System Interface */ + netif_wake_queue(dev); + /* set and active a timer process */ init_timer(&db->timer); - db->timer.expires = jiffies + DMFE_TIMER_WUT; - db->timer.data = (unsigned long) dev; + db->timer.expires = DMFE_TIMER_WUT + HZ * 2; + db->timer.data = (unsigned long)dev; db->timer.function = &dmfe_timer; add_timer(&db->timer); - - netif_wake_queue(dev); return 0; } -/* Initialize DM910X board - Reset DM910X board - Initialize TX/Rx descriptor chain structure - Send the set-up frame - Enable Tx/Rx machine + +/* Initilize DM910X board + * Reset DM910X board + * Initilize TX/Rx descriptor chain structure + * Send the set-up frame + * Enable Tx/Rx machine */ -static void dmfe_init_dm910x(struct net_device *dev) + +static void dmfe_init_dm910x(struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; u32 ioaddr = db->ioaddr; - + DMFE_DBUG(0, "dmfe_init_dm910x()", 0); - /* Reset DM910x board : need 32 PCI clock to complete */ + /* Reset DM910x MAC controller */ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ - udelay(5); + udelay(100); outl(db->cr0_data, ioaddr + DCR0); - - outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ - outl(0x80, ioaddr + DCR12); /* RESET DM9102 phyxcer */ - outl(0x0, ioaddr + DCR12); /* Clear RESET signal */ + udelay(5); /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */ db->phy_addr = 1; - /* Media Mode Check */ + /* Parser SROM and media mode */ + dmfe_parse_srom(db); db->media_mode = dmfe_media_mode; - if (db->media_mode & DMFE_AUTO) - dmfe_sense_speed(db); - else - db->op_mode = db->media_mode; - dmfe_process_mode(db); - /* Initialize Transmit/Receive decriptor and CR3/4 */ + /* RESET Phyxcer Chip by GPR port bit 7 */ + outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ + if (db->chip_id == PCI_DM9009_ID) { + outl(0x80, ioaddr + DCR12); /* Issue RESET signal */ + mdelay(300); /* Delay 300 ms */ + } + outl(0x0, ioaddr + DCR12); /* Clear RESET signal */ + + /* Process Phyxcer Media Mode */ + if ( !(db->media_mode & 0x10) ) /* Force 1M mode */ + dmfe_set_phyxcer(db); + + /* Media Mode Process */ + if ( !(db->media_mode & DMFE_AUTO) ) + db->op_mode = db->media_mode; /* Force Mode */ + + /* Initiliaze Transmit/Receive decriptor and CR3/4 */ dmfe_descriptor_init(db, ioaddr); /* Init CR6 to program DM910x operation */ @@ -618,182 +648,184 @@ else send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ - /* Init CR5/CR7, interrupt active bit */ - outl(0xffffffff, ioaddr + DCR5); /* clear all CR5 status */ + /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; outl(db->cr7_data, ioaddr + DCR7); /* Init CR15, Tx jabber and Rx watchdog timer */ - db->cr15_data = CR15_DEFAULT; outl(db->cr15_data, ioaddr + DCR15); /* Enable DM910X Tx/Rx function */ - db->cr6_data |= CR6_RXSC | CR6_TXSC; + db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000; update_cr6(db->cr6_data, ioaddr); - } /* - Hardware start transmission. - Send a packet to media from the upper layer. + * Hardware start transmission. + * Send a packet to media from the upper layer. */ -static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev) + +static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; struct tx_desc *txptr; unsigned long flags; DMFE_DBUG(0, "dmfe_start_xmit", 0); + + /* Resource flag check */ + netif_stop_queue(dev); + + /* Too large packet check */ + if (skb->len > MAX_PACKET_SIZE) { + printk(KERN_ERR ": big packet = %d\n", (u16)skb->len); + dev_kfree_skb(skb); + return 0; + } + spin_lock_irqsave(&db->lock, flags); - - /* transmit this packet */ - txptr = db->tx_insert_ptr; - memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len); - if (--db->tx_int_pkt_num < 0) - { - txptr->tdes1 = 0xe1000000 | skb->len; - db->tx_int_pkt_num = TX_IRQ_THR; + + /* No Tx resource check, it never happen nromally */ + if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { + spin_unlock_irqrestore(&db->lock, flags); + printk(KERN_ERR ": No Tx resource %d\n", db->tx_queue_cnt); + return 1; } - else - txptr->tdes1 = 0x61000000 | skb->len; - /* Transmit Packet Process */ - txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */ - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ - dev->trans_start = jiffies; /* saved the time stamp */ + /* Disable NIC interrupt */ + outl(0, dev->base_addr + DCR7); - /* Point to next transmit free descriptor */ - txptr = (struct tx_desc *)txptr->next_tx_desc; + /* transmit this packet */ + txptr = db->tx_insert_ptr; + memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len); + txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); - if (txptr->tdes0 & 0x80000000) - netif_stop_queue(dev); + /* Point to next transmit free descriptor */ + db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; - db->tx_insert_ptr = txptr; - db->tx_live_cnt++; + /* Transmit Packet Process */ + if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) { + txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */ + db->tx_packet_cnt++; /* Ready to send */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */ + dev->trans_start = jiffies; /* saved time stamp */ + } else { + db->tx_queue_cnt++; /* queue TX packet */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */ + } - spin_unlock_irqrestore(&db->lock, flags); + /* Tx resource check */ + if ( db->tx_queue_cnt < TX_FREE_DESC_CNT ) + netif_wake_queue(dev); /* free this SKB */ dev_kfree_skb(skb); + /* Restore CR7 to enable interrupt */ + spin_unlock_irqrestore(&db->lock, flags); + outl(db->cr7_data, dev->base_addr + DCR7); + return 0; } + /* * Stop the interface. * The interface is stopped when it is brought. */ -static int dmfe_stop(struct net_device *dev) +static int dmfe_stop(struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; u32 ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); + /* disable system */ netif_stop_queue(dev); + /* deleted timer */ + del_timer_sync(&db->timer); + /* Reset & stop DM910X board */ outl(DM910X_RESET, ioaddr + DCR0); udelay(5); + phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); - /* deleted timer */ - del_timer_sync(&db->timer); - /* free interrupt */ free_irq(dev->irq, dev); /* free allocated rx buffer */ dmfe_free_rxbuffer(db); - /* free all descriptor memory and buffer memory */ - kfree(db->desc_pool_ptr); - kfree(db->buf_pool_ptr); +#if 0 + /* show statistic counter */ + printk(": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + db->tx_fifo_underrun, db->tx_excessive_collision, + db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, + db->tx_jabber_timeout, db->reset_count, db->reset_cr8, + db->reset_fatal, db->reset_TXtimeout); +#endif return 0; } + /* - DM9102 interrupt handler - receive the packet to upper layer, free the transmitted packet + * DM9102 insterrupt handler + * receive the packet to upper layer, free the transmitted packet */ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = dev_id; - struct tx_desc *txptr; - struct dmfe_board_info *db; - u32 ioaddr; + struct DEVICE *dev = dev_id; + struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + u32 ioaddr = dev->base_addr; unsigned long flags; + DMFE_DBUG(0, "dmfe_interrupt()", 0); + if (!dev) { - DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0); + DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0); return; } - /* A real interrupt coming */ - db = (struct dmfe_board_info *) dev->priv; - ioaddr = dev->base_addr; - - DMFE_DBUG(0, "dmfe_interrupt()", 0); spin_lock_irqsave(&db->lock, flags); - /* Disable all interrupt in CR7 to solve the interrupt edge problem */ - outl(0, ioaddr + DCR7); - /* Got DM910X status */ db->cr5_data = inl(ioaddr + DCR5); outl(db->cr5_data, ioaddr + DCR5); - /* printk("CR5=%x\n", db->cr5_data); */ + if ( !(db->cr5_data & 0xc1) ) { + spin_unlock_irqrestore(&db->lock, flags); + return; + } + + /* Disable all interrupt in CR7 to solve the interrupt edge problem */ + outl(0, ioaddr + DCR7); /* Check system status */ if (db->cr5_data & 0x2000) { - /* A system bus error occurred */ - DMFE_DBUG(1, "A system bus error occurred. CR5=", db->cr5_data); - netif_stop_queue(dev); - db->wait_reset = 1; /* Need to RESET */ - outl(0, ioaddr + DCR7); /* disable all interrupt */ + /* system bus error happen */ + DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data); + db->reset_fatal++; + db->wait_reset = 1; /* Need to RESET */ spin_unlock_irqrestore(&db->lock, flags); return; } - /* Free the transmitted descriptor */ - txptr = db->tx_remove_ptr; - while (db->tx_live_cnt > 0 && (txptr->tdes0 & 0x80000000) == 0) - { - /* printk("tdes0=%x\n", txptr->tdes0); */ - db->stats.tx_packets++; - - if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) { - /* printk("tdes0=%x\n", txptr->tdes0); */ - db->stats.tx_errors++; - } - /* Transmit statistic counter */ - if (txptr->tdes0 != 0x7fffffff) { - /* printk("tdes0=%x\n", txptr->tdes0); */ - db->stats.collisions += (txptr->tdes0 >> 3) & 0xf; - db->stats.tx_bytes += txptr->tdes1 & 0x7ff; - if (txptr->tdes0 & TDES0_ERR_MASK) - db->stats.tx_errors++; - } - txptr = (struct tx_desc *) txptr->next_tx_desc; - db->tx_live_cnt--; - } - /* Update TX remove pointer to next */ - db->tx_remove_ptr = (struct tx_desc *) txptr; - - if ((db->tx_insert_ptr->tdes0 & 0x80000000) == 0) - netif_wake_queue(dev); - - /* Received the coming packet */ - if (db->rx_avail_cnt) + /* Received the coming packet */ + if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) dmfe_rx_packet(dev, db); /* reallocated rx descriptor buffer */ - if (db->rx_avail_cnt < RX_DESC_CNT) + if (db->rx_avail_cntcr5_data & 0x01) + dmfe_free_tx_pkt(dev, db); + /* Mode Check */ if (db->dm910x_chk_mode & 0x2) { db->dm910x_chk_mode = 0x4; @@ -802,19 +834,85 @@ } /* Restore CR7 to enable interrupt mask */ - if (db->interval_rx_cnt > RX_MAX_TRAFFIC) - db->cr7_data = 0x1a28d; - else - db->cr7_data = 0x1a2cd; outl(db->cr7_data, ioaddr + DCR7); spin_unlock_irqrestore(&db->lock, flags); } + /* - Receive the come packet and pass to upper layer + * Free TX resource after TX complete */ -static void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db) + +static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) +{ + struct tx_desc *txptr; + u32 ioaddr = dev->base_addr; + + txptr = db->tx_remove_ptr; + while(db->tx_packet_cnt) { + /* printk(": tdes0=%x\n", txptr->tdes0); */ + if (txptr->tdes0 & 0x80000000) + break; + + /* A packet sent completed */ + db->tx_packet_cnt--; + db->stats.tx_packets++; + + /* Transmit statistic counter */ + if ( txptr->tdes0 != 0x7fffffff ) { + /* printk(": tdes0=%x\n", txptr->tdes0); */ + db->stats.collisions += (txptr->tdes0 >> 3) & 0xf; + db->stats.tx_bytes += txptr->tdes1 & 0x7ff; + if (txptr->tdes0 & TDES0_ERR_MASK) { + db->stats.tx_errors++; + + if (txptr->tdes0 & 0x0002) { /* UnderRun */ + db->tx_fifo_underrun++; + if ( !(db->cr6_data & CR6_SFT) ) { + db->cr6_data = db->cr6_data | CR6_SFT; + update_cr6(db->cr6_data, db->ioaddr); + } + } + if (txptr->tdes0 & 0x0100) + db->tx_excessive_collision++; + if (txptr->tdes0 & 0x0200) + db->tx_late_collision++; + if (txptr->tdes0 & 0x0400) + db->tx_no_carrier++; + if (txptr->tdes0 & 0x0800) + db->tx_loss_carrier++; + if (txptr->tdes0 & 0x4000) + db->tx_jabber_timeout++; + } + } + + txptr = (struct tx_desc *) txptr->next_tx_desc; + }/* End of while */ + + /* Update TX remove pointer to next */ + db->tx_remove_ptr = (struct tx_desc *) txptr; + + /* Send the Tx packet in queue */ + if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) { + txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */ + db->tx_packet_cnt++; /* Ready to send */ + db->tx_queue_cnt--; + outl(0x1, ioaddr + DCR1); /* Issue Tx polling */ + dev->trans_start = jiffies; /* saved time stamp */ + } + + /* Resource available check */ + if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT ) + netif_wake_queue(dev); /* Active upper layer, send again */ +} + + +/* + * Receive the come packet and pass to upper layer + */ + +static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) { struct rx_desc *rxptr; struct sk_buff *skb; @@ -822,26 +920,26 @@ rxptr = db->rx_ready_ptr; - while (db->rx_avail_cnt) { + while(db->rx_avail_cnt) { if (rxptr->rdes0 & 0x80000000) /* packet owner check */ break; db->rx_avail_cnt--; db->interval_rx_cnt++; - if ((rxptr->rdes0 & 0x300) != 0x300) { + if ( (rxptr->rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ /* reused this SKB */ DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); - /* db->rx_error_cnt++; */ } else { /* A packet with First/Last flag */ - rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4; /* skip CRC */ + rxlen = ( (rxptr->rdes0 >> 16) & 0x3fff) - 4; - if (rxptr->rdes0 & 0x8000) { /* error summary bit check */ + /* error summary bit check */ + if (rxptr->rdes0 & 0x8000) { /* This is a error packet */ - /* printk("rdes0 error : %x \n", rxptr->rdes0); */ + //printk(": rdes0: %lx\n", rxptr->rdes0); db->stats.rx_errors++; if (rxptr->rdes0 & 1) db->stats.rx_fifo_errors++; @@ -850,21 +948,36 @@ if (rxptr->rdes0 & 0x80) db->stats.rx_length_errors++; } - if (!(rxptr->rdes0 & 0x8000) || - ((db->cr6_data & CR6_PM) && (rxlen > 6))) { + + if ( !(rxptr->rdes0 & 0x8000) || + ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { skb = (struct sk_buff *) rxptr->rx_skb_ptr; /* Received Packet CRC check need or not */ - if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != (*(unsigned long *) (skb->tail + rxlen)))) { + if ( (db->dm910x_chk_mode & 1) && + (cal_CRC(skb->tail, rxlen, 1) != + (*(unsigned long *) (skb->tail+rxlen) ) + ) ) { /* Found a error received packet */ dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; } else { - /* A good packet coming, send to upper layer */ - skb->dev = dev; - skb_put(skb, rxlen); + /* Good packet, send to upper layer */ + /* Shorst packet used new SKB */ + if ( (rxlen < RX_COPY_SIZE) && + ( (skb = dev_alloc_skb(rxlen + 2) ) + != NULL) ) { + /* size less than COPY_SIZE, allocated a rxlen SKB */ + skb->dev = dev; + skb_reserve(skb, 2); /* 16byte align */ + memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen); + dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + } else { + skb->dev = dev; + skb_put(skb, rxlen); + } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* Send to upper layer */ + netif_rx(skb); dev->last_rx = jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rxlen; @@ -880,24 +993,27 @@ } db->rx_ready_ptr = rxptr; - } + /* - Get statistics from driver. + * Get statistics from driver. */ -static struct net_device_stats *dmfe_get_stats(struct net_device *dev) + +static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev) { - struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv; DMFE_DBUG(0, "dmfe_get_stats", 0); return &db->stats; } + /* - Set DM910X multicast address + * Set DM910X multicast address */ -static void dmfe_set_filter_mode(struct net_device *dev) + +static void dmfe_set_filter_mode(struct DEVICE * dev) { struct dmfe_board_info *db = dev->priv; unsigned long flags; @@ -912,6 +1028,7 @@ spin_unlock_irqrestore(&db->lock, flags); return; } + if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) { DMFE_DBUG(0, "Pass all multicast address", dev->mc_count); db->cr6_data &= ~(CR6_PM | CR6_PBF); @@ -919,83 +1036,97 @@ spin_unlock_irqrestore(&db->lock, flags); return; } + DMFE_DBUG(0, "Set multicast address", dev->mc_count); if (db->chip_id == PCI_DM9132_ID) dm9132_id_table(dev, dev->mc_count); /* DM9132 */ else - send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ + send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */ spin_unlock_irqrestore(&db->lock, flags); } -/* - Process the upper socket ioctl command - */ -/* - * The following function just returns 0. Shouldn't it do more? +/* + * Process the upper socket ioctl command */ -static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd) { DMFE_DBUG(0, "dmfe_do_ioctl()", 0); return 0; } + /* - A periodic timer routine - Dynamic media sense, allocated Rx buffer... + * A periodic timer routine + * Dynamic media sense, allocated Rx buffer... */ + static void dmfe_timer(unsigned long data) { u32 tmp_cr8; unsigned char tmp_cr12; - struct net_device *dev = (struct net_device *) data; + struct DEVICE *dev = (struct DEVICE *) data; struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; - unsigned long flags; + unsigned long flags; DMFE_DBUG(0, "dmfe_timer()", 0); spin_lock_irqsave(&db->lock, flags); - /* Do reset now */ - if (db->in_reset_state) { - spin_unlock_irqrestore(&db->lock, flags); - return; + /* Media mode process when Link OK before enter this route */ + if (db->first_in_callback == 0) { + db->first_in_callback = 1; + if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) { + db->cr6_data &= ~0x40000; + update_cr6(db->cr6_data, db->ioaddr); + phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); + db->cr6_data |= 0x40000; + update_cr6(db->cr6_data, db->ioaddr); + db->timer.expires = DMFE_TIMER_WUT + HZ * 2; + add_timer(&db->timer); + spin_unlock_irqrestore(&db->lock, flags); + return; + } } + /* Operating Mode Check */ - if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET)) { + if ( (db->dm910x_chk_mode & 0x1) && + (db->stats.rx_packets > MAX_CHECK_PACKET) ) db->dm910x_chk_mode = 0x4; - } + /* Dynamic reset DM910X : system error or transmit time-out */ tmp_cr8 = inl(db->ioaddr + DCR8); - if ((db->interval_rx_cnt == 0) && (tmp_cr8)) { + if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) { + db->reset_cr8++; db->wait_reset = 1; - /* printk("CR8 %x, Interval Rx %x\n", tmp_cr8, db->interval_rx_cnt); */ } - /* Receiving Traffic check */ - if (db->interval_rx_cnt > RX_MAX_TRAFFIC) - db->cr7_data = 0x1a28d; - else - db->cr7_data = 0x1a2cd; - outl(db->cr7_data, db->ioaddr + DCR7); - db->interval_rx_cnt = 0; - if (db->wait_reset || - (db->tx_live_cnt > 0 && - ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) || - (db->rx_error_cnt > 3)) { - /* - printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start); - */ - DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx monitor step1", 0); + /* TX polling kick monitor */ + if ( db->tx_packet_cnt && + ((jiffies - dev->trans_start) > DMFE_TX_KICK) ) { + outl(0x1, dev->base_addr + DCR1); /* Tx polling again */ + + /* TX Timeout */ + if ( (jiffies - dev->trans_start) > DMFE_TX_TIMEOUT ) { + db->reset_TXtimeout++; + db->wait_reset = 1; + printk(KERN_WARNING "%s: Tx timeout - resetting\n", + dev->name); + } + } + + if (db->wait_reset) { + DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt); + db->reset_count++; dmfe_dynamic_reset(dev); - db->timer.expires = jiffies + DMFE_TIMER_WUT; + db->first_in_callback = 0; + db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer); spin_unlock_irqrestore(&db->lock, flags); return; } - db->rx_error_cnt = 0; /* Clear previos counter */ /* Link status check, Dynamic media type change */ if (db->chip_id == PCI_DM9132_ID) @@ -1003,138 +1134,150 @@ else tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */ - if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) || - ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) { + if ( ((db->chip_id == PCI_DM9102_ID) && + (db->chip_revision == 0x02000030)) || + ((db->chip_id == PCI_DM9132_ID) && + (db->chip_revision == 0x02000010)) ) { /* DM9102A Chip */ if (tmp_cr12 & 2) tmp_cr12 = 0x0; /* Link failed */ else - tmp_cr12 = 0x3; /* Link OK */ + tmp_cr12 = 0x3; /* Link OK */ } - if (!(tmp_cr12 & 0x3) && !db->link_failed) { + + if ( !(tmp_cr12 & 0x3) && !db->link_failed ) { /* Link Failed */ DMFE_DBUG(0, "Link Failed", tmp_cr12); db->link_failed = 1; - phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); /* reset Phy */ - - /* 10/100M link failed, used 1M Home-Net */ - db->cr6_data |= 0x00040000; /* CR6 bit18 = 1, select Home-Net */ - db->cr6_data &= ~0x00000200; /* CR6 bit9 =0, half duplex mode */ - update_cr6(db->cr6_data, db->ioaddr); - - /* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */ - db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id); - if (db->phy_id2 == 0xb900) - phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id); - } else if ((tmp_cr12 & 0x3) && db->link_failed) { - DMFE_DBUG(0, "Link link OK", tmp_cr12); - db->link_failed = 0; - /* CR6 bit18=0, select 10/100M */ - db->cr6_data &= ~0x00040000; - update_cr6(db->cr6_data, db->ioaddr); + /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ + /* AUTO or force 1M Homerun/Longrun don't need */ + if ( !(db->media_mode & 0x38) ) + phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); + + /* AUTO mode, if INT phyxcer link failed, select EXT device */ + if (db->media_mode & DMFE_AUTO) { + /* 10/100M link failed, used 1M Home-Net */ + db->cr6_data|=0x00040000; /* bit18=1, MII */ + db->cr6_data&=~0x00000200; /* bit9=0, HD mode */ + update_cr6(db->cr6_data, db->ioaddr); + } + } else + if ((tmp_cr12 & 0x3) && db->link_failed) { + DMFE_DBUG(0, "Link link OK", tmp_cr12); + db->link_failed = 0; + + /* Auto Sense Speed */ + if ( (db->media_mode & DMFE_AUTO) && + dmfe_sense_speed(db) ) + db->link_failed = 1; + dmfe_process_mode(db); + /* SHOW_MEDIA_TYPE(db->op_mode); */ + } - /* Auto Sense Speed */ - if (db->media_mode & DMFE_AUTO) - dmfe_sense_speed(db); - dmfe_process_mode(db); - update_cr6(db->cr6_data, db->ioaddr); - /* SHOW_MEDIA_TYPE(db->op_mode); */ + /* HPNA remote command check */ + if (db->HPNA_command & 0xf00) { + db->HPNA_timer--; + if (!db->HPNA_timer) + dmfe_HPNA_remote_cmd_chk(db); } - /* reallocated rx descriptor buffer */ - if (db->rx_avail_cnt < RX_DESC_CNT) - allocated_rx_buffer(db); /* Timer active again */ - db->timer.expires = jiffies + DMFE_TIMER_WUT; + db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer); spin_unlock_irqrestore(&db->lock, flags); } + /* - Dynamic reset the DM910X board - Stop DM910X board - Free Tx/Rx allocated memory - Reset DM910X board - Re-initialize DM910X board + * Dynamic reset the DM910X board + * Stop DM910X board + * Free Tx/Rx allocated memory + * Reset DM910X board + * Re-initilize DM910X board */ -static void dmfe_dynamic_reset(struct net_device *dev) + +static void dmfe_dynamic_reset(struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; DMFE_DBUG(0, "dmfe_dynamic_reset()", 0); - /* Enter dynamic reset route */ - db->in_reset_state = 1; + /* Sopt MAC controller */ + db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ + update_cr6(db->cr6_data, dev->base_addr); + outl(0, dev->base_addr + DCR7); /* Disable Interrupt */ + outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5); /* Disable upper layer interface */ netif_stop_queue(dev); - - db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ - update_cr6(db->cr6_data, dev->base_addr); /* Free Rx Allocate buffer */ dmfe_free_rxbuffer(db); /* system variable init */ - db->tx_int_pkt_num = TX_IRQ_THR; - db->tx_live_cnt = 0; + db->tx_packet_cnt = 0; + db->tx_queue_cnt = 0; db->rx_avail_cnt = 0; - db->link_failed = 0; + db->link_failed = 1; db->wait_reset = 0; - db->rx_error_cnt = 0; - /* Re-initialize DM910X board */ + /* Re-initilize DM910X board */ dmfe_init_dm910x(dev); - /* Leave dynamic reser route */ - db->in_reset_state = 0; - /* Restart upper layer interface */ netif_wake_queue(dev); } + /* - free all allocated rx buffer + * free all allocated rx buffer */ -static void dmfe_free_rxbuffer(struct dmfe_board_info *db) + +static void dmfe_free_rxbuffer(struct dmfe_board_info * db) { DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0); /* free allocated rx buffer */ while (db->rx_avail_cnt) { - dev_kfree_skb((void *) (db->rx_ready_ptr->rx_skb_ptr)); + dev_kfree_skb( (void *) (db->rx_ready_ptr->rx_skb_ptr) ); db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc; db->rx_avail_cnt--; } } + /* - Reused the SK buffer + * Reused the SK buffer */ -static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb) + +static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb) { struct rx_desc *rxptr = db->rx_insert_ptr; if (!(rxptr->rdes0 & 0x80000000)) { rxptr->rx_skb_ptr = (u32) skb; - rxptr->rdes2 = virt_to_bus(skb->tail); - rxptr->rdes0 = 0x80000000; + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc; } else DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt); } + /* - Initialize transmit/Receive descriptor - Using Chain structure, and allocated Tx/Rx buffer + * Initialize transmit/Receive descriptor + * Using Chain structure, and allocated Tx/Rx buffer */ + static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr) { struct tx_desc *tmp_tx; struct rx_desc *tmp_rx; unsigned char *tmp_buf; + dma_addr_t tmp_tx_dma, tmp_rx_dma; + dma_addr_t tmp_buf_dma; int i; DMFE_DBUG(0, "dmfe_descriptor_init()", 0); @@ -1142,67 +1285,77 @@ /* tx descriptor start pointer */ db->tx_insert_ptr = db->first_tx_desc; db->tx_remove_ptr = db->first_tx_desc; - outl(virt_to_bus(db->first_tx_desc), ioaddr + DCR4); /* Init CR4 */ + outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ - db->first_rx_desc = (struct rx_desc *) - ((u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT); + db->first_rx_desc = (struct rx_desc *) ( (u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT ); + db->first_rx_desc_dma = ( db->first_tx_desc_dma + sizeof(struct rx_desc) * TX_DESC_CNT); db->rx_insert_ptr = db->first_rx_desc; db->rx_ready_ptr = db->first_rx_desc; - outl(virt_to_bus(db->first_rx_desc), ioaddr + DCR3); /* Init CR3 */ + outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */ /* Init Transmit chain */ tmp_buf = db->buf_pool_start; + tmp_buf_dma = db->buf_pool_dma_start; + tmp_tx_dma = db->first_tx_desc_dma; for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) { tmp_tx->tx_buf_ptr = (u32) tmp_buf; - tmp_tx->tdes0 = 0; - tmp_tx->tdes1 = 0x81000000; /* IC, chain */ - tmp_tx->tdes2 = (u32) virt_to_bus(tmp_buf); - tmp_tx->tdes3 = (u32) virt_to_bus(tmp_tx) + sizeof(struct tx_desc); + tmp_tx->tdes0 = cpu_to_le32(0); + tmp_tx->tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ + tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma); + tmp_tx_dma += sizeof(struct tx_desc); + tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma); tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc)); tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC); + tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC; } - (--tmp_tx)->tdes3 = (u32) virt_to_bus(db->first_tx_desc); + (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma); tmp_tx->next_tx_desc = (u32) db->first_tx_desc; - /* Init Receive descriptor chain */ + /* Init Receive descriptor chain */ + tmp_rx_dma=db->first_rx_desc_dma; for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) { - tmp_rx->rdes0 = 0; - tmp_rx->rdes1 = 0x01000600; - tmp_rx->rdes3 = (u32) virt_to_bus(tmp_rx) + sizeof(struct rx_desc); + tmp_rx->rdes0 = cpu_to_le32(0); + tmp_rx->rdes1 = cpu_to_le32(0x01000600); + tmp_rx_dma += sizeof(struct rx_desc); + tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma); tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc)); } - (--tmp_rx)->rdes3 = (u32) virt_to_bus(db->first_rx_desc); + (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma); tmp_rx->next_rx_desc = (u32) db->first_rx_desc; /* pre-allocated Rx buffer */ allocated_rx_buffer(db); } + /* - Update CR6 value - Firstly stop DM910X , then written value and start + * Update CR6 vaule + * Firstly stop DM910X , then written value and start */ + static void update_cr6(u32 cr6_data, u32 ioaddr) { u32 cr6_tmp; - cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ + cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ outl(cr6_tmp, ioaddr + DCR6); udelay(5); outl(cr6_data, ioaddr + DCR6); - cr6_tmp = inl(ioaddr + DCR6); - /* printk("CR6 update %x ", cr6_tmp); */ + udelay(5); } -/* Send a setup frame for DM9132 - This setup frame initialize DM910X address filter mode - */ -static void dm9132_id_table(struct net_device *dev, int mc_cnt) + +/* + * Send a setup frame for DM9132 + * This setup frame initilize DM910X addres filter mode +*/ + +static void dm9132_id_table(struct DEVICE *dev, int mc_cnt) { struct dev_mc_list *mcptr; - u16 *addrptr; - u32 ioaddr = dev->base_addr + 0xc0; /* ID Table */ + u16 * addrptr; + u32 ioaddr = dev->base_addr+0xc0; /* ID Table */ u32 hash_val; u16 i, hash_table[4]; @@ -1226,26 +1379,28 @@ /* the multicast address in Hash Table : 64 bits */ for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { - hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f; + hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f; hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); } /* Write the hash table to MAC MD table */ - for (i = 0; i < 4; i++, ioaddr += 4) { + for (i = 0; i < 4; i++, ioaddr += 4) outw(hash_table[i], ioaddr); - } } -/* Send a setup frame for DM9102/DM9102A - This setup frame initialize DM910X address filter mode + +/* + * Send a setup frame for DM9102/DM9102A + * This setup frame initilize DM910X addres filter mode */ -static void send_filter_frame(struct net_device *dev, int mc_cnt) + +static void send_filter_frame(struct DEVICE *dev, int mc_cnt) { struct dmfe_board_info *db = dev->priv; struct dev_mc_list *mcptr; struct tx_desc *txptr; - u16 *addrptr; - u32 *suptr; + u16 * addrptr; + u32 * suptr; int i; DMFE_DBUG(0, "send_filter_frame()", 0); @@ -1253,12 +1408,6 @@ txptr = db->tx_insert_ptr; suptr = (u32 *) txptr->tx_buf_ptr; - if (txptr->tdes0 & 0x80000000) { - printk(KERN_WARNING "%s: Too busy to send filter frame\n", - dev->name); - return; - } - /* Node address */ addrptr = (u16 *) dev->dev_addr; *suptr++ = addrptr[0]; @@ -1278,26 +1427,35 @@ *suptr++ = addrptr[2]; } - for (i=0; i < 14; i++) + for (; i<14; i++) { *suptr++ = 0xffff; *suptr++ = 0xffff; *suptr++ = 0xffff; - + } + /* prepare the setup frame */ db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; - db->tx_live_cnt++; - txptr->tdes1 = 0x890000c0; - /* Send the setup packet */ - txptr->tdes0 = 0x80000000; - update_cr6(db->cr6_data | 0x2000, dev->base_addr); - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ - update_cr6(db->cr6_data, dev->base_addr); + txptr->tdes1 = cpu_to_le32(0x890000c0); + + /* Resource Check and Send the setup packet */ + if (!db->tx_packet_cnt) { + /* Resource Empty */ + db->tx_packet_cnt++; + txptr->tdes0 = cpu_to_le32(0x80000000); + update_cr6(db->cr6_data | 0x2000, dev->base_addr); + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */ + update_cr6(db->cr6_data, dev->base_addr); + dev->trans_start = jiffies; + } else + db->tx_queue_cnt++; /* Put in TX queue */ } + /* * Allocate rx buffer, - * Allocate as many Rx buffers as possible. + * As possible as allocated maxiumn Rx buffer */ + static void allocated_rx_buffer(struct dmfe_board_info *db) { struct rx_desc *rxptr; @@ -1305,12 +1463,12 @@ rxptr = db->rx_insert_ptr; - while (db->rx_avail_cnt < RX_DESC_CNT) { - if ((skb = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL) + while(db->rx_avail_cnt < RX_DESC_CNT) { + if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; rxptr->rx_skb_ptr = (u32) skb; - rxptr->rdes2 = virt_to_bus(skb->tail); - rxptr->rdes0 = 0x80000000; + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = (struct rx_desc *) rxptr->next_rx_desc; db->rx_avail_cnt++; } @@ -1318,9 +1476,11 @@ db->rx_insert_ptr = rxptr; } + /* - Read one word data from the serial ROM + * Read one word data from the serial ROM */ + static u16 read_srom_word(long ioaddr, int offset) { int i; @@ -1355,113 +1515,150 @@ return srom_data; } + /* * Auto sense the media mode */ - -static void dmfe_sense_speed(struct dmfe_board_info *db) + +static u8 dmfe_sense_speed(struct dmfe_board_info * db) { - int i; - u16 phy_mode = 0; + u8 ErrFlag = 0; + u16 phy_mode; - for (i = 1000; i; i--) { - udelay(5); - phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); - if ((phy_mode & 0x24) == 0x24) - break; - } + /* CR6 bit18=0, select 10/100M */ + update_cr6( (db->cr6_data & ~0x40000), db->ioaddr); + + phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); + phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); - if (i) { + if ( (phy_mode & 0x24) == 0x24 ) { if (db->chip_id == PCI_DM9132_ID) /* DM9132 */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000; - else /* DM9102/DM9102A */ + else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - /* printk("Phy_mode %x ",phy_mode); */ + /* printk(": Phy_mode %x ",phy_mode); */ switch (phy_mode) { - case 0x1000: - db->op_mode = DMFE_10MHF; - break; - case 0x2000: - db->op_mode = DMFE_10MFD; - break; - case 0x4000: - db->op_mode = DMFE_100MHF; - break; - case 0x8000: - db->op_mode = DMFE_100MFD; - break; - default: - db->op_mode = DMFE_10MHF; - DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode); + case 0x1000: db->op_mode = DMFE_10MHF; break; + case 0x2000: db->op_mode = DMFE_10MFD; break; + case 0x4000: db->op_mode = DMFE_100MHF; break; + case 0x8000: db->op_mode = DMFE_100MFD; break; + default: db->op_mode = DMFE_10MHF; + ErrFlag = 1; break; } } else { db->op_mode = DMFE_10MHF; DMFE_DBUG(0, "Link Failed :", phy_mode); + ErrFlag = 1; + } + + return ErrFlag; +} + + +/* + * Set 10/100 phyxcer capability + * AUTO mode : phyxcer register4 is NIC capability + * Force mode: phyxcer register4 is the force media + */ + +static void dmfe_set_phyxcer(struct dmfe_board_info *db) +{ + u16 phy_reg; + + /* Select 10/100M phyxcer */ + db->cr6_data &= ~0x40000; + update_cr6(db->cr6_data, db->ioaddr); + + /* DM9009 Chip: Phyxcer reg18 bit12=0 */ + if (db->chip_id == PCI_DM9009_ID) { + phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000; + phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id); + } + + /* Phyxcer capability setting */ + phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0; + + if (db->media_mode & DMFE_AUTO) { + /* AUTO Mode */ + phy_reg |= db->PHY_reg4; + } else { + /* Force Mode */ + switch(db->media_mode) { + case DMFE_10MHF: phy_reg |= 0x20; break; + case DMFE_10MFD: phy_reg |= 0x40; break; + case DMFE_100MHF: phy_reg |= 0x80; break; + case DMFE_100MFD: phy_reg |= 0x100; break; + } + if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61; } + + /* Write new capability to Phyxcer Reg4 */ + if ( !(phy_reg & 0x01e0)) { + phy_reg|=db->PHY_reg4; + db->media_mode|=DMFE_AUTO; + } + phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); + + /* Restart Auto-Negotiation */ + if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) ) + phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id); + if ( !db->chip_type ) + phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); } + /* - Process op-mode - AUTO mode : PHY controller in Auto-negotiation Mode - Force mode: PHY controller in force mode with HUB - N-way force capability with SWITCH + * Process op-mode + * AUTO mode : PHY controller in Auto-negotiation Mode + * Force mode: PHY controller in force mode with HUB + * N-way force capability with SWITCH */ + static void dmfe_process_mode(struct dmfe_board_info *db) { u16 phy_reg; /* Full Duplex Mode Check */ - db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ if (db->op_mode & 0x4) - db->cr6_data |= CR6_FDM; + db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */ + else + db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ - if (!(db->media_mode & DMFE_AUTO)) { /* Force Mode Check */ - /* User force the media type */ - phy_reg = phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id); - /* printk("Nway phy_reg5 %x ",phy_reg); */ - if (phy_reg & 0x1) { - /* parter own the N-Way capability */ - phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x1e0; - switch (db->op_mode) { - case DMFE_10MHF: - phy_reg |= 0x20; - break; - case DMFE_10MFD: - phy_reg |= 0x40; - break; - case DMFE_100MHF: - phy_reg |= 0x80; - break; - case DMFE_100MFD: - phy_reg |= 0x100; - break; - } - phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); - } else { - /* parter without the N-Way capability */ - switch (db->op_mode) { - case DMFE_10MHF: - phy_reg = 0x0; - break; - case DMFE_10MFD: - phy_reg = 0x100; - break; - case DMFE_100MHF: - phy_reg = 0x2000; - break; - case DMFE_100MFD: - phy_reg = 0x2100; - break; + /* Transciver Selection */ + if (db->op_mode & 0x10) /* 1M HomePNA */ + db->cr6_data |= 0x40000;/* External MII select */ + else + db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */ + + update_cr6(db->cr6_data, db->ioaddr); + + /* 10/100M phyxcer force mode need */ + if ( !(db->media_mode & 0x18)) { + /* Forece Mode */ + phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id); + if ( !(phy_reg & 0x1) ) { + /* parter without N-Way capability */ + phy_reg = 0x0; + switch(db->op_mode) { + case DMFE_10MHF: phy_reg = 0x0; break; + case DMFE_10MFD: phy_reg = 0x100; break; + case DMFE_100MHF: phy_reg = 0x2000; break; + case DMFE_100MFD: phy_reg = 0x2100; break; } phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); + if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) ) + mdelay(20); + phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); } } } + /* - Write a word to Phy register + * Write a word to Phy register */ + static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) { u16 i; @@ -1486,11 +1683,11 @@ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); - /* Send Phy address */ + /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register address */ + /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1499,14 +1696,16 @@ phy_write_1bit(ioaddr, PHY_DATA_0); /* Write a word data to PHY controller */ - for (i = 0x8000; i > 0; i >>= 1) + for ( i = 0x8000; i > 0; i >>= 1) phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0); } } + /* - Read a word data from phy register + * Read a word data from phy register */ + static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id) { int i; @@ -1519,8 +1718,8 @@ phy_data = inw(ioaddr); } else { /* DM9102/DM9102A Chip */ - ioaddr = iobase + DCR9; + /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1); @@ -1533,11 +1732,11 @@ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); - /* Send Phy address */ + /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register address */ + /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1554,41 +1753,47 @@ return phy_data; } + /* - Write one bit data to Phy Controller + * Write one bit data to Phy Controller */ + static void phy_write_1bit(u32 ioaddr, u32 phy_data) { - outl(phy_data, ioaddr); /* MII Clock Low */ + outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ udelay(1); - outl(phy_data, ioaddr); /* MII Clock Low */ + outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); } + /* - Read one bit phy data from PHY controller + * Read one bit phy data from PHY controller */ + static u16 phy_read_1bit(u32 ioaddr) { u16 phy_data; outl(0x50000, ioaddr); udelay(1); - phy_data = (inl(ioaddr) >> 19) & 0x1; + phy_data = ( inl(ioaddr) >> 19 ) & 0x1; outl(0x40000, ioaddr); udelay(1); return phy_data; } + /* - Calculate the CRC valude of the Rx packet - flag = 1 : return the reverse CRC (for the received packet CRC) - 0 : return the normal CRC (for Hash Table index) + * Calculate the CRC valude of the Rx packet + * flag = 1 : return the reverse CRC (for the received packet CRC) + * 0 : return the normal CRC (for Hash Table index) */ -unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag) + +unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) { unsigned long Crc = 0xffffffff; @@ -1603,10 +1808,190 @@ } -static struct pci_device_id dmfe_pci_tbl[] __initdata = { +/* + * Parser SROM and media mode + */ + +static void dmfe_parse_srom(struct dmfe_board_info * db) +{ + char * srom = db->srom; + int dmfe_mode, tmp_reg; + + DMFE_DBUG(0, "dmfe_parse_srom() ", 0); + + /* Init CR15 */ + db->cr15_data = CR15_DEFAULT; + + /* Check SROM Version */ + if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) { + /* SROM V4.01 */ + /* Get NIC support media mode */ + db->NIC_capability = *(u16 *) (&srom[34]); + db->PHY_reg4 = 0; + for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { + switch( db->NIC_capability & tmp_reg ) { + case 0x1: db->PHY_reg4 |= 0x0020; break; + case 0x2: db->PHY_reg4 |= 0x0040; break; + case 0x4: db->PHY_reg4 |= 0x0080; break; + case 0x8: db->PHY_reg4 |= 0x0100; break; + } + } + + /* Media Mode Force or not check */ + dmfe_mode = *( (int *) &srom[34]) & *( (int *) &srom[36] ); + switch(dmfe_mode) { + case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ + case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ + case 0x8: dmfe_media_mode = DMFE_100MFD; break; /* 100MFD */ + case 0x100: + case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */ + } + + /* Special Function setting */ + /* VLAN function */ + if ( (SF_mode & 0x1) || (srom[43] & 0x80) ) + db->cr15_data |= 0x40; + + /* Flow Control */ + if ( (SF_mode & 0x2) || (srom[40] & 0x1) ) + db->cr15_data |= 0x400; + + /* TX pause packet */ + if ( (SF_mode & 0x4) || (srom[40] & 0xe) ) + db->cr15_data |= 0x9800; + } + + /* Parse HPNA parameter */ + db->HPNA_command = 1; + + /* Accept remote command or not */ + if (HPNA_rx_cmd == 0) + db->HPNA_command |= 0x8000; + + /* Issue remote command & operation mode */ + if (HPNA_tx_cmd == 1) + switch(HPNA_mode) { /* Issue Remote Command */ + case 0: db->HPNA_command |= 0x0904; break; + case 1: db->HPNA_command |= 0x0a00; break; + case 2: db->HPNA_command |= 0x0506; break; + case 3: db->HPNA_command |= 0x0602; break; + } + else + switch(HPNA_mode) { /* Don't Issue */ + case 0: db->HPNA_command |= 0x0004; break; + case 1: db->HPNA_command |= 0x0000; break; + case 2: db->HPNA_command |= 0x0006; break; + case 3: db->HPNA_command |= 0x0002; break; + } + + /* Check DM9801 or DM9802 present or not */ + db->HPNA_present = 0; + update_cr6(db->cr6_data|0x40000, db->ioaddr); + tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id); + if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) { + /* DM9801 or DM9802 present */ + db->HPNA_timer = 8; + if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) { + /* DM9801 HomeRun */ + db->HPNA_present = 1; + dmfe_program_DM9801(db, tmp_reg); + } else { + /* DM9802 LongRun */ + db->HPNA_present = 2; + dmfe_program_DM9802(db); + } + } + +} + + +/* + * Init HomeRun DM9801 + */ + +static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev) +{ + uint reg17, reg25; + + if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR; + switch(HPNA_rev) { + case 0xb900: /* DM9801 E3 */ + db->HPNA_command |= 0x1000; + reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id); + reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000; + reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); + break; + case 0xb901: /* DM9801 E4 */ + reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); + reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor; + reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); + reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3; + break; + case 0xb902: /* DM9801 E5 */ + case 0xb903: /* DM9801 E6 */ + default: + db->HPNA_command |= 0x1000; + reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); + reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5; + reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); + reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor; + break; + } + phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); + phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id); + phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id); +} + + +/* + * Init HomeRun DM9802 + */ + +static void dmfe_program_DM9802(struct dmfe_board_info * db) +{ + uint phy_reg; + + if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR; + phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); + phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); + phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor; + phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id); +} + + +/* + * Check remote HPNA power and speed status. If not correct, + * issue command again. +*/ + +static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db) +{ + uint phy_reg; + + /* Got remote device status */ + phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60; + switch(phy_reg) { + case 0x00: phy_reg = 0x0a00;break; /* LP/LS */ + case 0x20: phy_reg = 0x0900;break; /* LP/HS */ + case 0x40: phy_reg = 0x0600;break; /* HP/LS */ + case 0x60: phy_reg = 0x0500;break; /* HP/HS */ + } + + /* Check remote device status match our setting ot not */ + if ( phy_reg != (db->HPNA_command & 0x0f00) ) { + phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); + db->HPNA_timer=8; + } else + db->HPNA_timer=600; /* Match, every 10 minutes, check */ +} + + + +static struct pci_device_id dmfe_pci_tbl[] __devinitdata = { { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID }, + { 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID }, { 0, } }; MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); @@ -1624,20 +2009,23 @@ MODULE_PARM(mode, "i"); MODULE_PARM(cr6set, "i"); MODULE_PARM(chkmode, "i"); +MODULE_PARM(HPNA_mode, "i"); +MODULE_PARM(HPNA_rx_cmd, "i"); +MODULE_PARM(HPNA_tx_cmd, "i"); +MODULE_PARM(HPNA_NoiseFloor, "i"); +MODULE_PARM(SF_mode, "i"); -/* Description: +/* Description: * when user used insmod to add module, system invoked init_module() - * to initialize and register. + * to initilize and register. */ - + static int __init dmfe_init_module(void) { int rc; - -/* when a module, this is printed whether or not devices are found in probe */ -#ifdef MODULE + printk(version); -#endif + printed_version = 1; DMFE_DBUG(0, "init_module() ", debug); @@ -1646,18 +2034,27 @@ if (cr6set) dmfe_cr6_user_set = cr6set; - switch (mode) { - case 0: - case 1: - case 4: - case 5: + switch(mode) { + case DMFE_10MHF: + case DMFE_100MHF: + case DMFE_10MFD: + case DMFE_100MFD: + case DMFE_1M_HPNA: dmfe_media_mode = mode; break; - default: - dmfe_media_mode = 8; + default:dmfe_media_mode = DMFE_AUTO; break; } + if (HPNA_mode > 4) + HPNA_mode = 0; /* Default: LP/HS */ + if (HPNA_rx_cmd > 1) + HPNA_rx_cmd = 0; /* Default: Ignored remote cmd */ + if (HPNA_tx_cmd > 1) + HPNA_tx_cmd = 0; /* Default: Don't issue remote cmd */ + if (HPNA_NoiseFloor > 15) + HPNA_NoiseFloor = 0; + rc = pci_module_init(&dmfe_driver); if (rc < 0) return rc; @@ -1665,14 +2062,16 @@ return 0; } + /* - * Description: + * Description: * when user used rmmod to delete module, system invoked clean_module() * to un-register all registered services. */ - + static void __exit dmfe_cleanup_module(void) { + DMFE_DBUG(0, "dmfe_clean_module() ", debug); pci_unregister_driver(&dmfe_driver); } diff -u --recursive --new-file v2.4.4/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.4/linux/drivers/net/epic100.c Fri Apr 20 11:54:23 2001 +++ linux/drivers/net/epic100.c Sat May 19 18:02:45 2001 @@ -41,8 +41,19 @@ * Merge becker version 1.11 * Move pci_enable_device before any PCI BAR len checks + LK1.1.7: + * { fill me in } + + LK1.1.8: + * ethtool support (jgarzik) + */ +#define DRV_NAME "epic100" +#define DRV_VERSION "1.11+LK1.1.8" +#define DRV_RELDATE "May 18, 2001" + + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -104,16 +115,18 @@ #include #include #include +#include #include #include +#include /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -"epic100.c:v1.11 1/7/2001 Written by Donald Becker \n"; +DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker \n"; static char version2[] __devinitdata = " http://www.scyld.com/network/epic100.html\n"; static char version3[] __devinitdata = -" (unofficial 2.4.x kernel port, version 1.1.7, April 17, 2001)\n"; +" (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); @@ -326,7 +339,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); static int epic_rx(struct net_device *dev); static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int epic_close(struct net_device *dev); static struct net_device_stats *epic_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -375,7 +388,7 @@ } SET_MODULE_OWNER(dev); - if (pci_request_regions(pdev, "epic100")) + if (pci_request_regions(pdev, DRV_NAME)) goto err_out_free_netdev; #ifdef USE_IO_OPS @@ -384,7 +397,7 @@ ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { - printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); + printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); goto err_out_free_res; } #endif @@ -435,7 +448,7 @@ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4)); if (debug > 2) { - printk(KERN_DEBUG "epic100(%s): EEPROM contents\n", + printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n", pdev->slot_name); for (i = 0; i < 64; i++) printk(" %4.4x%s", read_eeprom(ioaddr, i), @@ -455,7 +468,7 @@ int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; - printk(KERN_INFO "epic100(%s): MII transceiver #%d control " + printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control " "%4.4x status %4.4x.\n", pdev->slot_name, phy, mdio_read(dev, phy, 0), mii_status); } @@ -464,11 +477,11 @@ if (phy_idx != 0) { phy = ep->phys[0]; ep->advertising = mdio_read(dev, phy, 4); - printk(KERN_INFO "epic100(%s): Autonegotiation advertising %4.4x link " + printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link " "partner %4.4x.\n", pdev->slot_name, ep->advertising, mdio_read(dev, phy, 5)); } else if ( ! (ep->chip_flags & NO_MII)) { - printk(KERN_WARNING "epic100(%s): ***WARNING***: No MII transceiver found!\n", + printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n", pdev->slot_name); /* Use the known PHY address of the EPII. */ ep->phys[0] = 3; @@ -483,7 +496,7 @@ /* The lower four bits are the media type. */ if (duplex) { ep->duplex_lock = ep->full_duplex = 1; - printk(KERN_INFO "epic100(%s): Forced full duplex operation requested.\n", + printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n", pdev->slot_name); } dev->if_port = ep->default_port = option; @@ -496,7 +509,7 @@ dev->stop = &epic_close; dev->get_stats = &epic_get_stats; dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + dev->do_ioctl = &netdev_ioctl; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; @@ -1331,13 +1344,39 @@ return; } -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct epic_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pci_dev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ep->phys[0] & 0x1f; /* Fall Through */ @@ -1432,7 +1471,7 @@ static struct pci_driver epic_driver = { - name: "epic100", + name: DRV_NAME, id_table: epic_pci_tbl, probe: epic_init_one, remove: epic_remove_one, diff -u --recursive --new-file v2.4.4/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.4.4/linux/drivers/net/eql.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/net/eql.c Mon May 14 23:55:12 2001 @@ -422,6 +422,8 @@ slave_t *s = eql_new_slave (); equalizer_t *eql = (equalizer_t *) master_dev->priv; + if (!s) + return -ENOMEM; s->dev = slave_dev; s->priority = srq.priority; s->priority_bps = srq.priority; diff -u --recursive --new-file v2.4.4/linux/drivers/net/fealnx.c linux/drivers/net/fealnx.c --- v2.4.4/linux/drivers/net/fealnx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/fealnx.c Thu May 24 15:37:37 2001 @@ -0,0 +1,1777 @@ +/* + Written 1998-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support information and updates available at + http://www.scyld.com/network/pci-skeleton.html +*/ + +static int debug = 0; /* 1-> print debug message */ +static int max_interrupt_work = 20; + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ +static int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. */ +/* Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* 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 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; + +/* Operational parameters that are set at compile time. */ +/* Keep the ring sizes a power of two for compile efficiency. */ +/* The compiler will convert '%'<2^N> into a bit mask. */ +/* Making the Tx ring too large decreases the effectiveness of channel */ +/* bonding and packet priority. */ +/* There are no ill effects from too-large receive rings. */ +// 88-12-9 modify, +// #define TX_RING_SIZE 16 +// #define RX_RING_SIZE 32 +#define TX_RING_SIZE 6 +#define RX_RING_SIZE 12 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +/* These identify the driver base version and may not be removed. */ +static char version[] __devinitdata = +KERN_INFO "fealnx.c:v2.50 1/17/2001\n"; + + +/* This driver was written to use PCI memory space, however some x86 systems + work only with I/O space accesses. */ +#ifndef __alpha__ +#define USE_IO_OPS +#endif + +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. */ +/* This is only in the support-all-kernels source code. */ + +#define RUN_AT(x) (jiffies + (x)) + +MODULE_AUTHOR("Myson or whoever"); +MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(min_pci_latency, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(multicast_filter_limit, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define MIN_REGION_SIZE 136 + +enum pci_flags_bit { + PCI_USES_IO = 1, + PCI_USES_MEM = 2, + PCI_USES_MASTER = 4, + PCI_ADDR0 = 0x10 << 0, + PCI_ADDR1 = 0x10 << 1, + PCI_ADDR2 = 0x10 << 2, + PCI_ADDR3 = 0x10 << 3, +}; + +/* A chip capabilities table, matching the entries in pci_tbl[] above. */ +enum chip_capability_flags { + HAS_MII_XCVR, + HAS_CHIP_XCVR, +}; + +/* 89/6/13 add, */ +/* for different PHY */ +enum phy_type_flags { + MysonPHY = 1, + AhdocPHY = 2, + SeeqPHY = 3, + MarvellPHY = 4, + Myson981 = 5, + LevelOnePHY = 6, + OtherPHY = 10, +}; + +struct chip_info { + char *chip_name; + int io_size; + int flags; +}; + +static struct chip_info skel_netdrv_tbl[] = { + {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR}, + {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR}, + {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR}, +}; + +/* Offsets to the Command and Status Registers. */ +enum fealnx_offsets { + PAR0 = 0x0, /* physical address 0-3 */ + PAR1 = 0x04, /* physical address 4-5 */ + MAR0 = 0x08, /* multicast address 0-3 */ + MAR1 = 0x0C, /* multicast address 4-7 */ + FAR0 = 0x10, /* flow-control address 0-3 */ + FAR1 = 0x14, /* flow-control address 4-5 */ + TCRRCR = 0x18, /* receive & transmit configuration */ + BCR = 0x1C, /* bus command */ + TXPDR = 0x20, /* transmit polling demand */ + RXPDR = 0x24, /* receive polling demand */ + RXCWP = 0x28, /* receive current word pointer */ + TXLBA = 0x2C, /* transmit list base address */ + RXLBA = 0x30, /* receive list base address */ + ISR = 0x34, /* interrupt status */ + IMR = 0x38, /* interrupt mask */ + FTH = 0x3C, /* flow control high/low threshold */ + MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */ + TALLY = 0x44, /* tally counters for crc and mpa */ + TSR = 0x48, /* tally counter for transmit status */ + BMCRSR = 0x4c, /* basic mode control and status */ + PHYIDENTIFIER = 0x50, /* phy identifier */ + ANARANLPAR = 0x54, /* auto-negotiation advertisement and link + partner ability */ + ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */ + BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */ +}; + +/* Bits in the interrupt status/enable registers. */ +/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ +enum intr_status_bits { + RFCON = 0x00020000, /* receive flow control xon packet */ + RFCOFF = 0x00010000, /* receive flow control xoff packet */ + LSCStatus = 0x00008000, /* link status change */ + ANCStatus = 0x00004000, /* autonegotiation completed */ + FBE = 0x00002000, /* fatal bus error */ + FBEMask = 0x00001800, /* mask bit12-11 */ + ParityErr = 0x00000000, /* parity error */ + TargetErr = 0x00001000, /* target abort */ + MasterErr = 0x00000800, /* master error */ + TUNF = 0x00000400, /* transmit underflow */ + ROVF = 0x00000200, /* receive overflow */ + ETI = 0x00000100, /* transmit early int */ + ERI = 0x00000080, /* receive early int */ + CNTOVF = 0x00000040, /* counter overflow */ + RBU = 0x00000020, /* receive buffer unavailable */ + TBU = 0x00000010, /* transmit buffer unavilable */ + TI = 0x00000008, /* transmit interrupt */ + RI = 0x00000004, /* receive interrupt */ + RxErr = 0x00000002, /* receive error */ +}; + +/* Bits in the NetworkConfig register. */ +enum rx_mode_bits { + RxModeMask = 0xe0, + PROM = 0x80, /* promiscuous mode */ + AB = 0x40, /* accept broadcast */ + AM = 0x20, /* accept mutlicast */ + ARP = 0x08, /* receive runt pkt */ + ALP = 0x04, /* receive long pkt */ + SEP = 0x02, /* receive error pkt */ +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct fealnx_desc { + s32 status; + s32 control; + u32 buffer; + u32 next_desc; + struct fealnx_desc *next_desc_logical; + struct sk_buff *skbuff; + u32 reserved1; + u32 reserved2; +}; + +/* Bits in network_desc.status */ +enum rx_desc_status_bits { + RXOWN = 0x80000000, /* own bit */ + FLNGMASK = 0x0fff0000, /* frame length */ + FLNGShift = 16, + MARSTATUS = 0x00004000, /* multicast address received */ + BARSTATUS = 0x00002000, /* broadcast address received */ + PHYSTATUS = 0x00001000, /* physical address received */ + RXFSD = 0x00000800, /* first descriptor */ + RXLSD = 0x00000400, /* last descriptor */ + ErrorSummary = 0x80, /* error summary */ + RUNT = 0x40, /* runt packet received */ + LONG = 0x20, /* long packet received */ + FAE = 0x10, /* frame align error */ + CRC = 0x08, /* crc error */ + RXER = 0x04, /* receive error */ +}; + +enum rx_desc_control_bits { + RXIC = 0x00800000, /* interrupt control */ + RBSShift = 0, +}; + +enum tx_desc_status_bits { + TXOWN = 0x80000000, /* own bit */ + JABTO = 0x00004000, /* jabber timeout */ + CSL = 0x00002000, /* carrier sense lost */ + LC = 0x00001000, /* late collision */ + EC = 0x00000800, /* excessive collision */ + UDF = 0x00000400, /* fifo underflow */ + DFR = 0x00000200, /* deferred */ + HF = 0x00000100, /* heartbeat fail */ + NCRMask = 0x000000ff, /* collision retry count */ + NCRShift = 0, +}; + +enum tx_desc_control_bits { + TXIC = 0x80000000, /* interrupt control */ + ETIControl = 0x40000000, /* early transmit interrupt */ + TXLD = 0x20000000, /* last descriptor */ + TXFD = 0x10000000, /* first descriptor */ + CRCEnable = 0x08000000, /* crc control */ + PADEnable = 0x04000000, /* padding control */ + RetryTxLC = 0x02000000, /* retry late collision */ + PKTSMask = 0x3ff800, /* packet size bit21-11 */ + PKTSShift = 11, + TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ + TBSShift = 0, +}; + +/* BootROM/EEPROM/MII Management Register */ +#define MASK_MIIR_MII_READ 0x00000000 +#define MASK_MIIR_MII_WRITE 0x00000008 +#define MASK_MIIR_MII_MDO 0x00000004 +#define MASK_MIIR_MII_MDI 0x00000002 +#define MASK_MIIR_MII_MDC 0x00000001 + +/* ST+OP+PHYAD+REGAD+TA */ +#define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ +#define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ + +/* ------------------------------------------------------------------------- */ +/* Constants for Myson PHY */ +/* ------------------------------------------------------------------------- */ +#define MysonPHYID 0xd0000302 +/* 89-7-27 add, (begin) */ +#define MysonPHYID0 0x0302 +#define StatusRegister 18 +#define SPEED100 0x0400 // bit10 +#define FULLMODE 0x0800 // bit11 +/* 89-7-27 add, (end) */ + +/* ------------------------------------------------------------------------- */ +/* Constants for Seeq 80225 PHY */ +/* ------------------------------------------------------------------------- */ +#define SeeqPHYID0 0x0016 + +#define MIIRegister18 18 +#define SPD_DET_100 0x80 +#define DPLX_DET_FULL 0x40 + +/* ------------------------------------------------------------------------- */ +/* Constants for Ahdoc 101 PHY */ +/* ------------------------------------------------------------------------- */ +#define AhdocPHYID0 0x0022 + +#define DiagnosticReg 18 +#define DPLX_FULL 0x0800 +#define Speed_100 0x0400 + +/* 89/6/13 add, */ +/* -------------------------------------------------------------------------- */ +/* Constants */ +/* -------------------------------------------------------------------------- */ +#define MarvellPHYID0 0x0141 +#define LevelOnePHYID0 0x0013 + +#define MII1000BaseTControlReg 9 +#define MII1000BaseTStatusReg 10 +#define SpecificReg 17 + +/* for 1000BaseT Control Register */ +#define PHYAbletoPerform1000FullDuplex 0x0200 +#define PHYAbletoPerform1000HalfDuplex 0x0100 +#define PHY1000AbilityMask 0x300 + +// for phy specific status register, marvell phy. +#define SpeedMask 0x0c000 +#define Speed_1000M 0x08000 +#define Speed_100M 0x4000 +#define Speed_10M 0 +#define Full_Duplex 0x2000 + +// 89/12/29 add, for phy specific status register, levelone phy, (begin) +#define LXT1000_100M 0x08000 +#define LXT1000_1000M 0x0c000 +#define LXT1000_Full 0x200 +// 89/12/29 add, for phy specific status register, levelone phy, (end) + +/* for 3-in-1 case */ +#define PS10 0x00080000 +#define FD 0x00100000 +#define PS1000 0x00010000 +#define LinkIsUp2 0x00040000 + +/* for PHY */ +#define LinkIsUp 0x0004 + + +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct fealnx_desc rx_ring[RX_RING_SIZE]; + struct fealnx_desc tx_ring[TX_RING_SIZE]; + + struct net_device_stats stats; + + /* Media monitoring timer. */ + struct timer_list timer; + + /* Frequently used values: keep some adjacent for cache effect. */ + int flags; + struct pci_dev *pci_dev; + unsigned long crvalue; + unsigned long bcrvalue; + unsigned long imrvalue; + struct fealnx_desc *cur_rx; + struct fealnx_desc *lack_rxbuf; + int really_rx_count; + struct fealnx_desc *cur_tx; + struct fealnx_desc *cur_tx_copy; + int really_tx_count; + int free_tx_count; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + + /* These values are keep track of the transceiver/media in use. */ + unsigned int linkok; + unsigned int line_speed; + unsigned int duplexmode; + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int PHYType; + + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + unsigned char phys[2]; /* MII device addresses. */ +}; + + +static unsigned int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void getlinktype(struct net_device *dev); +static void getlinkstatus(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(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); +static int netdev_rx(struct net_device *dev); +static inline unsigned ether_crc(int length, unsigned char *data); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + +void stop_nic_tx(long ioaddr, long crvalue) +{ + writel(crvalue & (~0x40000), ioaddr + TCRRCR); + + /* wait for tx stop */ + { + int i = 0, delay = 0x1000; + + while ((!(readl(ioaddr + TCRRCR) & 0x04000000)) && (i < delay)) { + ++i; + } + } +} + + +void stop_nic_rx(long ioaddr, long crvalue) +{ + writel(crvalue & (~0x1), ioaddr + TCRRCR); + + /* wait for rx stop */ + { + int i = 0, delay = 0x1000; + + while ((!(readl(ioaddr + TCRRCR) & 0x00008000)) && (i < delay)) { + ++i; + } + } +} + + + +static int __devinit fealnx_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct netdev_private *np; + int i, option, err, irq; + static int card_idx = -1; + char boardname[12]; + long ioaddr; + unsigned int chip_id = ent->driver_data; + struct net_device *dev; + +/* when built into the kernel, we only print version if device is found */ +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk (version); +#endif + + card_idx++; + sprintf(boardname, "fealnx%d", card_idx); + + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + + i = pci_enable_device(pdev); + if (i) return i; + pci_set_master(pdev); + +#ifdef USE_IO_OPS + ioaddr = pci_resource_len(pdev, 0); +#else + ioaddr = pci_resource_len(pdev, 1); +#endif + if (ioaddr < MIN_REGION_SIZE) { + printk(KERN_ERR "%s: region size %ld too small, aborting\n", + boardname, ioaddr); + return -ENODEV; + } + + i = pci_request_regions(pdev, boardname); + if (i) return i; + + irq = pdev->irq; + +#ifdef USE_IO_OPS + ioaddr = pci_resource_start(pdev, 0); +#else + ioaddr = (long) ioremap(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (!ioaddr) { + err = -ENOMEM; + goto err_out_res; + } +#endif + + dev = alloc_etherdev(sizeof(struct netdev_private)); + if (!dev) { + err = -ENOMEM; + goto err_out_unmap; + } + SET_MODULE_OWNER(dev); + + /* read ethernet id */ + for (i = 0; i < 6; ++i) + dev->dev_addr[i] = readb(ioaddr + PAR0 + i); + + /* Reset the chip to erase previous misconfiguration. */ + writel(0x00000001, ioaddr + BCR); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the descriptor lists are aligned. */ + np = dev->priv; + np->pci_dev = pdev; + np->flags = skel_netdrv_tbl[chip_id].flags; + pci_set_drvdata(pdev, dev); + + /* find the connected MII xcvrs */ + if (np->flags == HAS_MII_XCVR) { + int phy, phy_idx = 0; + + for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(dev, phy, 1); + + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + printk(KERN_INFO + "%s: MII PHY found at address %d, status " + "0x%4.4x.\n", dev->name, phy, mii_status); + /* get phy type */ + { + unsigned int data; + + data = mdio_read(dev, np->phys[0], 2); + if (data == SeeqPHYID0) + np->PHYType = SeeqPHY; + else if (data == AhdocPHYID0) + np->PHYType = AhdocPHY; + else if (data == MarvellPHYID0) + np->PHYType = MarvellPHY; + else if (data == MysonPHYID0) + np->PHYType = Myson981; + else if (data == LevelOnePHYID0) + np->PHYType = LevelOnePHY; + else + np->PHYType = OtherPHY; + } + } + } + + np->mii_cnt = phy_idx; + if (phy_idx == 0) { + printk(KERN_WARNING "%s: MII PHY not found -- this device may " + "not operate correctly.\n", dev->name); + } + } else { + np->phys[0] = 32; +/* 89/6/23 add, (begin) */ + /* get phy type */ + if (readl(dev->base_addr + PHYIDENTIFIER) == MysonPHYID) + np->PHYType = MysonPHY; + else + np->PHYType = OtherPHY; + } + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + + if (np->default_port) + np->medialock = 1; + } + + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + np->full_duplex = full_duplex[card_idx]; + + if (np->full_duplex) { + printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); +/* 89/6/13 add, (begin) */ +// if (np->PHYType==MarvellPHY) + if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) { + unsigned int data; + + data = mdio_read(dev, np->phys[0], 9); + data = (data & 0xfcff) | 0x0200; + mdio_write(dev, np->phys[0], 9, data); + } +/* 89/6/13 add, (end) */ + if (np->flags == HAS_MII_XCVR) + mdio_write(dev, np->phys[0], 4, 0x141); + else + writel(0x141, dev->base_addr + ANARANLPAR); + np->duplex_lock = 1; + } + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + err = register_netdev(dev); + if (err) + goto err_out_free; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + return 0; + +err_out_free: + kfree(dev); +err_out_unmap: +#ifndef USE_IO_OPS + iounmap((void *)ioaddr); +err_out_res: +#endif + pci_release_regions(pdev); + return err; +} + +static void __devexit fealnx_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + if (dev) { + unregister_netdev(dev); +#ifndef USE_IO_OPS + iounmap((void *)dev->base_addr); +#endif + kfree(dev); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } else + printk(KERN_ERR "fealnx: remove for unknown device\n"); +} + +unsigned int m80x_read_tick(void) +/* function: Reads the Timer tick count register which decrements by 2 from */ +/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. */ +/* input : none. */ +/* output : none. */ +{ + unsigned char tmp; + int value; + + writeb((char) 0x06, 0x43); // Command 8254 to latch T0's count + + // now read the count. + tmp = (unsigned char) readb(0x40); + value = ((int) tmp) << 8; + tmp = (unsigned char) readb(0x40); + value |= (((int) tmp) & 0xff); + return (value); +} + + +void m80x_delay(unsigned int interval) +/* function: to wait for a specified time. */ +/* input : interval ... the specified time. */ +/* output : none. */ +{ + unsigned int interval1, interval2, i = 0; + + interval1 = m80x_read_tick(); // get initial value + do { + interval2 = m80x_read_tick(); + if (interval1 < interval2) + interval1 = interval2; + ++i; + } while (((interval1 - interval2) < (ushort) interval) && (i < 65535)); +} + + +static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad) +{ + ulong miir; + int i; + unsigned int mask, data; + + /* enable MII output */ + miir = (ulong) readl(miiport); + miir &= 0xfffffff0; + + miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; + + /* send 32 1's preamble */ + for (i = 0; i < 32; i++) { + /* low MDC; MDO is already high (miir) */ + miir &= ~MASK_MIIR_MII_MDC; + writel(miir, miiport); + + /* high MDC */ + miir |= MASK_MIIR_MII_MDC; + writel(miir, miiport); + } + + /* calculate ST+OP+PHYAD+REGAD+TA */ + data = opcode | (phyad << 7) | (regad << 2); + + /* sent out */ + mask = 0x8000; + while (mask) { + /* low MDC, prepare MDO */ + miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); + if (mask & data) + miir |= MASK_MIIR_MII_MDO; + + writel(miir, miiport); + /* high MDC */ + miir |= MASK_MIIR_MII_MDC; + writel(miir, miiport); + m80x_delay(30); + + /* next */ + mask >>= 1; + if (mask == 0x2 && opcode == OP_READ) + miir &= ~MASK_MIIR_MII_WRITE; + } + return miir; +} + + +static unsigned int mdio_read(struct net_device *dev, int phyad, int regad) +{ + long miiport = dev->base_addr + MANAGEMENT; + ulong miir; + unsigned int mask, data; + + miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); + + /* read data */ + mask = 0x8000; + data = 0; + while (mask) { + /* low MDC */ + miir &= ~MASK_MIIR_MII_MDC; + writel(miir, miiport); + + /* read MDI */ + miir = readl(miiport); + if (miir & MASK_MIIR_MII_MDI) + data |= mask; + + /* high MDC, and wait */ + miir |= MASK_MIIR_MII_MDC; + writel(miir, miiport); + m80x_delay((int) 30); + + /* next */ + mask >>= 1; + } + + /* low MDC */ + miir &= ~MASK_MIIR_MII_MDC; + writel(miir, miiport); + + return data; +} + + +static void mdio_write(struct net_device *dev, int phyad, int regad, int data) +{ + long miiport = dev->base_addr + MANAGEMENT; + ulong miir; + unsigned int mask; + + miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); + + /* write data */ + mask = 0x8000; + while (mask) { + /* low MDC, prepare MDO */ + miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); + if (mask & data) + miir |= MASK_MIIR_MII_MDO; + writel(miir, miiport); + + /* high MDC */ + miir |= MASK_MIIR_MII_MDC; + writel(miir, miiport); + + /* next */ + mask >>= 1; + } + + /* low MDC */ + miir &= ~MASK_MIIR_MII_MDC; + writel(miir, miiport); + + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + writel(0x00000001, ioaddr + BCR); /* Reset */ + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RXLBA); + writel(virt_to_bus(np->tx_ring), ioaddr + TXLBA); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. + 486: Set 8 longword burst. + 586: no burst limit. + Burst length 5:3 + 0 0 0 1 + 0 0 1 4 + 0 1 0 8 + 0 1 1 16 + 1 0 0 32 + 1 0 1 64 + 1 1 0 128 + 1 1 1 256 + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ +#if defined(__powerpc__) +// 89/9/1 modify, +// np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */ + np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */ + np->crvalue = 0xe00; /* rx 128 burst length */ +#elif defined(__alpha__) +// 89/9/1 modify, +// np->bcrvalue=0x38; /* little-endian, 256 burst length */ + np->bcrvalue = 0x10; /* little-endian, 8 burst length */ + np->crvalue = 0xe00; /* rx 128 burst length */ +#elif defined(__i386__) +#if defined(MODULE) +// 89/9/1 modify, +// np->bcrvalue=0x38; /* little-endian, 256 burst length */ + np->bcrvalue = 0x10; /* little-endian, 8 burst length */ + np->crvalue = 0xe00; /* rx 128 burst length */ +#else + /* When not a module we can work around broken '486 PCI boards. */ +#define x86 boot_cpu_data.x86 +// 89/9/1 modify, +// np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38); + np->bcrvalue = 0x10; + np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00); + if (x86 <= 4) + printk(KERN_INFO "%s: This is a 386/486 PCI system, setting burst " + "length to %x.\n", dev->name, (x86 <= 4 ? 0x10 : 0x38)); +#endif +#else +// 89/9/1 modify, +// np->bcrvalue=0x38; + np->bcrvalue = 0x10; + np->cralue = 0xe00; /* rx 128 burst length */ +#warning Processor architecture undefined! +#endif +// 89/12/29 add, +// 90/1/16 modify, +// np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI; + np->imrvalue = TUNF | CNTOVF | RBU | TI | RI; + if (np->pci_dev->device == 0x891) { + np->bcrvalue |= 0x200; /* set PROG bit */ + np->crvalue |= 0x02000000; /* set enhanced bit */ + np->imrvalue |= ETI; + } + writel(np->bcrvalue, ioaddr + BCR); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + writel(0, dev->base_addr + RXPDR); +// 89/9/1 modify, +// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ + np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ + np->full_duplex = np->duplex_lock; + getlinkstatus(dev); + if (np->linkok) + getlinktype(dev); + set_rx_mode(dev); + + netif_start_queue(dev); + + /* Clear and Enable interrupts by setting the interrupt mask. */ + writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); + writel(np->imrvalue, ioaddr + IMR); + + if (debug) + printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = RUN_AT(3 * HZ); + np->timer.data = (unsigned long) dev; + np->timer.function = &netdev_timer; + + /* timer handler */ + add_timer(&np->timer); + + return 0; +} + + +static void getlinkstatus(struct net_device *dev) +/* function: Routine will read MII Status Register to get link status. */ +/* input : dev... pointer to the adapter block. */ +/* output : none. */ +{ + struct netdev_private *np = dev->priv; + unsigned int i, DelayTime = 0x1000; + + np->linkok = 0; + + if (np->PHYType == MysonPHY) { + for (i = 0; i < DelayTime; ++i) { + if (readl(dev->base_addr + BMCRSR) & LinkIsUp2) { + np->linkok = 1; + return; + } + // delay + m80x_delay(100); + } + } else { + for (i = 0; i < DelayTime; ++i) { + if (mdio_read(dev, np->phys[0], 1) & 0x4) { + np->linkok = 1; + return; + } + // delay + m80x_delay(100); + } + } +} + + +static void getlinktype(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + if (np->PHYType == MysonPHY) { /* 3-in-1 case */ + if (readl(dev->base_addr + TCRRCR) & FD) + np->duplexmode = 2; /* full duplex */ + else + np->duplexmode = 1; /* half duplex */ + if (readl(dev->base_addr + TCRRCR) & PS10) + np->line_speed = 1; /* 10M */ + else + np->line_speed = 2; /* 100M */ + } else { + if (np->PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ + unsigned int data; + + data = mdio_read(dev, np->phys[0], MIIRegister18); + if (data & SPD_DET_100) + np->line_speed = 2; /* 100M */ + else + np->line_speed = 1; /* 10M */ + if (data & DPLX_DET_FULL) + np->duplexmode = 2; /* full duplex mode */ + else + np->duplexmode = 1; /* half duplex mode */ + } else if (np->PHYType == AhdocPHY) { + unsigned int data; + + data = mdio_read(dev, np->phys[0], DiagnosticReg); + if (data & Speed_100) + np->line_speed = 2; /* 100M */ + else + np->line_speed = 1; /* 10M */ + if (data & DPLX_FULL) + np->duplexmode = 2; /* full duplex mode */ + else + np->duplexmode = 1; /* half duplex mode */ + } +/* 89/6/13 add, (begin) */ + else if (np->PHYType == MarvellPHY) { + unsigned int data; + + data = mdio_read(dev, np->phys[0], SpecificReg); + if (data & Full_Duplex) + np->duplexmode = 2; /* full duplex mode */ + else + np->duplexmode = 1; /* half duplex mode */ + data &= SpeedMask; + if (data == Speed_1000M) + np->line_speed = 3; /* 1000M */ + else if (data == Speed_100M) + np->line_speed = 2; /* 100M */ + else + np->line_speed = 1; /* 10M */ + } +/* 89/6/13 add, (end) */ +/* 89/7/27 add, (begin) */ + else if (np->PHYType == Myson981) { + unsigned int data; + + data = mdio_read(dev, np->phys[0], StatusRegister); + + if (data & SPEED100) + np->line_speed = 2; + else + np->line_speed = 1; + + if (data & FULLMODE) + np->duplexmode = 2; + else + np->duplexmode = 1; + } +/* 89/7/27 add, (end) */ +/* 89/12/29 add */ + else if (np->PHYType == LevelOnePHY) { + unsigned int data; + + data = mdio_read(dev, np->phys[0], SpecificReg); + if (data & LXT1000_Full) + np->duplexmode = 2; /* full duplex mode */ + else + np->duplexmode = 1; /* half duplex mode */ + data &= SpeedMask; + if (data == LXT1000_1000M) + np->line_speed = 3; /* 1000M */ + else if (data == LXT1000_100M) + np->line_speed = 2; /* 100M */ + else + np->line_speed = 1; /* 10M */ + } + // chage crvalue + // np->crvalue&=(~PS10)&(~FD); + np->crvalue &= (~PS10) & (~FD) & (~PS1000); + if (np->line_speed == 1) + np->crvalue |= PS10; + else if (np->line_speed == 3) + np->crvalue |= PS1000; + if (np->duplexmode == 2) + np->crvalue |= FD; + } +} + + +static void allocate_rx_buffers(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* allocate skb for rx buffers */ + while (np->really_rx_count != RX_RING_SIZE) { + struct sk_buff *skb; + + skb = dev_alloc_skb(np->rx_buf_sz); + np->lack_rxbuf->skbuff = skb; + + if (skb == NULL) + break; /* Better luck next round. */ + + skb->dev = dev; /* Mark as being used by this device. */ + np->lack_rxbuf->buffer = virt_to_bus(skb->tail); + np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; + ++np->really_rx_count; + } +} + + +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; + int next_tick = 10 * HZ; + int old_crvalue = np->crvalue; + unsigned int old_linkok = np->linkok; + + if (debug) + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " + "config %8.8x.\n", dev->name, readl(ioaddr + ISR), + readl(ioaddr + TCRRCR)); + + if (np->flags == HAS_MII_XCVR) { + getlinkstatus(dev); + if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */ + getlinktype(dev); + if (np->crvalue != old_crvalue) { + stop_nic_tx(ioaddr, np->crvalue); + stop_nic_rx(ioaddr, np->crvalue & (~0x40000)); + writel(np->crvalue, ioaddr + TCRRCR); + } + } + } + + allocate_rx_buffers(dev); + + np->timer.expires = RUN_AT(next_tick); + add_timer(&np->timer); +} + + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, readl(ioaddr + ISR)); + +#ifndef __alpha__ + { + int i; + + printk(KERN_DEBUG " Rx ring %8.8x: ", (int) np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int) np->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int) np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. Just trigger a + Tx demand for now. */ + writel(0, dev->base_addr + TXPDR); + dev->if_port = 0; + + /* Stop and restart the chip's Tx processes . */ + dev->trans_start = jiffies; + np->stats.tx_errors++; + + return; +} + + +/* 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; + + /* initialize rx variables */ + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->cur_rx = &np->rx_ring[0]; + np->lack_rxbuf = NULL; + np->really_rx_count = 0; + + /* initial rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + np->rx_ring[i].control = np->rx_buf_sz << RBSShift; + np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i + 1]); + np->rx_ring[i].next_desc_logical = &np->rx_ring[i + 1]; + np->rx_ring[i].skbuff = NULL; + } + + /* for the last rx descriptor */ + np->rx_ring[i - 1].next_desc = virt_to_bus(&np->rx_ring[0]); + np->rx_ring[i - 1].next_desc_logical = &np->rx_ring[0]; + + /* allocate skb for rx buffers */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + + if (skb == NULL) { + np->lack_rxbuf = &np->rx_ring[i]; + break; + } + + ++np->really_rx_count; + np->rx_ring[i].skbuff = skb; + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[i].buffer = virt_to_bus(skb->tail); + np->rx_ring[i].status = RXOWN; + np->rx_ring[i].control |= RXIC; + } + + /* initialize tx variables */ + np->cur_tx = &np->tx_ring[0]; + np->cur_tx_copy = &np->tx_ring[0]; + np->really_tx_count = 0; + np->free_tx_count = TX_RING_SIZE; + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].status = 0; + np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i + 1]); + np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1]; + np->tx_ring[i].skbuff = NULL; + } + + /* for the last tx descriptor */ + np->tx_ring[i - 1].next_desc = virt_to_bus(&np->tx_ring[0]); + np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0]; + + return; +} + + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + np->cur_tx_copy->skbuff = skb; + np->cur_tx_copy->buffer = virt_to_bus(skb->data); + +#define one_buffer +#define BPT 1022 +#if defined(one_buffer) + np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; + np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ + np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ +// 89/12/29 add, + if (np->pci_dev->device == 0x891) + np->cur_tx_copy->control |= ETIControl | RetryTxLC; + np->cur_tx_copy->status = TXOWN; + np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; + --np->free_tx_count; +#elif defined(two_buffer) + if (skb->len > BPT) { + struct fealnx_desc *next; + + /* for the first descriptor */ + np->cur_tx_copy->control = TXIC | TXFD | CRCEnable | PADEnable; + np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ + np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */ + + /* for the last descriptor */ + next = (struct fealnx *) np->cur_tx_copy.next_desc_logical; + next->skbuff = skb; + next->control = TXIC | TXLD | CRCEnable | PADEnable; + next->control |= (skb->len << PKTSShift); /* pkt size */ + next->control |= ((skb->len - BPT) << TBSShift); /* buf size */ +// 89/12/29 add, + if (np->pci_dev->device == 0x891) + np->cur_tx_copy->control |= ETIControl | RetryTxLC; + next->buffer = virt_to_bus(skb->data) + BPT; + + next->status = TXOWN; + np->cur_tx_copy->status = TXOWN; + + np->cur_tx_copy = next->next_desc_logical; + np->free_tx_count -= 2; + } else { + np->cur_tx_copy->control = TXIC | TXLD | TXFD | CRCEnable | PADEnable; + np->cur_tx_copy->control |= (skb->len << PKTSShift); /* pkt size */ + np->cur_tx_copy->control |= (skb->len << TBSShift); /* buffer size */ +// 89/12/29 add, + if (np->pci_dev->device == 0x891) + np->cur_tx_copy->control |= ETIControl | RetryTxLC; + np->cur_tx_copy->status = TXOWN; + np->cur_tx_copy = np->cur_tx_copy->next_desc_logical; + --np->free_tx_count; + } +#endif + + if (np->free_tx_count < 2) + netif_stop_queue(dev); + ++np->really_tx_count; + writel(0, dev->base_addr + TXPDR); + dev->trans_start = jiffies; + + return 0; +} + + +void free_one_rx_descriptor(struct netdev_private *np) +{ + if (np->really_rx_count == RX_RING_SIZE) + np->cur_rx->status = RXOWN; + else { + np->lack_rxbuf->skbuff = np->cur_rx->skbuff; + np->lack_rxbuf->buffer = np->cur_rx->buffer; + np->lack_rxbuf->status = RXOWN; + ++np->really_rx_count; + np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; + } + np->cur_rx = np->cur_rx->next_desc_logical; +} + + +void reset_rx_descriptors(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + stop_nic_rx(dev->base_addr, np->crvalue); + + while (!(np->cur_rx->status & RXOWN)) + free_one_rx_descriptor(np); + + allocate_rx_buffers(dev); + + writel(virt_to_bus(np->cur_rx), dev->base_addr + RXLBA); + writel(np->crvalue, dev->base_addr + TCRRCR); +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct netdev_private *np = dev->priv; + long ioaddr, boguscnt = max_interrupt_work; + unsigned int num_tx = 0; + + writel(0, dev->base_addr + IMR); + + ioaddr = dev->base_addr; + np = (struct netdev_private *) dev->priv; + + do { + u32 intr_status = readl(ioaddr + ISR); + + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_status, ioaddr + ISR); + + if (debug) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, + intr_status); + + if (!(intr_status & np->imrvalue)) + break; + +// 90/1/16 delete, +// +// if (intr_status & FBE) +// { /* fatal error */ +// stop_nic_tx(ioaddr, 0); +// stop_nic_rx(ioaddr, 0); +// break; +// }; + + if (intr_status & TUNF) + writel(0, ioaddr + TXPDR); + + if (intr_status & CNTOVF) { + /* missed pkts */ + np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; + + /* crc error */ + np->stats.rx_crc_errors += + (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + } + + if (intr_status & (RI | RBU)) { + if (intr_status & RI) + netdev_rx(dev); + else + reset_rx_descriptors(dev); + } + + while (np->really_tx_count) { + long tx_status = np->cur_tx->status; + long tx_control = np->cur_tx->control; + + if (!(tx_control & TXLD)) { /* this pkt is combined by two tx descriptors */ + struct fealnx_desc *next; + + next = np->cur_tx->next_desc_logical; + tx_status = next->status; + tx_control = next->control; + } + + if (tx_status & TXOWN) + break; + + if (!(np->crvalue & 0x02000000)) { + if (tx_status & (CSL | LC | EC | UDF | HF)) { + np->stats.tx_errors++; + if (tx_status & EC) + np->stats.tx_aborted_errors++; + if (tx_status & CSL) + np->stats.tx_carrier_errors++; + if (tx_status & LC) + np->stats.tx_window_errors++; + if (tx_status & UDF) + np->stats.tx_fifo_errors++; + if ((tx_status & HF) && np->full_duplex == 0) + np->stats.tx_heartbeat_errors++; + +#ifdef ETHER_STATS + if (tx_status & EC) + np->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (tx_status & DFR) + np->stats.tx_deferred++; +#endif + + np->stats.tx_bytes += + ((tx_control & PKTSMask) >> PKTSShift); + + np->stats.collisions += + ((tx_status & NCRMask) >> NCRShift); + np->stats.tx_packets++; + } + } else { + np->stats.tx_bytes += + ((tx_control & PKTSMask) >> PKTSShift); + np->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(np->cur_tx->skbuff); + np->cur_tx->skbuff = NULL; + --np->really_tx_count; + if (np->cur_tx->control & TXLD) { + np->cur_tx = np->cur_tx->next_desc_logical; + ++np->free_tx_count; + } else { + np->cur_tx = np->cur_tx->next_desc_logical; + np->cur_tx = np->cur_tx->next_desc_logical; + np->free_tx_count += 2; + } + num_tx++; + } /* end of for loop */ + + if (num_tx && np->free_tx_count >= 2) + netif_wake_queue(dev); + + /* read transmit status for enhanced mode only */ + if (np->crvalue & 0x02000000) { + long data; + + data = readl(ioaddr + TSR); + np->stats.tx_errors += (data & 0xff000000) >> 24; + np->stats.tx_aborted_errors += (data & 0xff000000) >> 24; + np->stats.tx_window_errors += (data & 0x00ff0000) >> 16; +#ifdef ETHER_STATS + np->stats.collisions16 += (data & 0xff000000) >> 24; +#endif + np->stats.collisions += (data & 0x0000ffff); + } + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", dev->name, intr_status); + break; + } + } while (1); + + /* read the tally counters */ + /* missed pkts */ + np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; + + /* crc error */ + np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + + if (debug) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readl(ioaddr + ISR)); + + writel(np->imrvalue, ioaddr + IMR); + + return; +} + + +/* This routine is logically part of the interrupt handler, but seperated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while (!(np->cur_rx->status & RXOWN)) { + s32 rx_status = np->cur_rx->status; + + if (np->really_rx_count == 0) + break; + + if (debug) + printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", rx_status); + + if ((!((rx_status & RXFSD) && (rx_status & RXLSD))) + || (rx_status & ErrorSummary)) { + if (rx_status & ErrorSummary) { /* there was a fatal error */ + if (debug) + printk(KERN_DEBUG + "%s: Receive error, Rx status %8.8x.\n", + dev->name, rx_status); + + np->stats.rx_errors++; /* end of a packet. */ + if (rx_status & (LONG | RUNT)) + np->stats.rx_length_errors++; + if (rx_status & RXER) + np->stats.rx_frame_errors++; + if (rx_status & CRC) + np->stats.rx_crc_errors++; + } else { + int need_to_reset = 0; + int desno = 0; + + if (rx_status & RXFSD) { /* this pkt is too long, over one rx buffer */ + struct fealnx_desc *cur; + + /* check this packet is received completely? */ + cur = np->cur_rx; + while (desno <= np->really_rx_count) { + ++desno; + if ((!(cur->status & RXOWN)) + && (cur->status & RXLSD)) + break; + /* goto next rx descriptor */ + cur = cur->next_desc_logical; + } + if (desno > np->really_rx_count) + need_to_reset = 1; + } else /* RXLSD did not find, something error */ + need_to_reset = 1; + + if (need_to_reset == 0) { + int i; + + np->stats.rx_length_errors++; + + /* free all rx descriptors related this long pkt */ + for (i = 0; i < desno; ++i) + free_one_rx_descriptor(np); + continue; + } else { /* something error, need to reset this chip */ + reset_rx_descriptors(dev); + } + break; /* exit the while loop */ + } + } else { /* this received pkt is ok */ + + struct sk_buff *skb; + /* Omit the four octet CRC from the length. */ + short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4; + +#ifndef final_version + if (debug) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + " status %x.\n", pkt_len, rx_status); +#endif + + /* 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; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + /* Call copy + cksum if available. */ + +#if ! defined(__alpha__) + eth_copy_and_sum(skb, bus_to_virt(np->cur_rx->buffer), + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + bus_to_virt(np->cur_rx->buffer), pkt_len); +#endif + } else { + skb_put(skb = np->cur_rx->skbuff, pkt_len); + np->cur_rx->skbuff = NULL; + if (np->really_rx_count == RX_RING_SIZE) + np->lack_rxbuf = np->cur_rx; + --np->really_rx_count; + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += pkt_len; + } + + if (np->cur_rx->skbuff == NULL) { + struct sk_buff *skb; + + skb = dev_alloc_skb(np->rx_buf_sz); + + if (skb != NULL) { + skb->dev = dev; /* Mark as being used by this device. */ + np->cur_rx->buffer = virt_to_bus(skb->tail); + np->cur_rx->skbuff = skb; + ++np->really_rx_count; + } + } + + if (np->cur_rx->skbuff != NULL) + free_one_rx_descriptor(np); + } /* end of while loop */ + + /* allocate skb for rx buffers */ + allocate_rx_buffers(dev); + + return 0; +} + + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + + /* The chip only need report frame silently dropped. */ + if (netif_running(dev)) { + np->stats.rx_missed_errors += readl(ioaddr + TALLY) & 0x7fff; + np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; + } + + return &np->stats; +} + + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + + for (bit = 0; bit < 8; bit++, current_octet >>= 1) { + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + } + + return crc; +} + + +static void set_rx_mode(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + u32 rx_mode; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = PROM | AB | AM; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AB | AM; + } else { + struct dev_mc_list *mclist; + int i; + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F, + mc_filter); + } + rx_mode = AB | AM; + } + + stop_nic_tx(ioaddr, np->crvalue); + stop_nic_rx(ioaddr, np->crvalue & (~0x40000)); + + writel(mc_filter[0], ioaddr + MAR0); + writel(mc_filter[1], ioaddr + MAR1); + np->crvalue &= ~RxModeMask; + np->crvalue |= rx_mode; + writel(np->crvalue, ioaddr + TCRRCR); +} + + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *) & rq->ifr_data; + + switch (cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + int i; + + netif_stop_queue(dev); + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0x0000, ioaddr + IMR); + + /* Stop the chip's Tx and Rx processes. */ + stop_nic_tx(ioaddr, 0); + stop_nic_rx(ioaddr, 0); + + del_timer_sync(&np->timer); + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + if (np->rx_ring[i].skbuff) + dev_kfree_skb(np->rx_ring[i].skbuff); + np->rx_ring[i].skbuff = NULL; + } + + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_ring[i].skbuff) + dev_kfree_skb(np->tx_ring[i].skbuff); + np->tx_ring[i].skbuff = NULL; + } + + return 0; +} + +static struct pci_device_id fealnx_pci_tbl[] = __devinitdata { + {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + {} /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, fealnx_pci_tbl); + + +static struct pci_driver fealnx_driver = { + name: "fealnx", + id_table: fealnx_pci_tbl, + probe: fealnx_init_one, + remove: fealnx_remove_one, +}; + +static int __init fealnx_init(void) +{ +/* when a module, this is printed whether or not devices are found in probe */ +#ifdef MODULE + printk (version); +#endif + + return pci_module_init(&fealnx_driver); +} + +static void __exit fealnx_exit(void) +{ + pci_unregister_driver(&fealnx_driver); +} + +module_init(fealnx_init); +module_exit(fealnx_exit); diff -u --recursive --new-file v2.4.4/linux/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.4.4/linux/drivers/net/gmac.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/gmac.c Wed May 16 09:58:36 2001 @@ -9,7 +9,7 @@ * Changes: * Arnaldo Carvalho de Melo - 08/06/2000 * - check init_etherdev return in gmac_probe1 - * BenH - 03/09/2000 + * BenH - 03/09/2000 * - Add support for new PHYs * - Add some PowerBook sleep code * @@ -47,10 +47,11 @@ #define DEBUG_PHY /* Driver version 1.3, kernel 2.4.x */ -#define GMAC_VERSION "v1.3k4" +#define GMAC_VERSION "v1.4k4" -static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; -static struct net_device *gmacs = NULL; +#define DUMMY_BUF_LEN RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN +static unsigned char *dummy_buf; +static struct net_device *gmacs; /* Prototypes */ static int mii_read(struct gmac *gm, int phy, int r); @@ -62,6 +63,7 @@ static void mii_setup_phy(struct gmac *gm); static int mii_do_reset_phy(struct gmac *gm, int phy_addr); static void mii_init_BCM5400(struct gmac *gm); +static void mii_init_BCM5401(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct net_device *dev); @@ -211,10 +213,12 @@ int link_100 = 0; int gigabit = 0; #ifdef DEBUG_PHY - printk("Link state change, phy_status: 0x%04x\n", phy_status); + printk("%s: Link state change, phy_status: 0x%04x\n", + gm->dev->name, phy_status); #endif gm->phy_status = phy_status; + /* Should we enable that in generic mode ? */ lpar_ability = mii_read(gm, gm->phy_addr, MII_ANLPA); if (lpar_ability & MII_ANLPA_PAUS) GM_BIS(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); @@ -249,6 +253,9 @@ #endif full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); + } else { + full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0; + link_100 = (lpar_ability & MII_ANLPA_100M) != 0; } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, @@ -274,6 +281,144 @@ } } +/* Power management: stop PHY chip for suspend mode + */ +static void +gmac_suspend(struct gmac* gm) +{ + int data, timeout; + unsigned long flags; + + gm->sleeping = 1; + netif_stop_queue(gm->dev); + + + spin_lock_irqsave(&gm->lock, flags); + if (gm->opened) { + disable_irq(gm->dev->irq); + /* Stop polling PHY */ + mii_poll_stop(gm); + } + /* Mask out all chips interrupts */ + GM_OUT(GM_IRQ_MASK, 0xffffffff); + spin_unlock_irqrestore(&gm->lock, flags); + + if (gm->opened) { + int i; + /* Empty Tx ring of any remaining gremlins */ + gmac_tx_cleanup(gm->dev, 1); + + /* Empty Rx ring of any remaining gremlins */ + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb_irq(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + } + + /* Clear interrupts on 5201 */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_INTERRUPT, 0); + + /* Drive MDIO high */ + GM_OUT(GM_MIF_CFG, 0); + + /* Unchanged, don't ask me why */ + data = mii_read(gm, gm->phy_addr, MII_ANLPA); + mii_write(gm, gm->phy_addr, MII_ANLPA, data); + + /* Put MDIO in sane state */ + GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB); + GM_OUT(GM_MIF_BB_CLOCK, 0); + GM_OUT(GM_MIF_BB_DATA, 0); + GM_OUT(GM_MIF_BB_OUT_ENABLE, 0); + + /* Stop everything */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + + /* Set reset state */ + GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX); + for (timeout = 100; timeout > 0; --timeout) { + mdelay(10); + if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) + break; + } + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); + + /* Superisolate PHY */ + if (gm->phy_type == PHY_B5201) + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + MII_BCM5201_MULTIPHY_SUPERISOLATE); + + /* Unclock chip */ + gmac_set_power(gm, 0); +} + +static void +gmac_resume(struct gmac *gm) +{ + int data; + + if (gmac_powerup_and_reset(gm->dev)) { + printk(KERN_ERR "%s: Couldn't revive gmac ethernet !\n", gm->dev->name); + return; + } + + gm->sleeping = 0; + + if (gm->opened) { + /* Create fresh rings */ + gmac_init_rings(gm, 1); + /* re-initialize the MAC */ + gmac_mac_init(gm, gm->dev->dev_addr); + /* re-initialize the multicast tables & promisc mode if any */ + gmac_set_multicast(gm->dev); + } + + /* Early enable Tx and Rx so that we are clocked */ + GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN); + mdelay(20); + GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + mdelay(20); + GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE); + mdelay(20); + if (gm->phy_type == PHY_B5201) { + data = mii_read(gm, gm->phy_addr, MII_BCM5201_MULTIPHY); + mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY, + data & ~MII_BCM5201_MULTIPHY_SUPERISOLATE); + } + mdelay(1); + + if (gm->opened) { + /* restart polling PHY */ + mii_interrupt(gm); + /* restart DMA operations */ + gmac_start_dma(gm); + netif_start_queue(gm->dev); + enable_irq(gm->dev->irq); + } else { + /* Driver not opened, just leave things off. Note that + * we could be smart and superisolate the PHY when the + * driver is closed, but I won't do that unless I have + * a better understanding of some electrical issues with + * this PHY chip --BenH + */ + GM_OUT(GM_MAC_RX_CONFIG, 0); + GM_OUT(GM_MAC_TX_CONFIG, 0); + GM_OUT(GM_MAC_XIF_CONFIG, 0); + GM_OUT(GM_TX_CONF, 0); + GM_OUT(GM_RX_CONF, 0); + } +} + static int mii_do_reset_phy(struct gmac *gm, int phy_addr) { @@ -326,6 +471,40 @@ mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); } +static void +mii_init_BCM5401(struct gmac *gm) +{ + int data; + int rev; + + rev = mii_read(gm, gm->phy_addr, MII_ID1) & 0x000f; + if (rev == 0 || rev == 3) { + /* A bit of black magic from Apple */ + mii_write(gm, gm->phy_addr, 0x18, 0x0c20); + mii_write(gm, gm->phy_addr, 0x17, 0x0012); + mii_write(gm, gm->phy_addr, 0x15, 0x1804); + mii_write(gm, gm->phy_addr, 0x17, 0x0013); + mii_write(gm, gm->phy_addr, 0x15, 0x1204); + mii_write(gm, gm->phy_addr, 0x17, 0x8006); + mii_write(gm, gm->phy_addr, 0x15, 0x0132); + mii_write(gm, gm->phy_addr, 0x17, 0x8006); + mii_write(gm, gm->phy_addr, 0x15, 0x0232); + mii_write(gm, gm->phy_addr, 0x17, 0x201f); + mii_write(gm, gm->phy_addr, 0x15, 0x0a20); + } + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); +} + static int mii_lookup_and_reset(struct gmac *gm) { @@ -335,10 +514,7 @@ gm->phy_type = PHY_UNKNOWN; /* Hard reset the PHY */ - feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); - mdelay(10); - feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); - mdelay(10); + feature_gmac_phy_reset(gm->of_node); /* Find the PHY */ for(i=0; i<=31; i++) { @@ -367,14 +543,22 @@ printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); mii_init_BCM5400(gm); + } else if ((gm->phy_id & MII_BCM5401_MASK) == MII_BCM5401_ID) { + gm->phy_type = PHY_B5401; + printk(KERN_ERR "%s Found Broadcom BCM5401 PHY (Gigabit)\n", + gm->dev->name); + mii_init_BCM5401(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_BCM5221_MASK) == MII_BCM5221_ID) { + gm->phy_type = PHY_B5201; /* Same as 5201 for now */ + printk(KERN_INFO "%s Found Broadcom BCM5221 PHY\n", gm->dev->name); } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { gm->phy_type = PHY_LXT971; printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { - printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", + printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n", gm->dev->name, gm->phy_id); } @@ -448,8 +632,6 @@ PCI_CACHE_LINE_SIZE, 8); } } else { - /* FIXME: Add PHY power down */ - gm->phy_type = 0; feature_set_gmac_power(gm->of_node, 0); } } @@ -472,11 +654,14 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); return 0; } } printk(KERN_ERR "%s reset failed!\n", dev->name); gmac_set_power(gm, 0); + gm->phy_type = 0; return -1; } @@ -747,7 +932,9 @@ int multicast_hash = 0; int multicast_all = 0; int promisc = 0; - + + if (gm->sleeping) + return; /* Lock out others. */ netif_stop_queue(dev); @@ -881,6 +1068,7 @@ /* Shut down chip */ gmac_set_power(gm, 0); + gm->phy_type = 0; /* Empty rings of any remaining gremlins */ for (i = 0; i < NRX; ++i) { @@ -904,7 +1092,6 @@ gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) { struct gmac *gm; - int i; /* XXX should handle more than one */ if (gmacs == NULL) @@ -920,38 +1107,10 @@ case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: - disable_irq(gm->dev->irq); - netif_stop_queue(gm->dev); - gmac_stop_dma(gm); - mii_poll_stop(gm); - gmac_set_power(gm, 0); - for (i = 0; i < NRX; ++i) { - if (gm->rx_buff[i] != 0) { - dev_kfree_skb(gm->rx_buff[i]); - gm->rx_buff[i] = 0; - } - } - for (i = 0; i < NTX; ++i) { - if (gm->tx_buff[i] != 0) { - dev_kfree_skb(gm->tx_buff[i]); - gm->tx_buff[i] = 0; - } - } + gmac_suspend(gm); break; case PBOOK_WAKE: - /* see if this is enough */ - gmac_powerup_and_reset(gm->dev); - gm->full_duplex = 0; - gm->phy_status = 0; - mii_lookup_and_reset(gm); - mii_setup_phy(gm); - gmac_init_rings(gm, 0); - gmac_mac_init(gm, gm->dev->dev_addr); - gmac_set_multicast(gm->dev); - mii_interrupt(gm); - gmac_start_dma(gm); - netif_start_queue(gm->dev); - enable_irq(gm->dev->irq); + gmac_resume(gm); break; } return PBOOK_SLEEP_OK; @@ -967,7 +1126,10 @@ struct gmac *gm = (struct gmac *) dev->priv; int i, timeout; unsigned long flags; - + + if (gm->sleeping) + return; + printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); spin_lock_irqsave(&gm->lock, flags); @@ -990,6 +1152,8 @@ if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) { /* Mask out all chips interrupts */ GM_OUT(GM_IRQ_MASK, 0xffffffff); + GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW); + GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW); break; } } @@ -1022,6 +1186,9 @@ unsigned long flags; int i; + if (gm->sleeping) + return 1; + spin_lock_irqsave(&gm->lock, flags); i = gm->next_tx; @@ -1274,7 +1441,7 @@ struct gmac *gm = (struct gmac *) dev->priv; struct net_device_stats *stats = &gm->stats; - if (gm && gm->opened) { + if (gm && gm->opened && !gm->sleeping) { stats->rx_crc_errors += GM_IN(GM_MAC_RX_CRC_ERR_CTR); GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0); @@ -1315,10 +1482,14 @@ gmac = gmac->next) gmac_probe1(gmac); +#ifdef CONFIG_PMAC_PBOOK + if (gmacs) + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif MOD_DEC_USE_COUNT; - return 0; + return gmacs? 0: -ENODEV; } static void @@ -1343,6 +1514,14 @@ return; } + if (dummy_buf == NULL) { + dummy_buf = kmalloc(DUMMY_BUF_LEN, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "GMAC: failed to allocated dummy buffer\n"); + return; + } + } + tx_descpage = get_free_page(GFP_KERNEL); if (tx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for tx descriptors\n"); @@ -1351,17 +1530,13 @@ rx_descpage = get_free_page(GFP_KERNEL); if (rx_descpage == 0) { printk(KERN_ERR "GMAC: can't get a page for rx descriptors\n"); - free_page(tx_descpage); - return; + goto out_txdesc; } dev = init_etherdev(NULL, sizeof(struct gmac)); - if (!dev) { printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n"); - free_page(tx_descpage); - free_page(rx_descpage); - return; + goto out_rxdesc; } SET_MODULE_OWNER(dev); @@ -1369,6 +1544,10 @@ dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); + if (!gm->regs) { + printk(KERN_ERR "GMAC: unable to map I/O registers\n"); + goto out_unreg; + } dev->irq = gmac->intrs[0].line; gm->dev = dev; gm->of_node = gmac; @@ -1394,6 +1573,7 @@ gm->phy_addr = 0; gm->opened = 0; + gm->sleeping = 0; dev->open = gmac_open; dev->stop = gmac_close; @@ -1404,13 +1584,18 @@ dev->watchdog_timeo = 5*HZ; ether_setup(dev); - + gm->next_gmac = gmacs; gmacs = dev; + return; -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&gmac_sleep_notifier); -#endif +out_unreg: + unregister_netdev(dev); + kfree(dev); +out_rxdesc: + free_page(rx_descpage); +out_txdesc: + free_page(tx_descpage); } MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); @@ -1421,16 +1606,25 @@ struct gmac *gm; struct net_device *dev; +#ifdef CONFIG_PMAC_PBOOK + if (gmacs) + pmu_unregister_sleep_notifier(&gmac_sleep_notifier); +#endif + while ((dev = gmacs) != NULL) { gm = (struct gmac *) dev->priv; unregister_netdev(dev); + iounmap((void *) gm->regs); free_page(gm->tx_desc_page); free_page(gm->rx_desc_page); gmacs = gm->next_gmac; kfree(dev); } + if (dummy_buf != NULL) { + kfree(dummy_buf); + dummy_buf = NULL; + } } module_init(gmac_probe); module_exit(gmac_cleanup_module); - diff -u --recursive --new-file v2.4.4/linux/drivers/net/gmac.h linux/drivers/net/gmac.h --- v2.4.4/linux/drivers/net/gmac.h Sun Sep 17 09:48:05 2000 +++ linux/drivers/net/gmac.h Wed May 16 09:58:36 2001 @@ -722,6 +722,13 @@ #define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */ #define MII_ANLPA_PAUS 0x0400 +/* Generic PHYs + * + * These GENERIC values assumes that the PHY devices follow 802.3u and + * allow parallel detection to set the link partner ability register. + * Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported. + */ + /* * Model-specific PHY registers * @@ -731,6 +738,7 @@ /* Supported PHYs (phy_type field ) */ #define PHY_B5400 0x5400 +#define PHY_B5401 0x5401 #define PHY_B5201 0x5201 #define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 @@ -741,11 +749,21 @@ #define MII_BCM5201_REV 0x01 #define MII_BCM5201_ID ((MII_BCM5201_OUI << 10) | (MII_BCM5201_MODEL << 4)) #define MII_BCM5201_MASK 0xfffffff0 +#define MII_BCM5221_OUI 0x001018 +#define MII_BCM5221_MODEL 0x1e +#define MII_BCM5221_REV 0x00 +#define MII_BCM5221_ID ((MII_BCM5221_OUI << 10) | (MII_BCM5221_MODEL << 4)) +#define MII_BCM5221_MASK 0xfffffff0 #define MII_BCM5400_OUI 0x000818 #define MII_BCM5400_MODEL 0x04 #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_BCM5401_OUI 0x000818 +#define MII_BCM5401_MODEL 0x05 +#define MII_BCM5401_REV 0x01 +#define MII_BCM5401_ID ((MII_BCM5401_OUI << 10) | (MII_BCM5401_MODEL << 4)) +#define MII_BCM5401_MASK 0xfffffff0 #define MII_LXT971_OUI 0x0004de #define MII_LXT971_MODEL 0x0e #define MII_LXT971_REV 0x00 @@ -791,7 +809,6 @@ #define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 - /* * DMA descriptors */ @@ -877,6 +894,7 @@ u8 pci_devfn; spinlock_t lock; int opened; + int sleeping; struct net_device *next_gmac; }; diff -u --recursive --new-file v2.4.4/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c --- v2.4.4/linux/drivers/net/hamachi.c Fri Apr 20 11:54:23 2001 +++ linux/drivers/net/hamachi.c Sat May 19 18:02:45 2001 @@ -23,10 +23,21 @@ or http://www.parl.clemson.edu/~keithu/hamachi.html - For best viewing, set your tabs to 3. + + + Linux kernel changelog: + + LK1.0.1: + - fix lack of pci_dev<->dev association + - ethtool support (jgarzik) */ +#define DRV_NAME "hamachi" +#define DRV_VERSION "1.01+LK1.0.1" +#define DRV_RELDATE "5/18/2001" + + /* A few user-configurable values. */ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ @@ -116,7 +127,7 @@ #define RX_RING_SIZE 512 /* - * Enable mii_ioctl. Added interrupt coalescing parameter adjustment. + * Enable netdev_ioctl. Added interrupt coalescing parameter adjustment. * 2/19/99 Pete Wyckoff */ @@ -152,7 +163,9 @@ #include #include #include +#include +#include #include /* Processor type for cache alignment. */ #include #include @@ -166,7 +179,7 @@ #include static char version[] __initdata = -KERN_INFO "hamachi.c:v1.01 5/16/2000 Written by Donald Becker\n" +KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" KERN_INFO " Some modifications by Eric kasten \n" KERN_INFO " Further modifications by Keith Underwood \n"; @@ -502,7 +515,7 @@ unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ u_int32_t rx_int_var, tx_int_var; /* interrupt control variables */ u_int32_t option; /* Hold on to a copy of the options */ - u_int8_t pad[16]; /* Used for 32-byte alignment */ + struct pci_dev *pci_dev; }; MODULE_AUTHOR("Donald Becker , Eric Kasten , Keith Underwood "); @@ -527,7 +540,7 @@ static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); static int hamachi_open(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); @@ -569,7 +582,7 @@ pci_set_master(pdev); - i = pci_request_regions(pdev, "hamachi"); + i = pci_request_regions(pdev, DRV_NAME); if (i) return i; irq = pdev->irq; @@ -633,8 +646,10 @@ dev->base_addr = ioaddr; dev->irq = irq; + pci_set_drvdata(pdev, dev); hmp->chip_id = chip_id; + hmp->pci_dev = pdev; /* The lower four bits are the media type. */ if (option > 0) { @@ -676,7 +691,7 @@ dev->stop = &hamachi_close; dev->get_stats = &hamachi_get_stats; dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &hamachi_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) @@ -687,6 +702,7 @@ kfree(dev); iounmap((char *)ioaddr); pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); return i; } @@ -1815,12 +1831,38 @@ } } -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct hamachi_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pci_dev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ @@ -1878,7 +1920,7 @@ MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl); static struct pci_driver hamachi_driver = { - name: "hamachi", + name: DRV_NAME, id_table: hamachi_pci_tbl, probe: hamachi_init_one, remove: hamachi_remove_one, diff -u --recursive --new-file v2.4.4/linux/drivers/net/hp100.h linux/drivers/net/hp100.h --- v2.4.4/linux/drivers/net/hp100.h Wed May 20 18:55:04 1998 +++ linux/drivers/net/hp100.h Wed May 16 10:25:38 2001 @@ -38,10 +38,10 @@ #define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */ #define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */ #define HP100_REG_PAGING 0x02 /* R: (16),15:4 Card ID */ - /* W: (16),3:0 Switch pages */ + /* W: (16),3:0 Switch pages */ #define HP100_REG_OPTION_LSW 0x04 /* RW: (16) Select card functions */ #define HP100_REG_OPTION_MSW 0x06 /* RW: (16) Select card functions */ - + /* Page 0 - Performance */ #define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */ @@ -53,27 +53,27 @@ #define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */ #define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */ #define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */ -#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */ -#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */ +#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */ +#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */ #define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */ #define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */ -#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */ -#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */ -#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */ - /* which point to a PDL */ -#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */ -#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */ -#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */ -#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */ -#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */ -#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */ -#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */ +#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */ +#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */ +#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */ + /* which point to a PDL */ +#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */ +#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */ +#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */ +#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */ +#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */ +#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */ +#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */ /* Page 1 - MAC Address/Hash Table */ -#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */ +#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */ #define HP100_REG_HASH_BYTE0 0x10 /* RW: (8) Cards multicast filter */ - + /* Page 2 - Hardware Mapping */ #define HP100_REG_MEM_MAP_LSW 0x08 /* RW: (16) LSW of cards mem addr */ @@ -84,44 +84,44 @@ #define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */ /* New on Page 2 for ETR chips: */ -#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */ -#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */ -#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */ -#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */ -#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */ -#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */ -#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */ -#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */ -#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */ - +#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */ +#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */ +#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */ +#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */ +#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */ +#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */ +#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */ +#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */ +#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */ + /* Page 3 - EEPROM/Boot ROM */ #define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */ #define HP100_REG_BOOTROM_CTRL 0x0a - + /* Page 4 - LAN Configuration (MAC_CTRL) */ #define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */ -#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */ +#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */ #define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */ -#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */ +#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */ #define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */ #define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */ -#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ -#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ -#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem*/ +#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ +#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ +#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem */ #define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */ #define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */ -#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register.*/ -#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */ - +#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register. */ +#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */ + /* Page 5 - MMU */ #define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */ #define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */ -#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */ -#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */ - +#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */ +#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */ + /* Page 6 - Card ID/Physical LAN Address */ #define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */ @@ -129,7 +129,7 @@ #define HP100_REG_SOFT_MODEL 0x0d /* R: (8) Config program defined */ #define HP100_REG_LAN_ADDR 0x10 /* R: (8) MAC addr of card */ #define HP100_REG_LAN_ADDR_CHCK 0x16 /* R: (8) Added to addr to get FFh */ - + /* Page 7 - MMU Current Pointers */ #define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */ @@ -146,7 +146,7 @@ /* * Hardware ID Register I (Always available, HW_ID, Offset 0x00) */ -#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */ +#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */ /* * Hardware ID Register 2 & Paging Register @@ -154,12 +154,12 @@ * Bits 15:4 are for the Chip ID */ #define HP100_CHIPID_MASK 0xFFF0 -#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */ - /* EISA BM/SL, MCA16/32 SL, ISA SL */ -#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM,*/ - /* PCI SL, MCA16/32 SL, ISA SL */ -#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */ - /* LRF supported */ +#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */ + /* EISA BM/SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM, */ + /* PCI SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */ + /* LRF supported */ /* * Option Registers I and II @@ -167,24 +167,24 @@ */ #define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */ #define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */ - /* system mem. before Rx interrupt */ + /* system mem. before Rx interrupt */ #define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */ - /* MMAP_DIS must be 0 and MEM_EN */ - /* must be 1 for memory-mapped */ - /* mode to be enabled */ + /* MMAP_DIS must be 0 and MEM_EN */ + /* must be 1 for memory-mapped */ + /* mode to be enabled */ #define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */ #define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */ #define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */ #define HP100_TRI_INT 0x0200 /* 0:Don't, 1:Do tri-state the int */ #define HP100_MEM_EN 0x0040 /* Config program set this to */ - /* 0:Disable, 1:Enable mem map. */ - /* See MMAP_DIS. */ + /* 0:Disable, 1:Enable mem map. */ + /* See MMAP_DIS. */ #define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */ #define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */ #define HP100_FAKE_INT 0x0008 /* 1:int */ #define HP100_INT_EN 0x0004 /* 1:Enable ints from card */ #define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */ - /* NIC reset on 0 to 1 transition */ + /* NIC reset on 0 to 1 transition */ /* * Option Register III @@ -193,9 +193,9 @@ #define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */ #define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */ #define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */ - /* h/w will set to 0 when done */ + /* h/w will set to 0 when done */ #define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */ - /* will set to 0 when done */ + /* will set to 0 when done */ /* * Interrupt Status Registers I and II @@ -208,10 +208,10 @@ #define HP100_RX_PDL_FILL_COMPL 0x0800 #define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */ #define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */ -#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */ +#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */ #define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */ #define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */ -#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error*/ +#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error */ #define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */ /* @@ -229,7 +229,7 @@ #define HP100_IRQ_SCRAMBLE 0x40 #define HP100_BOND_HP 0x20 #define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */ - /* (Only valid on EISA cards) */ + /* (Only valid on EISA cards) */ #define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */ /* @@ -237,20 +237,20 @@ * (Page HW_MAP, SRAM, Offset 0x0e) */ #define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */ -#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits)*/ +#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits) */ /* * Bus Master Register * (Page HW_MAP, BM, Offset 0x0f) */ -#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */ - /* memory to chip (tx) */ -#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */ - /* memory to chip (rx) */ +#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (tx) */ +#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (rx) */ #define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */ -#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in*/ - /* an EISA system */ -#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */ +#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in */ + /* an EISA system */ +#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */ /* @@ -258,82 +258,82 @@ * (Page HW_MAP, MODECTRL1, Offset0x10) */ #define HP100_TX_DUALQ 0x10 - /* If set and BM -> dual tx pda queues*/ -#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */ - /* interrupts on read (etr only?) */ -#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */ - /* from the eeprom */ -#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */ -#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */ - /* first three data elements of a PDL */ - /* on the first access. */ -#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */ + /* If set and BM -> dual tx pda queues */ +#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */ + /* interrupts on read (etr only?) */ +#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */ + /* from the eeprom */ +#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */ +#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */ + /* first three data elements of a PDL */ + /* on the first access. */ +#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */ /* * Mode Control Register II * (Page HW_MAP, MODECTRL2, Offset0x11) */ -#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */ - /* certain resources */ -#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */ -#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */ - /* written back to system mem */ -#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */ - /* interrupt */ +#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */ + /* certain resources */ +#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */ +#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */ + /* written back to system mem */ +#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */ + /* interrupt */ /* * PCI Configuration and Control Register I * (Page HW_MAP, PCICTRL1, Offset 0x12) */ -#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */ -#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */ - /* bios */ -#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */ - /* simultaneously with PCI decodes */ -#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */ -#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */ - +#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */ +#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */ + /* bios */ +#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */ + /* simultaneously with PCI decodes */ +#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */ +#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */ + /* * PCI Configuration and Control Register II * (Page HW_MAP, PCICTRL2, Offset 0x13) */ -#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */ -#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */ -#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */ -#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */ -#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */ - /* pci stop if cascade not ready */ -#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity*/ -#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */ +#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */ +#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */ +#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */ +#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */ +#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */ + /* pci stop if cascade not ready */ +#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity */ +#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */ /* * Early TX Configuration and Control Register * (Page HW_MAP, EARLYTXCFG, Offset 0x16) */ -#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */ -#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */ -#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */ -#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */ -#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */ +#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */ +#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */ +#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */ +#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */ +#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */ /* * Early RX Configuration and Control Register * (Page HW_MAP, EARLYRXCFG, Offset 0x18) */ -#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */ -#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */ -#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the - * early rx circuit will start the - * dma of received packet into system - * memory for BM */ +#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */ +#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */ +#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the + * early rx circuit will start the + * dma of received packet into system + * memory for BM */ /* * Serial Devices Control Register * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08) */ #define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */ - /* When it goes back to 0, load is */ - /* complete. This should take ~600us.*/ + /* When it goes back to 0, load is */ + /* complete. This should take ~600us. */ /* * 10MB LAN Control and Configuration Register I @@ -345,7 +345,7 @@ #define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */ #define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */ #define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */ - /* been reversed */ + /* been reversed */ #define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */ /* @@ -353,9 +353,9 @@ * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09) */ #define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */ - /* after Tx.Only used for AUI. */ -#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */ -#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */ + /* after Tx.Only used for AUI. */ +#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */ +#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */ /* * MAC Selection, use with MAC10_SEL bits @@ -372,9 +372,9 @@ #define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */ #define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */ #define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */ - /* promiscuous */ + /* promiscuous */ #define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */ - /* be a cascaded repeater */ + /* be a cascaded repeater */ /* * 100MB LAN Control and Configuration Register @@ -383,16 +383,16 @@ #define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */ #define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */ #define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */ - /* from hub */ + /* from hub */ #define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */ - /* 100ms later the link status */ - /* bits are valid */ + /* 100ms later the link status */ + /* bits are valid */ #define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */ - /* 100ms later the link status */ - /* bits are valid */ -#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */ - /* after LinkUp Cmd is given and set */ - /* when training has completed. */ + /* 100ms later the link status */ + /* bits are valid */ +#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */ + /* after LinkUp Cmd is given and set */ + /* when training has completed. */ #define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */ #define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */ @@ -414,7 +414,7 @@ #define HP100_MAC1MODE2 0x00 #define HP100_MAC1MODE3 HP100_MAC1MODE2 | HP100_ACC_BC #define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC -#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */ +#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */ #define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */ /* Note MODE6 will receive all GOOD packets on the LAN. This really needs a mode 7 defined to be LAN Analyzer mode, which will receive errored and @@ -428,14 +428,14 @@ #define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */ #define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */ #define HP100_LBK_XCVR 0x20 /* 0:No, 1:Yes loopback through MAC & */ - /* transceiver */ + /* transceiver */ #define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */ #define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */ -#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring +#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring * group addr that maches NA mask */ #define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */ - /* The length will reflect this. */ -#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional + /* The length will reflect this. */ +#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional * addrs that match FA mask (page1) */ #define HP100_MAC2MODEMASK 0x02 #define HP100_MAC2MODE1 0x00 @@ -450,58 +450,58 @@ * MAC Configuration Register III * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e) */ -#define HP100_PACKET_PACE 0x03 /* Packet Pacing: - * 00: No packet pacing - * 01: 8 to 16 uS delay - * 10: 16 to 32 uS delay - * 11: 32 to 64 uS delay - */ -#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and - * TCP/IP Checksumming enabled. */ -#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */ +#define HP100_PACKET_PACE 0x03 /* Packet Pacing: + * 00: No packet pacing + * 01: 8 to 16 uS delay + * 10: 16 to 32 uS delay + * 11: 32 to 64 uS delay + */ +#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and + * TCP/IP Checksumming enabled. */ +#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */ /* * MAC Configuration Register IV * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f) */ -#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL - * Signal, 1=100VG, 0=10Mbit sel. */ -#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion - * of the Misc. Interrupt */ +#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL + * Signal, 1=100VG, 0=10Mbit sel. */ +#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion + * of the Misc. Interrupt */ /* * 100 MB LAN Training Request/Allowed Registers * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only) */ -#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be - * a cascaded repeater - * 0: ... wants to be a DTE */ -#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode - * 00: Rcv only unicast packets - * specifically addr to this - * endnode - * 10: Rcv all pckts fwded by - * the local repeater */ -#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */ -#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */ -#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */ -#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */ -#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an - * end node is allowed */ -#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode - * 00: Rcv only unicast packets - * specifically addr to this - * endnode - * 10: Rcv all pckts fwded by - * the local repeater */ -#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format - * 00: 802.3 format will be used - * 10: 802.5 format will be used */ -#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */ -#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */ -#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */ -#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */ - /* protocol of repeater */ +#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be + * a cascaded repeater + * 0: ... wants to be a DTE */ +#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */ +#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */ +#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */ +#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */ +#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an + * end node is allowed */ +#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format + * 00: 802.3 format will be used + * 10: 802.5 format will be used */ +#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */ +#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */ +#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */ +#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */ + /* protocol of repeater */ /* ****************************************************************************** */ @@ -516,7 +516,7 @@ /* * Misc. Constants */ -#define HP100_LAN_100 100 /* lan_type value for VG */ +#define HP100_LAN_100 100 /* lan_type value for VG */ #define HP100_LAN_10 10 /* lan_type value for 10BaseT */ #define HP100_LAN_ERR (-1) /* lan_type value for link down */ @@ -528,10 +528,10 @@ * Bus Master Data Structures ---------------------------------------------- */ -#define MAX_RX_PDL 30 /* Card limit = 31 */ -#define MAX_RX_FRAG 2 /* Don't need more... */ +#define MAX_RX_PDL 30 /* Card limit = 31 */ +#define MAX_RX_FRAG 2 /* Don't need more... */ #define MAX_TX_PDL 29 -#define MAX_TX_FRAG 2 /* Limit = 31 */ +#define MAX_TX_FRAG 2 /* Limit = 31 */ /* Define total PDL area size in bytes (should be 4096) */ /* This is the size of kernel (dma) memory that will be allocated. */ @@ -539,16 +539,16 @@ /* Ethernet Packet Sizes */ #define MIN_ETHER_SIZE 60 -#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */ - /* skb buffer when busmastering */ +#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */ + /* skb buffer when busmastering */ /* Tx or Rx Ring Entry */ typedef struct hp100_ring { - u_int *pdl; /* Address of PDLs PDH, dword before - * this address is used for rx hdr */ - u_int pdl_paddr; /* Physical address of PDL */ - struct sk_buff *skb; - struct hp100_ring *next; + u_int *pdl; /* Address of PDLs PDH, dword before + * this address is used for rx hdr */ + u_int pdl_paddr; /* Physical address of PDL */ + struct sk_buff *skb; + struct hp100_ring *next; } hp100_ring_t; @@ -564,12 +564,12 @@ #define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */ #define HP100_BAD_SYMBOL_ERR 0x1000 /* 0:No, 1:Yes invalid symbol received */ #define HP100_RCV_IPM_ERR 0x0800 /* 0:No, 1:Yes pkt had an invalid packet */ - /* marker */ + /* marker */ #define HP100_SYMBOL_BAL_ERR 0x0400 /* 0:No, 1:Yes symbol balance error */ #define HP100_VG_ALN_ERR 0x0200 /* 0:No, 1:Yes non-octet received */ #define HP100_TRUNC_ERR 0x0100 /* 0:No, 1:Yes the packet was truncated */ #define HP100_RUNT_ERR 0x0040 /* 0:No, 1:Yes pkt length < Min Pkt */ - /* Length Reg. */ + /* Length Reg. */ #define HP100_ALN_ERR 0x0010 /* 0:No, 1:Yes align error. */ #define HP100_CRC_ERR 0x0008 /* 0:No, 1:Yes CRC occurred. */ @@ -616,11 +616,3 @@ outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW ) #define hp100_mem_map_disable() \ outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW ) - - -/* - * Local variables: - * c-indent-level: 2 - * tab-width: 8 - * End: -*/ diff -u --recursive --new-file v2.4.4/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.4.4/linux/drivers/net/ioc3-eth.c Tue Mar 20 12:04:58 2001 +++ linux/drivers/net/ioc3-eth.c Wed May 16 10:25:38 2001 @@ -402,7 +402,7 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) { - struct ioc3_private *ip = (struct ioc3_private *) dev->priv; + struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; ip->stats.collisions += (ioc3->etcdc & ETCDC_COLLCNT_MASK); @@ -566,7 +566,7 @@ after the Tx thread. */ static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)_dev; + struct net_device *dev = _dev; struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | @@ -595,7 +595,7 @@ static void negotiate(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct ioc3_private *ip = (struct ioc3_private *) dev->priv; + struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; mod_timer(&ip->negtimer, jiffies + 20 * HZ); @@ -864,7 +864,7 @@ return -EAGAIN; } - ip = (struct ioc3_private *) dev->priv; + ip = dev->priv; ip->ehar_h = 0; ip->ehar_l = 0; @@ -1131,7 +1131,7 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct ioc3_private *ip = (struct ioc3_private *) dev->priv; + struct ioc3_private *ip = dev->priv; u16 *data = (u16 *)&rq->ifr_data; struct ioc3 *ioc3 = ip->regs; int phy = ip->phy; diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in --- v2.4.4/linux/drivers/net/irda/Config.in Fri Jan 28 19:36:22 2000 +++ linux/drivers/net/irda/Config.in Tue May 1 16:05:00 2001 @@ -5,14 +5,6 @@ dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA -comment 'FIR device drivers' -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 -if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then -dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA -fi - comment 'Dongle support' bool 'Serial dongle support' CONFIG_DONGLE if [ "$CONFIG_DONGLE" != "n" ]; then @@ -22,6 +14,15 @@ dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA +fi + +comment 'FIR device drivers' +dep_tristate 'IrDA USB dongles (Experimental)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL +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 +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then +dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA fi endmenu diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.4.4/linux/drivers/net/irda/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/irda/Makefile Tue May 1 16:05:00 2001 @@ -12,6 +12,7 @@ obj-$(CONFIG_IRTTY_SIR) += irtty.o obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_USB_IRDA) += irda-usb.o obj-$(CONFIG_NSC_FIR) += nsc-ircc.o obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c --- v2.4.4/linux/drivers/net/irda/irda-usb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/irda/irda-usb.c Tue May 1 16:05:00 2001 @@ -0,0 +1,1176 @@ +/***************************************************************************** + * + * Filename: irda-usb.c + * Version: 0.9 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli + * + * Copyright (C) 2001, Dag Brattli + * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2000, Roman Weissgaerber + * + * 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 + +static u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ +static int qos_mtt_bits = 0; + +static void irda_usb_dump_class_desc(struct irda_class_desc *desc); +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum); +static void irda_usb_disconnect(struct usb_device *dev, void *ptr); +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static int irda_usb_open(struct irda_usb_cb *self); +static int irda_usb_close(struct irda_usb_cb *self); +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb); +static void write_bulk_callback(purb_t purb); +static void irda_usb_receive(purb_t purb); +static int irda_usb_net_init(struct net_device *dev); +static int irda_usb_net_open(struct net_device *dev); +static int irda_usb_net_close(struct net_device *dev); +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void irda_usb_net_timeout(struct net_device *dev); +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev); + +/* Master instance for each hardware found */ +#define NIRUSB 4 /* Max number of USB-IrDA dongles */ +static struct irda_usb_cb irda_instance[NIRUSB]; + +/* These are the currently known IrDA USB dongles. Add new dongles here */ +static struct usb_device_id dongles[] = { + /* ACTiSYS Corp, ACT-IR2000U FIR-USB Adapter */ + { USB_DEVICE(0x9c4, 0x011), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* KC Technology Inc., KC-180 USB IrDA Device */ + { USB_DEVICE(0x50f, 0x180), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ + { USB_DEVICE(0x8e9, 0x100), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, + bInterfaceClass: USB_CLASS_APP_SPEC, + bInterfaceSubClass: USB_CLASS_IRDA, + driver_info: IUC_DEFAULT, }, + { }, /* The end */ +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + * Note : it might be worth protecting this function by a global + * spinlock... + */ +static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct irda_usb_cb *self = NULL; + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct irda_class_desc *irda_desc; + int capability = id->driver_info; + int ret; + int ep; + int i; + + IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); + + MESSAGE("IRDA-USB found at address %d\n", dev->devnum); + + /* Try to cleanup all instance that have a pending disconnect + * Instance will be in this state is the disconnect() occurs + * before the net_close(). + * Jean II */ + for (i = 0; i < NIRUSB; i++) { + struct irda_usb_cb *irda = &irda_instance[i]; + if ((irda->usbdev != NULL) && + (irda->present == 0) && + (irda->netopen == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + + /* Find an free instance to handle this new device... */ + self = NULL; + for (i = 0; i < NIRUSB; i++) { + if(irda_instance[i].usbdev == NULL) { + self = &irda_instance[i]; + break; + } + } + if (self == NULL) { + IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n", + NIRUSB); + return NULL; + } + + /* Reset the instance */ + self->present = 0; + self->netopen = 0; + + /* Is this really necessary? */ + if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) { + err("set_configuration failed"); + return NULL; + } + + /* Is this really necessary? */ + ret = usb_set_interface(dev, ifnum, 0); + IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret); + switch (ret) { + case USB_ST_NOERROR: /* 0 */ + break; + case USB_ST_STALL: /* -EPIPE = -32 */ + usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); + IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" ); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret); + return NULL; + break; + } + + /* Find our endpoints */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + endpoint = interface->endpoint; + ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[0].wMaxPacketSize; + } + + ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[1].wMaxPacketSize; + } + + if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 || + endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK || + endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) + { + ERROR(__FUNCTION__ "(), Bogus endpoints"); + return NULL; + } + + /* Find IrDA class descriptor */ + irda_desc = irda_usb_find_class_desc(dev, ifnum); + if (irda_desc == NULL) + return NULL; + + self->irda_desc = irda_desc; + self->present = 1; + self->netopen = 0; + self->capability = capability; + self->usbdev = dev; + ret = irda_usb_open(self); + if (ret) + return NULL; + + return self; +} + +/* + * Function irda_usb_find_class_desc(dev, ifnum) + * + * Returns instance of IrDA class descriptor, or NULL if not found + * + */ +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct irda_class_desc *desc, *ptr; + int ret; + + desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + if (desc == NULL) + return NULL; + memset(desc, 0, sizeof(struct irda_class_desc)); + + ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); + IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret); + if (ret) { + WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret); + } + + /* Check if we found it? */ + if (desc->bDescriptorType == USB_DT_IRDA) + return desc; + + IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n"); + + /* Check if the class descriptor is interleaved with standard descriptors */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); + if (ret) { + kfree(desc); + return NULL; + } + *desc = *ptr; +#if 0 + irda_usb_dump_class_desc(desc); +#endif + return desc; +} + +/* + * Function usb_irda_dump_class_desc(desc) + * + * Prints out the contents of the IrDA class descriptor + * + */ +static void irda_usb_dump_class_desc(struct irda_class_desc *desc) +{ + printk("bLength=%x\n", desc->bLength); + printk("bDescriptorType=%x\n", desc->bDescriptorType); + printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); + printk("bmDataSize=%x\n", desc->bmDataSize); + printk("bmWindowSize=%x\n", desc->bmWindowSize); + printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + printk("wBaudRate=%x\n", desc->wBaudRate); + printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList); +} + +static void irda_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Oups ! We are not there any more */ + self->present = 0; + + /* Hum... Check if networking is still active */ + if (self->netopen) { + /* Accept no more transmissions */ + /*netif_device_detach(self->netdev);*/ + netif_stop_queue(self->netdev); + /* Stop all the receive URBs */ + for (i = 0; i < IU_MAX_RX_URBS; i++) + usb_unlink_urb(&(self->rx_urb[i])); + /* Cancel Tx and speed URB */ + usb_unlink_urb(&(self->tx_urb)); + usb_unlink_urb(&(self->speed_urb)); + + IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n"); + /* better not do anything just yet, usb_irda_cleanup() + * will do whats needed */ + return; + } + + /* Cleanup the device stuff */ + irda_usb_close(self); + /* No longer attached to USB bus */ + self->usbdev = NULL; + IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n"); +} + +static struct usb_driver irda_driver = { + name: "irda-usb", + probe: irda_usb_probe, + disconnect: irda_usb_disconnect, + id_table: dongles, +}; + +static void irda_usb_init_qos(struct irda_usb_cb *self) +{ + struct irda_class_desc *desc; + + desc = self->irda_desc; + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + self->qos.baud_rate.bits = desc->wBaudRate; + self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime; + self->qos.additional_bofs.bits = desc->bmAdditionalBOFs; + self->qos.window_size.bits = desc->bmWindowSize; + self->qos.data_size.bits = desc->bmDataSize; + + IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); + + /* Don't always trust what the dongle tell us */ + if (self->capability & IUC_SIR_ONLY) + self->qos.baud_rate.bits &= 0xff; + if (self->capability & IUC_SMALL_PKT) + self->qos.data_size.bits = 0x07; + if (self->capability & IUC_NO_WINDOW) + self->qos.window_size.bits = 0x01; + if (self->capability & IUC_MAX_WINDOW) + self->qos.window_size.bits = 0x7f; + if (self->capability & IUC_MAX_XBOFS) + self->qos.additional_bofs.bits = 0x01; + +#if 1 + /* Module parameter can override the rx window size */ + if (qos_mtt_bits) + self->qos.min_turn_time.bits = qos_mtt_bits; +#endif + /* + * Note : most of those values apply only for the receive path, + * the transmit path will be set differently - Jean II + */ + irda_qos_bits_to_value(&self->qos); + + self->flags |= IFF_SIR; + if (self->qos.baud_rate.value > 115200) + self->flags |= IFF_MIR; + if (self->qos.baud_rate.value > 1152000) + self->flags |= IFF_FIR; + if (self->qos.baud_rate.value > 4000000) + self->flags |= IFF_VFIR; +} + +static int irda_usb_open(struct irda_usb_cb *self) +{ + struct net_device *netdev; + int err; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + spin_lock_init(&self->lock); + + irda_usb_init_qos(self); + + self->tx_list = hashbin_new(HB_GLOBAL); + + /* Create a network device for us */ + if (!(netdev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -1; + } + self->netdev = netdev; + netdev->priv = (void *) self; + + /* Override the network functions we need to use */ + netdev->init = irda_usb_net_init; + netdev->hard_start_xmit = irda_usb_hard_xmit; + netdev->tx_timeout = irda_usb_net_timeout; + netdev->watchdog_timeo = 110*HZ/1000; /* 110 ms > USB timeout */ + netdev->open = irda_usb_net_open; + netdev->stop = irda_usb_net_close; + netdev->get_stats = irda_usb_net_get_stats; + netdev->do_ioctl = irda_usb_net_ioctl; + + rtnl_lock(); + err = register_netdevice(netdev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + MESSAGE("IrDA: Registered device %s\n", netdev->name); + + return 0; +} + +static int irda_usb_close(struct irda_usb_cb *self) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return -1;); + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + self->netdev = NULL; + rtnl_unlock(); + } + hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any); + + return 0; +} + +/* + * Function irda_usb_build_header(self, skb, header) + * + * Builds USB-IrDA outbound header + * + * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 + * that the setting of the link speed and xbof number in this outbound header + * should be applied *AFTER* the frame has been sent. + * Unfortunately, some devices are not compliant with that... It seems that + * reading the spec is far too difficult... + * Jean II + */ +static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header, + int force) +{ + /* Set the negotiated link speed */ + if (self->new_speed != -1) { + /* Hum... Ugly hack :-( + * Some device are not compliant with the spec and change + * parameters *before* sending the frame. - Jean II + */ + if ((self->capability & IUC_SPEED_BUG) && + (!force) && (self->speed != -1)) + { + /* No speed and xbofs change here + * (we'll do it later in the write callback) */ + IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n"); + *header = 0; + return; + } + + IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed); + self->speed = self->new_speed; + self->new_speed = -1; + + switch (self->speed) { + case 2400: + *header = SPEED_2400; + break; + default: + case 9600: + *header = SPEED_9600; + break; + case 19200: + *header = SPEED_19200; + break; + case 38400: + *header = SPEED_38400; + break; + case 57600: + *header = SPEED_57600; + break; + case 115200: + *header = SPEED_115200; + break; + case 576000: + *header = SPEED_576000; + break; + case 1152000: + *header = SPEED_1152000; + break; + case 4000000: + *header = SPEED_4000000; + self->new_xbofs = 0; + break; + } + } else + /* No change */ + *header = 0; + + /* Set the negotiated additional XBOFS */ + if (self->new_xbofs != -1) { + IRDA_DEBUG(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs); + self->xbofs = self->new_xbofs; + self->new_xbofs = -1; + + switch (self->xbofs) { + case 48: + *header |= 0x10; + break; + case 28: + case 24: /* USB spec 1.0 says 24 */ + *header |= 0x20; + break; + default: + case 12: + *header |= 0x30; + break; + case 5: /* Bug in IrLAP spec? (should be 6) */ + case 6: + *header |= 0x40; + break; + case 3: + *header |= 0x50; + break; + case 2: + *header |= 0x60; + break; + case 1: + *header |= 0x70; + break; + case 0: + *header |= 0x80; + break; + } + } +} + +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) +{ + struct sk_buff *skb; + unsigned long flags; + purb_t purb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n", + self->new_speed, self->new_xbofs); + + purb = &self->speed_urb; + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + return; + } + spin_lock_irqsave(&self->lock, flags); + + /* Allocate the fake frame */ + skb = dev_alloc_skb(IRDA_USB_SPEED_MTU); + if (!skb) + return; + ((struct irda_skb_cb *)skb->cb)->context = self; + + /* Set the new speed and xbofs in this fake frame */ + irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1); + + /* Submit the 0 length IrDA frame to trigger new speed settings */ + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + if ((ret = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n"); + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + purb_t purb = &self->tx_urb; + unsigned long flags; + s32 speed; + s16 xbofs; + int mtt; + + /* Check if the device is still there */ + if ((!self) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n"); + return 1; /* Failed */ + } + + netif_stop_queue(netdev); + + /* Check if we need to change the number of xbofs */ + xbofs = irda_get_next_xbofs(skb); + if ((xbofs != self->xbofs) && (xbofs != -1)) { + self->new_xbofs = xbofs; + } + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->speed) && (speed != -1)) { + /* Set the desired speed */ + self->new_speed = speed; + + /* Check for empty frame */ + if (!skb->len) { + /* IrLAP send us an empty frame to make us change the + * speed. Changing speed with the USB adapter is in + * fact sending an empty frame to the adapter, so we + * could just let the present function do its job. + * However, we would wait for min turn time, + * do an extra memcpy and increment packet counters... + * Jean II */ + irda_usb_change_speed_xbofs(self); + netdev->trans_start = jiffies; + dev_kfree_skb(skb); + /* Will netif_wake_queue() in callback */ + return 0; + } + } + + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + dev_kfree_skb(skb); + return 0; + } + + /* Make room for IrDA-USB header */ + if (skb_cow(skb, USB_IRDA_HEADER)) { + dev_kfree_skb(skb); + return 0; + } + + spin_lock_irqsave(&self->lock, flags); + + /* Change setting for next frame */ + irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + /* FIXME: Make macro out of this one */ + ((struct irda_skb_cb *)skb->cb)->context = self; + + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + /* Generate min turn time */ + mtt = irda_get_mtt(skb); + if (mtt) { + int diff; + get_fast_time(&self->now); + diff = self->now.tv_usec - self->stamp.tv_usec; + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + if (mtt > 1000) { + /* + * FIXME: can we do better than this? Maybe call + * a function which sends a frame to a non + * existing device, or change the speed to the + * current one a number of times just to burn + * time a better way. + */ + mdelay(mtt/1000); + irda_usb_write_bulk(self, purb); + goto out; + } else + udelay(mtt); + } + } + irda_usb_write_bulk(self, purb); +out: + spin_unlock_irqrestore(&self->lock, flags); + + return 0; +} + +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb) +{ + int len = purb->transfer_buffer_length; + int res; + + if ((res = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n"); + self->stats.tx_errors++; + netif_start_queue(self->netdev); + + return; + } + self->stats.tx_packets++; + self->stats.tx_bytes += len; + self->netdev->trans_start = jiffies; + + /* Send empty frame if size if a multiple of the USB max packet size */ + ASSERT(self->bulk_out_mtu == 64, return;); + if ((len % self->bulk_out_mtu) == 0) { + /* Borrow speed urb */ + purb = &self->speed_urb; + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + self, /* Anything not on the stack will do */ + IRDA_USB_MAX_MTU, NULL, NULL); + purb->transfer_buffer_length = 0; + purb->transfer_flags |= USB_QUEUE_BULK; + res = usb_submit_urb(purb); + } +} + +/* + * Note : this function will be called with both tx_urb and speed_urb... + */ +static void write_bulk_callback(purb_t purb) +{ + struct sk_buff *skb = purb->context; + struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; + + /* We should always have a context */ + if (self == NULL) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + return; + } + + /* urb is now available */ + purb->status = USB_ST_NOERROR; + + dev_kfree_skb_any(skb); + purb->context = NULL; + + /* Check for timeout and other USB nasties */ + if (purb->status != USB_ST_NOERROR) { + /* I get a lot of -ECONNABORTED = -103 here - Jean II */ + WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", + purb->status, purb->transfer_flags); + /* Don't do anything here, that might confuse the USB layer, + * and we could go in recursion and blow the kernel stack... + * Instead, we will wait for irda_usb_net_timeout(), the + * network layer watchdog, to fix the situation. + * Jean II */ + /* A reset of the dongle might be welcomed here - Jean II */ + return; + } + + + /* URB is now available */ + purb->status = USB_ST_NOERROR; + + /* If the network is closed, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n"); + return; + } + + /* If we need to change the speed or xbofs, do it now */ + if ((self->new_speed != -1) || (self->new_xbofs != -1)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n"); + irda_usb_change_speed_xbofs(self); + } else { + /* Otherwise, allow the stack to send more packets */ + netif_wake_queue(self->netdev); + } +} + +static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb) +{ + struct irda_skb_cb *cb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + /* Check that we have an urb */ + if (!purb) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n"); + return; + } + + /* Allocate new skb if it has not been recycled */ + if (!skb) { + skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1); + if (!skb) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n"); + return; + } + } else { + /* Reset recycled skb */ + skb->data = skb->tail = skb->head; + skb->len = 0; + } + /* Make sure IP header get aligned (IrDA header is 5 bytes ) */ + skb_reserve(skb, 1); + + /* Save ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + cb->context = self; + + /* Reinitialize URB */ + FILL_BULK_URB(purb, self->usbdev, + usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), + skb->data, skb->truesize, + irda_usb_receive, skb); + purb->transfer_flags |= USB_QUEUE_BULK; + purb->status = USB_ST_NOERROR; + purb->next = NULL; /* Make sure we don't auto resubmit */ + + ret = usb_submit_urb(purb); + if (ret) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + } +} + +/* + * Function irda_usb_receive(purb) + * + * Called by the USB subsystem when a frame has been received + * + */ +static void irda_usb_receive(purb_t purb) +{ + struct sk_buff *skb = (struct sk_buff *) purb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct sk_buff *new; + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + ASSERT(self != NULL, return;); + + /* If the network is closed or the device gone, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n"); + /* Don't re-submit the URB : will stall the Rx path */ + return; + } + + /* Check the status */ + if (purb->status != USB_ST_NOERROR) { + switch (purb->status) { + case USB_ST_CRC: /* -EILSEQ */ + self->stats.rx_errors++; + self->stats.rx_crc_errors++; + break; + case -ECONNRESET: + WARNING(__FUNCTION__ "(), Connection Reset !!!\n"); + /* uhci_cleanup_unlink() is going to kill the Rx + * URB just after we return. No problem, at this + * point the URB will be idle ;-) - Jean II */ + break; + default: + WARNING(__FUNCTION__ "(), RX status %d\n", purb->status); + break; + } + goto done; + } + + /* Check for empty frames */ + if (purb->actual_length <= USB_IRDA_HEADER) { + WARNING(__FUNCTION__ "(), empty frame!\n"); + goto done; + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + get_fast_time(&self->stamp); + + /* Fix skb, and remove USB-IrDA header */ + skb_put(skb, purb->actual_length); + skb_pull(skb, USB_IRDA_HEADER); + + /* Don't waste a lot of memory on small IrDA frames */ + if (skb->len < RX_COPY_THRESHOLD) { + new = dev_alloc_skb(skb->len+1); + if (!new) { + self->stats.rx_dropped++; + goto done; + } + + /* Make sure IP header get aligned (IrDA header is 5 bytes) */ + skb_reserve(new, 1); + + /* Copy packet, so we can recycle the original */ + memcpy(skb_put(new, skb->len), skb->data, skb->len); + /* We will cleanup the skb in irda_usb_submit */ + } else { + /* Deliver the original skb */ + new = skb; + skb = NULL; + } + + self->stats.rx_bytes += new->len; + self->stats.rx_packets++; + + /* Ask the networking layer to queue the packet for the IrDA stack */ + new->dev = self->netdev; + new->mac.raw = new->data; + new->protocol = htons(ETH_P_IRDA); + netif_rx(new); +done: + /* Recycle Rx URB (and possible the skb as well) */ + irda_usb_submit(self, skb, self->rx_idle_urb); + + /* Recycle Rx URB : Now, the idle URB is the present one */ + self->rx_idle_urb = purb; + purb->context = NULL; + /* Prevent the USB layer playing games with our URBs */ + purb->status = -ENOENT; +} + +static int irda_usb_net_init(struct net_device *dev) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Set up to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function irda_usb_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + * + * Note : don't mess with self->netopen - Jean II + */ +static int irda_usb_net_open(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Can only open the device if it's there */ + if(!self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + return -1; + } + + /* Initialise default speed and xbofs value + * (IrLAP will change that soon) */ + self->speed = -1; + self->xbofs = -1; + self->new_speed = -1; + self->new_xbofs = -1; + + /* To do *before* submitting Rx urbs and starting net Tx queue + * Jean II */ + self->netopen = 1; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + self->irlap = irlap_open(netdev, &self->qos); + ASSERT(self->irlap != NULL, return -1;); + + /* Allow IrLAP to send data to us */ + netif_start_queue(netdev); + + /* Now that we can pass data to IrLAP, allow the USB layer + * to send us some data... */ + for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) + irda_usb_submit(self, NULL, &(self->rx_urb[i])); + /* Note : we submit all the Rx URB except for one - Jean II */ + self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]); + self->rx_idle_urb->context = NULL; + + /* Ready to play !!! */ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Function irda_usb_net_close (self) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int irda_usb_net_close(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Clear this flag *before* unlinking the urbs and *before* + * stopping the network Tx queue - Jean II */ + self->netopen = 0; + + /* Stop network Tx queue */ + netif_stop_queue(netdev); + + /* Deallocate all the Rx path buffers (URBs and skb) */ + for (i = 0; i < IU_MAX_RX_URBS; i++) { + purb_t purb = &(self->rx_urb[i]); + struct sk_buff *skb = (struct sk_buff *) purb->context; + /* Cancel the receive command */ + usb_unlink_urb(purb); + /* The skb is ours, free it */ + if (skb) { + dev_kfree_skb(skb); + purb->context = NULL; + } + } + /* Cancel Tx and speed URB */ + usb_unlink_urb(&self->tx_urb); + usb_unlink_urb(&self->speed_urb); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void irda_usb_net_timeout(struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + int done = 0; /* If we have made any progress */ + purb_t purb; + + IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n"); + + if (!self || !self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + netif_stop_queue(netdev); + return; + } + WARNING("%s: Tx timed out\n", netdev->name); + + /* Check Tx URB */ + purb = &self->tx_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Check speed URB */ + purb = &self->speed_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Maybe we need a reset */ + /* if(done == 0) */ +} + +static int irda_usb_is_receiving(struct irda_usb_cb *self) +{ + return 0; /* For now */ +} + +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct irda_usb_cb *self; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + self = dev->priv; + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Check if the device is still there */ + if (!self->present) + return -EFAULT; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* Set the desired speed */ + self->new_speed = irq->ifr_baudrate; + irda_usb_change_speed_xbofs(self); + /* Note : will spinlock in above function */ + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = irda_usb_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) +{ + struct irda_usb_cb *self = dev->priv; + return &self->stats; +} + +int __init usb_irda_init(void) +{ + if (usb_register(&irda_driver) < 0) + return -1; + + MESSAGE("USB IrDA support registered\n"); + return 0; +} +module_init(usb_irda_init); + +void __exit usb_irda_cleanup(void) +{ + struct irda_usb_cb *irda = NULL; + int i; + + /* Find zombie instances and kill them... */ + for (i = 0; i < NIRUSB; i++) { + irda = &irda_instance[i]; + /* If the Device is zombie */ + if((irda->usbdev != NULL) && (irda->present == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} +module_exit(usb_irda_cleanup); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); +MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); + + + diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.4.4/linux/drivers/net/irda/nsc-ircc.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/irda/nsc-ircc.c Tue May 1 16:05:00 2001 @@ -251,9 +251,14 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); + MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, + info->cfg_base); + if ((nsc_ircc_setup(info)) == -1) return -1; + MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); + /* Allocate new instance of the driver */ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { @@ -315,8 +320,8 @@ self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL|GFP_DMA); if (self->tx_buff.head == NULL) { - kfree(self); kfree(self->rx_buff.head); + kfree(self); return -ENOMEM; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); @@ -699,8 +704,6 @@ ERROR("%s, Wrong chip version %02x\n", driver_name, version); return -1; } - MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, - info->cfg_base); /* Switch to advanced mode */ switch_bank(iobase, BANK2); @@ -729,8 +732,6 @@ outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); - /* Enable receive interrupts */ switch_bank(iobase, BANK0); outb(IER_RXHDL_IE, iobase+IER); @@ -1858,7 +1859,7 @@ if (request_dma(self->io.dma, dev->name)) { WARNING("%s, unable to allocate dma=%d\n", driver_name, self->io.dma); - free_irq(self->io.irq, self); + free_irq(self->io.irq, dev); return -EAGAIN; } @@ -2008,18 +2009,10 @@ static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) { - int iobase; - if (!self->io.suspended) return; - iobase = self->io.fir_base; - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - + nsc_ircc_setup(&self->io); nsc_ircc_net_open(self->netdev); MESSAGE("%s, Waking up\n", driver_name); diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.4.4/linux/drivers/net/irda/toshoboe.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/irda/toshoboe.c Tue May 1 16:05:00 2001 @@ -81,10 +81,18 @@ #include -static char *driver_name = "toshoboe"; +#define PCI_DEVICE_ID_FIR701b 0x0d01 -static struct toshoboe_cb *dev_self[NSELFS + 1] = -{NULL, NULL, NULL, NULL, NULL}; +static struct pci_device_id toshoboe_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701b, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); + +static const char *driver_name = "toshoboe"; + +static struct toshoboe_cb *dev_self[NSELFS + 1]; static int max_baud = 4000000; @@ -191,8 +199,8 @@ outb_p (OBOE_NTR_VAL, OBOE_NTR); outb_p (0xf0, OBOE_REG_D); outb_p (0xff, OBOE_ISR); - outb_p (0x0f, OBOE_REG_1A); - outb_p (0xff, OBOE_REG_1B); + outb_p (0x0f, OBOE_REG_1B); + outb_p (0xff, OBOE_REG_1A); physaddr = virt_to_bus (self->taskfile); @@ -608,18 +616,21 @@ /* Disable interrupts & save flags */ save_flags(flags); cli(); - switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ @@ -628,9 +639,8 @@ default: ret = -EOPNOTSUPP; } - +out: restore_flags(flags); - return ret; } @@ -712,6 +722,9 @@ return -ENOMEM; } + if ((err=pci_enable_device(pci_dev))) + return err; + self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL); if (self == NULL) @@ -898,7 +911,7 @@ /*FIXME: can't sleep here wait one second */ while ((i--) && (self->txpending)) - mdelay (100); + udelay (100); toshoboe_stopchip (self); toshoboe_disablebm (self); @@ -978,6 +991,24 @@ } while (pci_dev); + + if (!found) do + { + pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, + PCI_DEVICE_ID_FIR701b, pci_dev); + if (pci_dev) + { + printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n", + pci_dev->resource[0].start, + pci_dev->irq); + + if (!toshoboe_open (pci_dev)) + found++; + } + + } + while (pci_dev); + if (found) diff -u --recursive --new-file v2.4.4/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.4.4/linux/drivers/net/mace.c Thu Apr 12 12:15:25 2001 +++ linux/drivers/net/mace.c Sun May 20 12:11:38 2001 @@ -5,6 +5,7 @@ * Copyright (C) 1996 Paul Mackerras. */ +#include #include #include #include @@ -21,6 +22,9 @@ #include "mace.h" static struct net_device *mace_devs; +static int port_aaui = -1; + +MODULE_PARM(port_aaui, "i"); #define N_RX_RING 8 #define N_TX_RING 6 @@ -53,6 +57,7 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; + int port_aaui; struct net_device *next_mace; }; @@ -178,6 +183,21 @@ init_timer(&mp->tx_timeout); mp->timeout_active = 0; + if (port_aaui >= 0) + mp->port_aaui = port_aaui; + else { + /* Apple Network Server uses the AAUI port */ + if (machine_is_compatible("AAPL,ShinerESB")) + mp->port_aaui = 1; + else { +#ifdef CONFIG_MACE_AAUI_PORT + mp->port_aaui = 1; +#else + mp->port_aaui = 0; +#endif + } + } + dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; @@ -261,7 +281,10 @@ /* done changing address */ out_8(&mb->iac, 0); - out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO); + if (mp->port_aaui) + out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO); + else + out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO); } static void __mace_set_address(struct net_device *dev, void *addr) diff -u --recursive --new-file v2.4.4/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.4/linux/drivers/net/natsemi.c Fri Apr 20 11:54:23 2001 +++ linux/drivers/net/natsemi.c Sat May 19 18:02:45 2001 @@ -34,9 +34,30 @@ - Clean up PCI enable (davej) Version 1.0.4: - Merge Donald Becker's natsemi.c version 1.07 + Version 1.0.5: + - { fill me in } + Version 1.0.6: + * ethtool support (jgarzik) + * Proper initialization of the card (which sometimes + fails to occur and leaves the card in a non-functional + state). (uzi) + + * Some documented register settings to optimize some + of the 100Mbit autodetection circuitry in rev C cards. (uzi) + + * Polling of the PHY intr for stuff like link state + change and auto- negotiation to finally work properly. (uzi) + + * One-liner removal of a duplicate declaration of + netdev_error(). (uzi) */ +#define DRV_NAME "natsemi" +#define DRV_VERSION "1.07+LK1.0.6" +#define DRV_RELDATE "May 18, 2001" + + /* Updated to recommendations in pci-skeleton v2.03. */ /* Automatically extracted configuration info: @@ -98,8 +119,6 @@ #error You must compile this driver with "-O". #endif -/* Include files, designed to support most kernel versions 2.0.0 and later. */ -#include #include #include #include @@ -114,15 +133,17 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include +#include /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -KERN_INFO "natsemi.c:v1.07 1/9/2001 Written by Donald Becker \n" +KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker \n" KERN_INFO " http://www.scyld.com/network/natsemi.html\n" -KERN_INFO " (unofficial 2.4.x kernel port, version 1.0.5, April 17, 2001 Jeff Garzik, Tjeerd Mulder)\n"; +KERN_INFO " (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE " Jeff Garzik, Tjeerd Mulder)\n"; /* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) @@ -257,9 +278,12 @@ TxRingPtr=0x20, TxConfig=0x24, RxRingPtr=0x30, RxConfig=0x34, ClkRun=0x3C, WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, - BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, - RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, - PCIPM = 0x44, + BootRomAddr=0x50, BootRomData=0x54, SiliconRev=0x58, StatsCtrl=0x5C, + StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, + PCIPM=0x44, PhyStatus=0xC0, MIntrCtrl=0xC4, MIntrStatus=0xC8, + + /* These are from the spec, around page 78... on a separate table. */ + PGSEL=0xCC, PMDCSR=0xE4, TSTDAT=0xFC, DSPCFG=0xF4, SDCFG=0x8C }; /* Bit in ChipCmd. */ @@ -353,10 +377,9 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); -static void netdev_error(struct net_device *dev, int intr_status); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); @@ -468,7 +491,7 @@ dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -582,7 +605,26 @@ long ioaddr = dev->base_addr; int i; - /* Do we need to reset the chip??? */ + /* Reset the chip, just in case. */ + writel(ChipReset, ioaddr + ChipCmd); + + /* On page 78 of the spec, they recommend some settings for "optimum + performance" to be done in sequence. These settings optimize some + of the 100Mbit autodetection circuitry. Also, we only want to do + this for rev C of the chip. + */ + if (readl(ioaddr + SiliconRev) == 0x302) { + writew(0x0001, ioaddr + PGSEL); + writew(0x189C, ioaddr + PMDCSR); + writew(0x0000, ioaddr + TSTDAT); + writew(0x5040, ioaddr + DSPCFG); + writew(0x008C, ioaddr + SDCFG); + } + + /* Enable PHY Specific event based interrupts. Link state change + and Auto-Negotiation Completion are among the affected. + */ + writew(0x0002, ioaddr + MIntrCtrl); i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; @@ -818,14 +860,6 @@ long ioaddr; int boguscnt = max_interrupt_work; -#ifndef final_version /* Can never occur. */ - if (dev == NULL) { - printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " - "device.\n", irq); - return; - } -#endif - ioaddr = dev->base_addr; np = dev->priv; @@ -853,9 +887,7 @@ break; if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) { np->stats.tx_packets++; -#if LINUX_VERSION_CODE > 0x20127 np->stats.tx_bytes += np->tx_skbuff[entry]->len; -#endif } else { /* Various Tx errors */ int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status); if (tx_status & 0x04010000) np->stats.tx_aborted_errors++; @@ -891,18 +923,6 @@ if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, (int)readl(ioaddr + IntrStatus)); - -#ifndef final_version - /* Code that should never be run! Perhaps remove after testing.. */ - { - static int stopit = 10; - if (!netif_running(dev) && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } -#endif } /* This routine is logically part of the interrupt handler, but separated @@ -966,27 +986,12 @@ skb->head, temp); #endif } -#ifndef final_version /* Remove after testing. */ - /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " - "%d.%d.%d.%d.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13], - skb->data[14], skb->data[15], skb->data[16], - skb->data[17]); -#endif skb->protocol = eth_type_trans(skb, dev); /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */ netif_rx(skb); dev->last_rx = jiffies; np->stats.rx_packets++; -#if LINUX_VERSION_CODE > 0x20127 np->stats.rx_bytes += pkt_len; -#endif } entry = (++np->cur_rx) % RX_RING_SIZE; np->rx_head_desc = &np->rx_ring[entry]; @@ -1023,6 +1028,8 @@ printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" " %4.4x partner %4.4x.\n", dev->name, (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94)); + /* read MII int status to clear the flag */ + readw(ioaddr + MIntrStatus); check_duplex(dev); } if (intr_status & StatsMax) { @@ -1124,12 +1131,38 @@ np->cur_rx_mode = rx_mode; } -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct netdev_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pci_dev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = 1; /* Fall Through */ @@ -1209,9 +1242,6 @@ np->rx_ring[i].cmd_status = 0; np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - np->rx_skbuff[i]->free = 1; -#endif dev_kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; @@ -1243,7 +1273,7 @@ } static struct pci_driver natsemi_driver = { - name: "natsemi", + name: DRV_NAME, id_table: natsemi_pci_tbl, probe: natsemi_probe1, remove: natsemi_remove1, diff -u --recursive --new-file v2.4.4/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.4/linux/drivers/net/net_init.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/net/net_init.c Wed May 16 10:25:39 2001 @@ -205,11 +205,12 @@ } /** - * alloc_etherdev - Register ethernet device + * alloc_etherdev - Allocates and sets up an ethernet device * @sizeof_priv: Size of additional driver-private structure to be allocated * for this ethernet device * - * Fill in the fields of the device structure with ethernet-generic values. + * Fill in the fields of the device structure with ethernet-generic + * values. Basically does everything except registering the device. * * Constructs a new net device, complete with a private data area of * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.4.4/linux/drivers/net/pcmcia/Config.in Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pcmcia/Config.in Mon May 7 19:42:14 2001 @@ -26,7 +26,6 @@ bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA - dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.4.4/linux/drivers/net/pcmcia/Makefile Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pcmcia/Makefile Mon May 7 19:42:14 2001 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := ray_cs.o hermes.o +export-objs := ray_cs.o # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o @@ -25,7 +25,6 @@ obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o hermes.o obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c --- v2.4.4/linux/drivers/net/pcmcia/hermes.c Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/hermes.c Wed Dec 31 16:00:00 1969 @@ -1,502 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * This file distributed under the GPL, version 2. - */ - -static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ -#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ -#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -/* - * Debugging helpers - */ - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#include - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ - printk(#stuff);} while (0) - -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -/* - * Prototypes - */ - -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); - -/* - * Internal inline functions - */ - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) -{ - uint16_t reg; -/* unsigned long k = CMD_BUSY_TIMEOUT; */ - - /* First check that the command register is not busy */ - reg = hermes_read_regn(hw, CMD); - if (reg & HERMES_CMD_BUSY) { - return -EBUSY; - } - - hermes_write_regn(hw, PARAM2, 0); - hermes_write_regn(hw, PARAM1, 0); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -void hermes_struct_init(hermes_t *hw, ushort io) -{ - hw->iobase = io; - hw->inten = 0x0; -} - -int hermes_reset(hermes_t *hw) -{ - uint16_t status, reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Because we hope we can reset the card even if it gets into - a stupid state, we actually wait to see if the command - register will unbusy itself */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been removed, - so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - hermes_issue_cmd() will - probably return -EBUSY */ - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (! hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = status & HERMES_STATUS_RESULT; - - out: - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) -{ - int err; - int k; - uint16_t reg; - - err = hermes_issue_cmd(hw, cmd, parm0); - if (err) { - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", - hw->iobase); - err = -ENODEV; - } else - printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", - hw->iobase); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", - hw->iobase); - err = -ETIMEDOUT; - goto out; - } - - resp->status = hermes_read_regn(hw, STATUS); - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = resp->status & HERMES_STATUS_RESULT; - - out: - return err; -} - -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) -{ - int err = 0; - hermes_response_t resp; - int k; - uint16_t reg; - - if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); - if (err) { - printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", - hw->iobase, err); - return err; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (! (reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: < 0 on internal failure (errno), 0 on success, >0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - int l = BAP_ERROR_RETRY; - uint16_t reg; - - /* Paranoia.. */ - if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) - return -EINVAL; - - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - - if (reg & HERMES_OFFSET_BUSY) - return -EBUSY; - - /* Now we actually set up the transfer */ - retry: - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* For some reason, seeking the BAP seems to randomly fail somewhere - (firmware bug?). We retry a few times before giving up. */ - if (reg & HERMES_OFFSET_ERR) { - if (l--) { - udelay(1); - goto retry; - } else - return -EIO; - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - uint16_t rlength, rtype; - hermes_response_t resp; - int count; - - if (buflen % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); - if (err) - goto out; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - rlength = hermes_read_reg(hw, dreg); - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " - "not match type (0x%04x)\n", rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) - printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); - - /* For now we always read the whole buffer, the - lengths in the records seem to be wrong, frequently */ - count = buflen / 2; - -#if 0 - if (length) - count = (MIN(buflen, rlength) + 1) / 2; - else { - count = buflen / 2; - if (rlength != buflen) - printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ -record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); - } -#endif - hermes_read_data(hw, dreg, buf, count); - - out: - return err; -} - -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - hermes_response_t resp; - int count; - - DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", - bap, rid, length, * ((uint16_t *)value)); - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_data(hw, dreg, value, count); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, &resp); - - out: - return err; -} - -EXPORT_SYMBOL(hermes_struct_init); -EXPORT_SYMBOL(hermes_reset); -EXPORT_SYMBOL(hermes_docmd_wait); -EXPORT_SYMBOL(hermes_allocate); - -EXPORT_SYMBOL(hermes_bap_pread); -EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_read_ltv); -EXPORT_SYMBOL(hermes_write_ltv); - -static int __init init_hermes(void) -{ - printk(KERN_INFO "%s\n", version); - - return 0; -} - -module_init(init_hermes); diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h --- v2.4.4/linux/drivers/net/pcmcia/hermes.h Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/hermes.h Wed Dec 31 16:00:00 1969 @@ -1,402 +0,0 @@ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * This file distributed under the GPL, version 2. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes_t structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_FRAME_LEN_MAX (2304) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET refister bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands --------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands --------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) -#define HERMES_CMD_CLRPRST (0x0012) - -/*--- Regulate Commands --------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQ (0x0011) - -/*--- Configure Commands --------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_MONITOR (0x0038) -#define HERMES_MONITOR_ENABLE (0x000b) -#define HERMES_MONITOR_DISABLE (0x000f) - -/* - * Configuration RIDs - */ - -#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_PRISM2_WEP_ON (0xfc28) -#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_PRISM2_TX_KEY (0xfc23) -#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) -#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) -#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) -#define HERMES_RID_CNF_PRISM2_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_PRIMARY_VER (0xfd03) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) -#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) - -/* - * Frame structures and constants - */ - -typedef struct hermes_frame_desc { - /* Hermes - i.e. little-endian byte-order */ - uint16_t status; /* 0x0 */ - uint16_t res1, res2; /* 0x2, 0x4 */ - uint16_t q_info; /* 0x6 */ - uint16_t res3, res4; /* 0x8, 0xA */ - uint16_t tx_ctl; /* 0xC */ -} __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) - -#ifdef __KERNEL__ - -/* Basic control structure */ -typedef struct hermes { - uint iobase; - - uint16_t inten; /* Which interrupts should be enabled? */ -} hermes_t; - -typedef struct hermes_response { - uint16_t status, resp0, resp1, resp2; -} hermes_response_t; - -/* Firmware information structure */ -typedef struct hermes_identity { - uint16_t id, vendor, major, minor; -} __attribute__ ((packed)) hermes_identity_t; - -/* "ID" structure - used for ESSID and station nickname */ -typedef struct hermes_id { - uint16_t len; - uint16_t val[16]; -} __attribute__ ((packed)) hermes_id_t; - -typedef struct hermes_commsqual { - uint16_t qual, signal, noise; -} __attribute__ ((packed)) hermes_commsqual_t; - -typedef struct hermes_multicast { - uint8_t 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))) - -#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) -#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) -#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) - -/* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ushort io); -int hermes_reset(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); - - -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf); -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value); - -/* Inline functions */ - -static inline int hermes_present(hermes_t *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) -{ - hw->inten |= events; - hermes_write_regn(hw, INTEN, hw->inten); -} - -static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -static inline int hermes_disable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) -#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) - -static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) -{ - uint16_t rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) -{ - uint16_t rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->id); - le16_to_cpus(&buf->vendor); - le16_to_cpus(&buf->major); - le16_to_cpus(&buf->minor); - - return 0; -} - -static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->qual); - le16_to_cpus(&buf->signal); - le16_to_cpus(&buf->noise); - - return 0; -} - -#else /* ! __KERNEL__ */ - -/* These are provided for the benefit of userspace drivers and testing programs - which use ioperm() or iopl() */ - -#define hermes_read_reg(base, off) (inw((base) + (off))) -#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) - -#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) -#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) -#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) - -#endif /* ! __KERNEL__ */ - -#endif /* _HERMES_H */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c --- v2.4.4/linux/drivers/net/pcmcia/orinoco_cs.c Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/orinoco_cs.c Wed Dec 31 16:00:00 1969 @@ -1,4327 +0,0 @@ -/* orinoco_cs.c 0.04 - (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/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright (C) 2000 David Gibson, Linuxcare Australia - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds 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 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 by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -/* 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()). - * - * The kernel's IRQ handling stuff ensures that the interrupt handler - * does not re-enter itself. The interrupt handler is written such - * that everything it does is safe without a lock: chiefly this means - * that the Rx path uses one of the Hermes chipset's BAPs while - * everything else uses the other. - * - * For the moment access to the device statistics from the interrupt - * handler is unsafe - we just put up with any resulting errors in the - * statisics. FIXME: This should probably be changed to store the - * stats in atomic types. - * - * EXCEPT that we don't want the irq handler running when we actually - * reset or shut down the card, because strange things might happen - * (probably the worst would be one packet of garbage, but you can't - * be too careful). For this we use __dldwd_stop_irqs() which will set - * a flag to disable the interrupt handler, and wait for any - * outstanding instances of the handler to complete. THIS WILL LOSE - * INTERRUPTS! so it shouldn't be used except for resets, when we - * don't care about that.*/ - -/* - * Tentative changelog... - * - * v0.01 -> v0.02 - 21/3/2001 - Jean II - * o Allow to use regular ethX device name instead of dldwdX - * o Warning on IBSS with ESSID=any for firmware 6.06 - * o Put proper range.throughput values (optimistic) - * o IWSPY support (IOCTL and stat gather in Rx path) - * o Allow setting frequency in Ad-Hoc mode - * o Disable WEP setting if !has_wep to work on old firmware - * o Fix txpower range - * o Start adding support for Samsung/Compaq firmware - * - * v0.02 -> v0.03 - 23/3/2001 - Jean II - * o Start adding Symbol support - need to check all that - * o Fix Prism2/Symbol WEP to accept 128 bits keys - * o Add Symbol WEP (add authentication type) - * o Add Prism2/Symbol rate - * o Add PM timeout (holdover duration) - * o Enable "iwconfig eth0 key off" and friends (toggle flags) - * o Enable "iwconfig eth0 power unicast/all" (toggle flags) - * o Try with an intel card. It report firmware 1.01, behave like - * an antiquated firmware, however on windows it says 2.00. Yuck ! - * o Workaround firmware bug in allocate buffer (Intel 1.01) - * o Finish external renaming to orinoco... - * o Testing with various Wavelan firmwares - * - * v0.03 -> v0.04 - 30/3/2001 - Jean II - * o Update to Wireless 11 -> add retry limit/lifetime support - * o Tested with a D-Link DWL 650 card, fill in firmware support - * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) - * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( - * It work on D-Link *only* after a tcpdump. Weird... - * And still doesn't work on Intel card. Grrrr... - * o Update the mode after a setport3 - * o Add preamble setting for Symbol cards (not yet enabled) - * o Don't complain as much about Symbol cards... - * - * v0.04 -> v0.04b - 22/4/2001 - David Gibson - * o Removed the 'eth' parameter - always use ethXX as the - * interface name instead of dldwdXX. The other was racy - * anyway. - * o Clean up RID definitions in hermes.h, other cleanups - * - * v0.04b -> v0.04c - 24/4/2001 - Jean II - * o Tim Hurley reported a D-Link card - * with vendor 02 and firmware 0.08. Added in the capabilities... - * o Tested Lucent firmware 7.28, everything works... - * - * TODO - Jean II - * o inline functions (lot's of candidate, need to reorder code) - * o Separate Pcmcia specific code to help Airport/Mini PCI driver - * o Test PrismII/Symbol cards & firmware versions - */ - -#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 "hermes.h" - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -static char *version = "orinoco_cs.c 0.04 (David Gibson )"; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#define DEBUGMORE(n, args...) do { } while (0) -#endif - -#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); -#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) - - -#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco_cs requires Wireless extensions v10 or later." -#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ -#define WIRELESS_SPY // enable iwspy support - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* The old way: bit map of interrupts to choose from */ -/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ -static uint irq_mask = 0xdeb8; -/* Newer, simpler way of listing specific interrupts */ -static int irq_list[4] = { -1 }; -/* Do a Pcmcia soft reset (may help some cards) */ -static int reset_cor = 0; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(reset_cor, "i"); - -/*====================================================================*/ - -#define DLDWD_MIN_MTU 256 -#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) - -#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 Intel 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 - -const long channel_frequency[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; - -#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])) -typedef struct dldwd_key { - uint16_t len; - char data[MAX_KEY_SIZE]; -} __attribute__ ((packed)) dldwd_key_t; - -typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; - -typedef struct dldwd_priv { - dev_link_t link; - dev_node_t node; - int instance; - - spinlock_t lock; - long state; -#define DLDWD_STATE_INIRQ 0 -#define DLDWD_STATE_DOIRQ 1 - - /* 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; - - /* Capabilities of the hardware/firmware */ - hermes_identity_t firmware_info; - int firmware_type; -#define FIRMWARE_TYPE_LUCENT 1 -#define FIRMWARE_TYPE_PRISM2 2 -#define FIRMWARE_TYPE_SYMBOL 3 - int has_ibss, has_port3, prefer_port3, has_ibss_any; - int has_wep, has_big_wep; - int has_mwo; - int has_pm; - int has_retry; - int has_preamble; - int broken_reset, broken_allocate; - uint16_t channel_mask; - - /* Current configuration */ - uint32_t iw_mode; - int port_type, allow_ibss; - uint16_t wep_on, wep_restrict, tx_key; - dldwd_keys_t keys; - 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 retry_short, retry_long, retry_time; - uint16_t preamble; - - int promiscuous, allmulti, mc_count; - -#ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; -#endif - - /* /proc based debugging stuff */ - struct proc_dir_entry *dir_dev; - struct proc_dir_entry *dir_regs; - struct proc_dir_entry *dir_recs; -} dldwd_priv_t; - -struct p80211_hdr { - uint16_t frame_ctl; - uint16_t duration_id; - uint8_t addr1[ETH_ALEN]; - uint8_t addr2[ETH_ALEN]; - uint8_t addr3[ETH_ALEN]; - uint16_t seq_ctl; - uint8_t addr4[ETH_ALEN]; - uint16_t data_len; -} __attribute__ ((packed)); - -/* 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 - -struct p8022_hdr { - uint8_t dsap; - uint8_t ssap; - uint8_t ctrl; - uint8_t oui[3]; -} __attribute__ ((packed)); - -struct dldwd_frame_hdr { - hermes_frame_desc_t desc; - struct p80211_hdr p80211; - struct ethhdr p8023; - struct p8022_hdr p8022; - uint16_t ethertype; -} __attribute__ ((packed)); - -#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ - sizeof(struct p80211_hdr)) -#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) - -/* - * Function prototypes - */ - -/* PCMCIA gumpf */ - -static void dldwd_config(dev_link_t * link); -static void dldwd_release(u_long arg); -static int dldwd_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *dldwd_attach(void); -static void dldwd_detach(dev_link_t *); - -/* Hardware control routines */ - -static int __dldwd_hw_reset(dldwd_priv_t *priv); -static void dldwd_shutdown(dldwd_priv_t *dev); -static int dldwd_reset(dldwd_priv_t *dev); -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, - int32_t *rates, int max); - -/* Interrupt handling routines */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); -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); - -/* struct net_device methods */ -static int dldwd_init(struct net_device *dev); -static int dldwd_open(struct net_device *dev); -static int dldwd_stop(struct net_device *dev); - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); -static void dldwd_tx_timeout(struct net_device *dev); - -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 void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr); - -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 int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu); -static void __dldwd_set_multicast_list(struct net_device *dev); - -/* /proc debugging stuff */ -static int dldwd_proc_init(void); -static void dldwd_proc_cleanup(void); -static int dldwd_proc_dev_init(dldwd_priv_t *dev); -static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev); - -/* - * Inline functions - */ -static inline void -dldwd_lock(dldwd_priv_t *priv) -{ - spin_lock_bh(&priv->lock); -} - -static inline void -dldwd_unlock(dldwd_priv_t *priv) -{ - spin_unlock_bh(&priv->lock); -} - -static inline int -dldwd_irqs_allowed(dldwd_priv_t *priv) -{ - return test_bit(DLDWD_STATE_DOIRQ, &priv->state); -} - -static inline void -__dldwd_stop_irqs(dldwd_priv_t *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)) - ; -} - -static inline void -__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) -{ - hermes_t *hw = &priv->hw; - - TRACE_ENTER(priv->ndev.name); - - __cli(); - set_bit(DLDWD_STATE_DOIRQ, &priv->state); - hermes_set_irqmask(hw, irqmask); - __sti(); - - TRACE_EXIT(priv->ndev.name); -} - -static inline void -set_port_type(dldwd_priv_t *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->allow_ibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->allow_ibss = 0; - } else { - priv->port_type = 1; - priv->allow_ibss = 1; - } - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev.name); - } -} - -static inline void -dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - - dldwd_lock(priv); - __dldwd_set_multicast_list(dev); - dldwd_unlock(priv); -} - -/* - * Hardware control routines - */ - -static int -__dldwd_hw_reset(dldwd_priv_t *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; - } -} - -static void -dldwd_shutdown(dldwd_priv_t *priv) -{ -/* hermes_t *hw = &priv->hw; */ - int err = 0; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - __dldwd_stop_irqs(priv); - - err = __dldwd_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); - - TRACE_EXIT(priv->ndev.name); -} - -static int -dldwd_reset(dldwd_priv_t *priv) -{ - struct net_device *dev = &priv->ndev; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t idbuf; - int frame_size; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - - __dldwd_stop_irqs(priv); - - err = __dldwd_hw_reset(priv); - if (err) - goto out; - - frame_size = TX_NICBUF_SIZE; - /* This stupid bug is present in Intel firmware 1.10, and - * may be fixed in later firmwares - Jean II */ - if(priv->broken_allocate) - frame_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, frame_size, &priv->txfid); - if (err) - goto out; - - /* Now set up all the parameters on the card */ - - /* Set up the link mode */ - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); - if (err) - goto out; - if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, - priv->allow_ibss); - if (err) - goto out; - if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) - && (!priv->has_ibss_any)) { - printk(KERN_WARNING "%s: This firmware requires an \ -ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - } - } - - /* Set up encryption */ - if (priv->has_wep) { - err = __dldwd_hw_setup_wep(priv); - if (err) - goto out; - } - - /* Set the desired ESSID */ - 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_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) - goto out; - - /* 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, - 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); - if (err) - goto out; - - /* Set AP density */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, 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); - 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); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_FRAG_THRESH, 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); - if (err) - goto out; - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, - priv->pm_on); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, - priv->pm_mcast); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - priv->pm_period); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, - priv->pm_timeout); - if (err) - goto out; - } - - /* Set retry settings - will fail on lot's of firmwares */ - if (priv->has_retry) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, - priv->retry_short); - if (err) { - printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name); - goto out; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, - priv->retry_long); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, - priv->retry_time); - if (err) - goto out; - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, - priv->preamble); - if (err) { - printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); - goto out; - } - } - - /* 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; - - __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | - HERMES_EV_TX | HERMES_EV_TXEXC | - HERMES_EV_WTERR | HERMES_EV_INFO | - HERMES_EV_INFDROP); - - out: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - int extra_wep_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); - if (err) - return err; - break; - - case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->wep_on) { - char keybuf[LARGE_KEY_SIZE+1]; - int keylen; - int i; - - /* Write all 4 keys */ - for(i = 0; i < MAX_KEYS; i++) { - keylen = priv->keys[i].len; - keybuf[keylen] = '\0'; - memcpy(keybuf, priv->keys[i].data, keylen); - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNF_PRISM2_KEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen + 1), - &keybuf); - if (err) - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, - priv->tx_key); - if (err) - return err; - - /* Authentication is where Prism2 and Symbol - * firmware differ... */ - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { - /* Symbol cards : set the authentication : - * 0 -> no encryption, 1 -> open, - * 2 -> shared key, 3 -> shared key 128bit */ - if(priv->wep_restrict) { - if(priv->keys[priv->tx_key].len > - SMALL_KEY_SIZE) - extra_wep_flag = 3; - else - extra_wep_flag = 2; - } else - extra_wep_flag = 1; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); - if (err) - return err; - } else { - /* Prism2 card : we need to modify master - * WEP setting */ - if(priv->wep_restrict) - extra_wep_flag = 2; - else - extra_wep_flag = 0; - } - } - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); - if (err) - return err; - break; - - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev.name); - return -EINVAL; - } - } - - return 0; -} - -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - dldwd_lock(priv); - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, - ETH_ALEN, NULL, buf); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - - TRACE_ENTER(priv->ndev.name); - - dldwd_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 - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - uint16_t rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : - HERMES_RID_CNF_DESIRED_SSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - - memset(buf, 0, sizeof(buf)); - memcpy(buf, p, len); - buf[len] = '\0'; - - fail_unlock: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static long dldwd_hw_get_freq(dldwd_priv_t *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t channel; - long freq = 0; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); - if (err) - goto out; - - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - struct net_device *dev = &priv->ndev; - - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); - err = -EBUSY; - goto out; - - } - freq = channel_frequency[channel-1] * 100000; - - out: - dldwd_unlock(priv); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - int32_t *rates, int max) -{ - hermes_t *hw = &priv->hw; - hermes_id_t 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); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = MIN(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; -} - -#ifndef PCMCIA_DEBUG -static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} -#else -static void show_rx_frame(struct dldwd_frame_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 "IEEE 802.11 header:\n"); - printk(KERN_DEBUG " frame_ctl = 0x%04x\n", - frame->p80211.frame_ctl); - printk(KERN_DEBUG " duration_id = 0x%04x\n", - frame->p80211.duration_id); - printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr1[0], frame->p80211.addr1[1], - frame->p80211.addr1[2], frame->p80211.addr1[3], - frame->p80211.addr1[4], frame->p80211.addr1[5]); - printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr2[0], frame->p80211.addr2[1], - frame->p80211.addr2[2], frame->p80211.addr2[3], - frame->p80211.addr2[4], frame->p80211.addr2[5]); - printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr3[0], frame->p80211.addr3[1], - frame->p80211.addr3[2], frame->p80211.addr3[3], - frame->p80211.addr3[4], frame->p80211.addr3[5]); - printk(KERN_DEBUG " seq_ctl = 0x%04x\n", - frame->p80211.seq_ctl); - printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr4[0], frame->p80211.addr4[1], - frame->p80211.addr4[2], frame->p80211.addr4[3], - frame->p80211.addr4[4], frame->p80211.addr4[5]); - printk(KERN_DEBUG " data_len = 0x%04x\n", - frame->p80211.data_len); - - printk(KERN_DEBUG "IEEE 802.3 header:\n"); - printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_dest[0], frame->p8023.h_dest[1], - frame->p8023.h_dest[2], frame->p8023.h_dest[3], - frame->p8023.h_dest[4], frame->p8023.h_dest[5]); - printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_source[0], frame->p8023.h_source[1], - frame->p8023.h_source[2], frame->p8023.h_source[3], - frame->p8023.h_source[4], frame->p8023.h_source[5]); - printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); - - printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); - printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); - printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); - printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); - printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", - frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); - printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); -} -#endif - -/* - * Interrupt handler - */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) -{ - dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; - hermes_t *hw = &priv->hw; - struct net_device *dev = &priv->ndev; - int count = IRQ_LOOP_MAX; - uint16_t evstat, events; - static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ - - if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) - BUG(); - - if (! dldwd_irqs_allowed(priv)) { - clear_bit(DLDWD_STATE_INIRQ, &priv->state); - return; - } - - DEBUG(3, "%s: dldwd_interrupt() irq %d\n", priv->ndev.name, irq); - - while (1) { - if (jiffies != old_time) - timecount = 0; - if ( (++timecount > 50) || (! count--) ) { - 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); - 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"); - break; - } - - if (events & HERMES_EV_TICK) - __dldwd_ev_tick(priv, hw); - if (events & HERMES_EV_WTERR) - __dldwd_ev_wterr(priv, hw); - if (events & HERMES_EV_INFDROP) - __dldwd_ev_infdrop(priv, hw); - if (events & HERMES_EV_INFO) - __dldwd_ev_info(priv, hw); - if (events & HERMES_EV_RX) - __dldwd_ev_rx(priv, hw); - if (events & HERMES_EV_TXEXC) - __dldwd_ev_txexc(priv, hw); - if (events & HERMES_EV_TX) - __dldwd_ev_tx(priv, hw); - if (events & HERMES_EV_ALLOC) - __dldwd_ev_alloc(priv, hw); - - hermes_write_regn(hw, EVACK, events); - } - - clear_bit(DLDWD_STATE_INIRQ, &priv->state); -} - -static void __dldwd_ev_tick(dldwd_priv_t *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) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", - priv->ndev.name); -} - -static void __dldwd_ev_infdrop(dldwd_priv_t *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) -{ - 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 */ -} - -static void __dldwd_ev_rx(dldwd_priv_t *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; - uint16_t rxfid, status; - int length, data_len, data_off; - char *p; - struct dldwd_frame_hdr hdr; - struct ethhdr *eh; - int err; - - rxfid = hermes_read_regn(hw, RXFID); - DEBUG(3, "__dldwd_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. */ - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - status = le16_to_cpu(hdr.desc.status); - - if (status & HERMES_RXSTAT_ERR) { - if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { - stats->rx_crc_errors++; - printk(KERN_WARNING "%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++; - printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - } else { - wstats->discard.misc++; - printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", - dev->name, status & HERMES_RXSTAT_ERR); - } - stats->rx_errors++; - goto drop; - } - - length = le16_to_cpu(hdr.p80211.data_len); - /* Yes, you heard right, that's le16. 802.2 and 802.3 are - big-endian, but 802.11 is little-endian believe it or - not. */ - /* Correct. 802.3 is big-endian byte order and little endian bit - * order, whereas 802.11 is little endian for both byte and bit - * order. That's specified in the 802.11 spec. - Jean II */ - - /* Sanity check */ - if (length > MAX_FRAME_SIZE) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - stats->rx_errors++; - goto drop; - } - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - stats->rx_dropped++; - goto drop; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - - /* Handle decapsulation */ - switch (status & HERMES_RXSTAT_MSGTYPE) { - /* These both indicate a SNAP within 802.2 LLC within - 802.3 within 802.11 frame which we'll need to - de-encapsulate. IEEE and ISO OSI have a lot to - answer for. */ - case HERMES_RXSTAT_1042: - case HERMES_RXSTAT_TUNNEL: - data_len = length - ENCAPS_OVERHEAD; - data_off = sizeof(hdr); - - eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); - - memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); - eh->h_proto = hdr.ethertype; - - break; - - /* Otherwise, we just throw the whole thing in, and hope - the protocol layer can deal with it as 802.3 */ - default: - data_len = length; - data_off = P8023_OFFSET; - break; - } - - p = skb_put(skb, data_len); - if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off) != 0) { - printk(KERN_WARNING "%s: Error reading packet data\n", - dev->name); - stats->rx_errors++; - goto drop; - } - - dev->last_rx = jiffies; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - - /* Process the wireless stats if needed */ - dldwd_stat_gather(dev, skb, &hdr); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - if (skb) - dev_kfree_skb_irq(skb); - return; -} - -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - printk(KERN_WARNING "%s: Tx error!\n", dev->name); - - netif_wake_queue(dev); - stats->tx_errors++; -} - -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - DEBUG(3, "%s: Transmit completed\n", dev->name); - - stats->tx_packets++; - netif_wake_queue(dev); -} - -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) -{ - uint16_t allocfid; - - allocfid = hermes_read_regn(hw, ALLOCFID); - DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); - - /* For some reason we don't seem to get transmit completed events properly */ - if (allocfid == priv->txfid) - __dldwd_ev_tx(priv, hw); - -/* hermes_write_regn(hw, ALLOCFID, 0); */ -} - -/* - * struct net_device methods - */ - -static int dldwd_init(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t nickbuf; - uint16_t reclen; - int len; - char *vendor_str; - uint32_t firmver; - - TRACE_ENTER("dldwd"); - - dldwd_lock(priv); - - err = hermes_reset(hw); - if (err != 0) { - printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); - goto out; - } - - /* Get the firmware version */ - err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); - if (err) { - printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", - dev->name, err); - memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); - } - - firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; - DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); - - /* Determine capabilities from the firmware version */ - - switch (priv->firmware_info.vendor) { - case 0x1: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - * ELSA, Melco, HP, IBM, Dell 1150 cards */ - vendor_str = "Lucent"; - /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ - - priv->firmware_type = FIRMWARE_TYPE_LUCENT; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; /* Still works in 7.28 */ - priv->has_ibss = (firmver >= 0x60006); - priv->has_ibss_any = (firmver >= 0x60010); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with Lucent firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case 0x2: - vendor_str = "Generic Prism II"; - /* Some D-Link cards report vendor 0x02... */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - - /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ - - /* Special case for Symbol cards */ - if(firmver == 0x10001) { - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - vendor_str = "Symbol"; - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - - /* FIXME : probably need to use SYMBOL_***ARY_VER - * to get proper firmware version */ - priv->firmware_type = FIRMWARE_TYPE_SYMBOL; - priv->broken_reset = 0; - priv->broken_allocate = 1; - priv->has_port3 = 1; - priv->has_ibss = 1; /* FIXME */ - priv->has_wep = 1; /* FIXME */ - priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ - priv->has_mwo = 0; - priv->has_pm = 1; /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; /* FIXME */ - /* Tested with Intel firmware : v15 => Jean II */ - } - break; - case 0x3: - vendor_str = "Samsung"; - /* To check - Should cover Samsung & Compaq */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = 0; /* FIXME: available in later firmwares */ - priv->has_wep = (firmver >= 0x20000); /* FIXME */ - priv->has_big_wep = 0; /* FIXME */ - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x20000); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - break; - case 0x6: - /* D-Link DWL 650, ... */ - vendor_str = "LinkSys/D-Link"; - /* D-Link MAC : 00:40:05:* */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with D-Link firmware 0.07 => Jean II */ - /* Note : with 0.07, IBSS to a Lucent card seem flaky */ - break; - default: - vendor_str = "UNKNOWN"; - - priv->firmware_type = 0; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 0; - priv->has_ibss = 0; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = 0; - priv->has_retry = 0; - priv->has_preamble = 0; - } - - printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", - dev->name, priv->firmware_info.id, priv->firmware_info.vendor, - vendor_str, priv->firmware_info.major, priv->firmware_info.minor); - - if (priv->has_port3) - printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); - if (priv->has_ibss) - printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", - dev->name); - if (priv->has_wep) { - printk(KERN_INFO "%s: WEP supported, ", dev->name); - if (priv->has_big_wep) - printk("\"128\"-bit key.\n"); - else - printk("40-bit key.\n"); - } - - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name!n", - dev->name); - goto out; - } - if ( nickbuf.len ) - len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); - else - len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_INFO "%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); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &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); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); - goto out; - } - - /* Set initial bitrate control*/ - priv->tx_rate_ctrl = 3; - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - &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, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Retry setup */ - if (priv->has_retry) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time); - if (err) - goto out; - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); - if (err) - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); - set_port_type(priv); - - priv->promiscuous = 0; - priv->allmulti = 0; - priv->wep_on = 0; - priv->tx_key = 0; - - printk(KERN_INFO "%s: ready\n", dev->name); - - out: - dldwd_unlock(priv); - - TRACE_EXIT("dldwd"); - - return err; -} - -static int dldwd_open(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - int err = 0; - - TRACE_ENTER(dev->name); - - link->open++; - MOD_INC_USE_COUNT; - netif_device_attach(dev); - - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - else - netif_start_queue(dev); - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_stop(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - - TRACE_ENTER(dev->name); - - netif_stop_queue(dev); - - dldwd_shutdown(priv); - - link->open--; - - if (link->state & DEV_STALE_CONFIG) - mod_timer(&link->release, jiffies + HZ/20); - - MOD_DEC_USE_COUNT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static struct net_device_stats *dldwd_get_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - - return &priv->stats; -} - -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err = 0; - hermes_commsqual_t cq; - - dldwd_lock(priv); - - if (priv->port_type == 3) { - 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) { - 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 { - err = hermes_read_commsqual(hw, USER_BAP, &cq); - - DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - - /* Why are we using MIN/MAX ? We don't really care - * if the value goes above max, because we export the - * raw dBm values anyway. The normalisation should be done - * in user space - Jean II */ - wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); - wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; - wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; - wstats->qual.updated = 7; - } - - dldwd_unlock(priv); - - if (err) - return NULL; - - return wstats; -} - -#ifdef WIRELESS_SPY -static inline void dldwd_spy_gather(struct net_device *dev, - u_char *mac, - hermes_commsqual_t *cq) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); - priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].updated = 7; - } -} -#endif /* WIRELESS_SPY */ - -static void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_commsqual_t cq; - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ -#ifdef WIRELESS_EXT - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if ( -#ifdef WIRELESS_SPY - (priv->spy_number > 0) || -#endif - 0 ) - { - u_char *stats = (u_char *) &(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 */ - cq.signal = stats[1]; /* High order byte */ - cq.noise = stats[0]; /* Low order byte */ - cq.qual = stats[0] - stats[1]; /* Better than nothing */ - - DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - -#ifdef WIRELESS_SPY - dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); -#endif - } -#endif /* WIRELESS_EXT */ -} - -struct p8022_hdr encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t txfid = priv->txfid; - char *p; - struct ethhdr *eh; - int len, data_len, data_off; - struct dldwd_frame_hdr hdr; - hermes_response_t resp; - - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return 1; - - } - - if (netif_queue_stopped(dev)) { - printk(KERN_ERR "%s: Tx while transmitter busy!\n", - dev->name); - return 1; - } - - dldwd_lock(priv); - - /* Length of the packet body */ - len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); - - eh = (struct ethhdr *)skb->data; - - /* Build the IEEE 802.11 header */ - 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; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ - data_len = len; - data_off = sizeof(hdr); - p = skb->data + ETH_HLEN; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); - - /* 802.3 header */ - memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); - memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); - hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); - - /* 802.2 header */ - 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) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } else { /* IEEE 802.3 frame */ - data_len = len + ETH_HLEN; - data_off = P8023_OFFSET; - p = skb->data; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(len); - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, - txfid, 0); - if (err) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } - - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - - - /* Finally, we actually initiate the send */ - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); - if (err) { - printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - stats->tx_errors++; - goto fail; - } - - dev->trans_start = jiffies; - stats->tx_bytes += data_off + data_len; - - netif_stop_queue(dev); - - dldwd_unlock(priv); - - dev_kfree_skb(skb); - - return 0; - fail: - - dldwd_unlock(priv); - return err; -} - -static void dldwd_tx_timeout(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - int err = 0; - - printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); - - stats->tx_errors++; - - err = dldwd_reset(priv); - if (err) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, err); - else { - dev->trans_start = jiffies; - netif_wake_queue(dev); - } -} - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int ptype; - struct iw_range range; - int numrates; - int i, k; - - TRACE_ENTER(dev->name); - - err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); - if (err) - return err; - - rrq->length = sizeof(range); - - dldwd_lock(priv); - ptype = priv->port_type; - dldwd_unlock(priv); - - memset(&range, 0, sizeof(range)); - - /* Much of this shamelessly taken from wvlan_cs.c. No idea - * what it all means -dgibson */ -#if WIRELESS_EXT > 10 - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 11; -#endif /* WIRELESS_EXT > 10 */ - - range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ - - /* Set available channels/frequencies */ - range.num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range.freq[k].i = i + 1; - range.freq[k].m = channel_frequency[i] * 100000; - range.freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range.num_frequency = k; - - range.sensitivity = 3; - - if ((ptype == 3) && (priv->spy_number == 0)){ - /* Quality stats meaningless in ad-hoc mode */ - range.max_qual.qual = 0; - range.max_qual.level = 0; - range.max_qual.noise = 0; - } else { - range.max_qual.qual = 0x8b - 0x2f; - range.max_qual.level = 0x2f - 0x95 - 1; - range.max_qual.noise = 0x2f - 0x95 - 1; - } - - err = dldwd_hw_get_bitratelist(priv, &numrates, - range.bitrate, IW_MAX_BITRATES); - if (err) - return err; - range.num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if(numrates > 2) - range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range.min_rts = 0; - range.max_rts = 2347; - range.min_frag = 256; - range.max_frag = 2346; - - dldwd_lock(priv); - if (priv->has_wep) { - range.max_encoding_tokens = MAX_KEYS; - - range.encoding_size[0] = SMALL_KEY_SIZE; - range.num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range.encoding_size[1] = LARGE_KEY_SIZE; - range.num_encoding_sizes = 2; - } - } else { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } - dldwd_unlock(priv); - - range.min_pmp = 0; - range.max_pmp = 65535000; - range.min_pmt = 0; - range.max_pmt = 65535 * 1000; /* ??? */ - range.pmp_flags = IW_POWER_PERIOD; - range.pmt_flags = IW_POWER_TIMEOUT; - range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; - - range.num_txpower = 1; - range.txpower[0] = 15; /* 15dBm */ - range.txpower_capa = IW_TXPOW_DBM; - -#if WIRELESS_EXT > 10 - range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range.retry_flags = IW_RETRY_LIMIT; - range.r_time_flags = IW_RETRY_LIFETIME; - range.min_retry = 0; - range.max_retry = 65535; /* ??? */ - range.min_r_time = 0; - range.max_r_time = 65535 * 1000; /* ??? */ -#endif /* WIRELESS_EXT > 10 */ - - if (copy_to_user(rrq->pointer, &range, sizeof(range))) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *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; - uint16_t xlen = 0; - int err = 0; - char keybuf[MAX_KEY_SIZE]; - - if (erq->pointer) { - /* We actually have a key to set */ - - if (copy_from_user(keybuf, erq->pointer, erq->length)) - return -EFAULT; - } - - dldwd_lock(priv); - - if (erq->pointer) { - if (erq->length > MAX_KEY_SIZE) { - err = -E2BIG; - goto out; - } - - if ( (erq->length > LARGE_KEY_SIZE) - || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { - err = -EINVAL; - goto out; - } - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - if (erq->length > SMALL_KEY_SIZE) { - xlen = LARGE_KEY_SIZE; - } else if (erq->length > 0) { - xlen = SMALL_KEY_SIZE; - } else - xlen = 0; - - /* Switch on WEP if off */ - if ((!enable) && (xlen > 0)) { - setindex = index; - enable = 1; - } - } else { - /* 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 != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if(priv->keys[index].len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - enable = 0; - /* Only for Prism2 & Symbol cards (so far) - Jean II */ - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); - } - priv->tx_key = setindex; - priv->wep_on = enable; - priv->wep_restrict = restricted; - - out: - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - uint16_t xlen = 0; - char keybuf[MAX_KEY_SIZE]; - - - dldwd_lock(priv); - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (! priv->wep_on) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { - if(priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - } - - xlen = le16_to_cpu(priv->keys[index].len); - - erq->length = xlen; - - if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); - } - - dldwd_unlock(priv); - - if (erq->pointer) { - if (copy_to_user(erq->pointer, keybuf, xlen)) - return -EFAULT; - } - - return 0; -} - -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - char essidbuf[IW_ESSID_MAX_SIZE+1]; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - memset(&essidbuf, 0, sizeof(essidbuf)); - - if (erq->flags) { - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (copy_from_user(&essidbuf, erq->pointer, erq->length)) - return -EFAULT; - - essidbuf[erq->length] = '\0'; - } - - dldwd_lock(priv); - - memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *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); - if (err) - return err; - - erq->flags = 1; - erq->length = strlen(essidbuf) + 1; - if (erq->pointer) - if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - memset(nickbuf, 0, sizeof(nickbuf)); - - if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) - return -EFAULT; - - nickbuf[nrq->length] = '\0'; - - dldwd_lock(priv); - - memcpy(priv->nick, nickbuf, sizeof(priv->nick)); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - dldwd_lock(priv); - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); - dldwd_unlock(priv); - - nrq->length = strlen(nickbuf)+1; - - if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) -{ - dldwd_priv_t *priv = dev->priv; - int chan = -1; - - /* We can only use this in Ad-Hoc demo mode to set the operating - * frequency, or in IBSS mode to set the frequency where the IBSS - * will be created - Jean II */ - if (priv->iw_mode != IW_MODE_ADHOC) - return -EOPNOTSUPP; - - if ( (frq->e == 0) && (frq->m <= 1000) ) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency - search the table */ - int mult = 1; - int i; - - for (i = 0; i < (6 - frq->e); i++) - mult *= 10; - - for (i = 0; i < NUM_CHANNELS; i++) - if (frq->m == (channel_frequency[i] * mult)) - chan = i+1; - } - - if ( (chan < 1) || (chan > NUM_CHANNELS) || - ! (priv->channel_mask & (1 << (chan-1)) ) ) - return -EINVAL; - - dldwd_lock(priv); - priv->channel = chan; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - uint16_t val; - int err; - - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); - dldwd_unlock(priv); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - int val = srq->value; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - dldwd_lock(priv); - priv->ap_density = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = rrq->value; - - if (rrq->disabled) - val = 2347; - - if ( (val < 0) || (val > 2347) ) - return -EINVAL; - - dldwd_lock(priv); - priv->rts_thresh = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - dldwd_lock(priv); - - if (priv->has_mwo) { - if (frq->disabled) - priv->mwo_robust = 0; - else { - if (frq->fixed) - printk(KERN_WARNING "%s: Fixed fragmentation not \ -supported on this firmware. Using MWO robust instead.\n", dev->name); - priv->mwo_robust = 1; - } - } else { - if (frq->disabled) - priv->frag_thresh = 2346; - else { - if ( (frq->value < 256) || (frq->value > 2346) ) - err = -EINVAL; - else - priv->frag_thresh = frq->value & ~0x1; /* must be even */ - } - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t val; - - dldwd_lock(priv); - - if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); - if (err) - val = 0; - - frq->value = val ? 2347 : 0; - frq->disabled = ! val; - frq->fixed = 0; - } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); - if (err) - val = 0; - - frq->value = val; - frq->disabled = (val >= 2346); - frq->fixed = 1; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int rate_ctrl = -1; - int fixed, upto; - int brate; - int i; - - dldwd_lock(priv); - - /* Normalise value */ - brate = rrq->value / 500000; - - 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_PRISM2: /* Prism II style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - switch(brate) { - case 0: - fixed = 0x0; - upto = 0x15; - 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 = 0x15; - 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; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t 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; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - - if (val == 6) - brate = 11; - else - brate = 2*val; - } else - rrq->fixed = 1; - break; - case FIRMWARE_TYPE_PRISM2: /* Prism II 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; - - if(val >= 8) - brate = 22; - else if(val >= 4) - brate = 11; - else if(val >= 2) - brate = 4; - else - brate = 2; - break; - } - - rrq->value = brate * 500000; - rrq->disabled = 0; - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - } - if (err) - goto out; - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if(!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t enable, period, timeout, mcast; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - dldwd_unlock(priv); - - return err; -} - -#if WIRELESS_EXT > 10 -static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if ((rrq->disabled) || (!priv->has_retry)){ - err = -EOPNOTSUPP; - goto out; - } else { - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_MAX) - priv->retry_long = rrq->value; - else if (rrq->flags & IW_RETRY_MIN) - priv->retry_short = rrq->value; - else { - /* No modifier : set both */ - priv->retry_long = rrq->value; - priv->retry_short = rrq->value; - } - } - if (rrq->flags & IW_RETRY_LIFETIME) { - priv->retry_time = rrq->value / 1000; - } - if ((rrq->flags & IW_RETRY_TYPE) == 0) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t short_limit, long_limit, lifetime; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); - if (err) - goto out; - - rrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the retry number */ - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = lifetime * 1000; /* ??? */ - } else { - /* By default, display the min number */ - if ((rrq->flags & IW_RETRY_MAX)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - rrq->value = long_limit; - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = short_limit; - if(short_limit != long_limit) - rrq->flags |= IW_RETRY_MIN; - } - } - - out: - dldwd_unlock(priv); - - return err; -} -#endif /* WIRELESS_EXT > 10 */ - -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = *( (int *) wrq->u.name ); - int err = 0; - - dldwd_lock(priv); - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (! priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (! priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (! err) - /* Actually update the mode we are using */ - set_port_type(priv); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->prefer_port3; - dldwd_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) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - int number = srq->length; - int i; - int err = 0; - - /* Check the number of addresses */ - if (number > IW_MAX_SPY) - return -E2BIG; - - /* Get the data in the driver */ - if (srq->pointer) { - if (copy_from_user(address, srq->pointer, - sizeof(struct sockaddr) * number)) - return -EFAULT; - } - - /* Make sure nobody mess with the structure while we do */ - dldwd_lock(priv); - - /* dldwd_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Time to show what we have done... */ - DEBUG(0, "%s: New spy list:\n", dev->name); - for (i = 0; i < number; i++) { - DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, i+1, - priv->spy_address[i][0], priv->spy_address[i][1], - priv->spy_address[i][2], priv->spy_address[i][3], - priv->spy_address[i][4], priv->spy_address[i][5]); - } - - /* Now, let the others play */ - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - struct iw_quality spy_stat[IW_MAX_SPY]; - int number; - int i; - - dldwd_lock(priv); - - number = priv->spy_number; - if ((number > 0) && (srq->pointer)) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path migh update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(&spy_stat, priv->spy_stat, - sizeof(struct iw_quality) * IW_MAX_SPY); - for (i=0; i < number; i++) - priv->spy_stat[i].updated = 0; - } - - dldwd_unlock(priv); - - /* Push stuff to user space */ - srq->length = number; - if(copy_to_user(srq->pointer, address, - sizeof(struct sockaddr) * number)) - return -EFAULT; - if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), - &spy_stat, sizeof(struct iw_quality) * number)) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - dldwd_priv_t *priv = dev->priv; - struct iwreq *wrq = (struct iwreq *)rq; - int err = 0; - int changed = 0; - - TRACE_ENTER(dev->name); - - switch (cmd) { - case SIOCGIWNAME: - DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); - strcpy(wrq->u.name, "IEEE 802.11-DS"); - break; - - 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); - break; - - case SIOCGIWRANGE: - DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); - err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); - break; - - case SIOCSIWMODE: - DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); - dldwd_lock(priv); - switch (wrq->u.mode) { - case IW_MODE_ADHOC: - if (! (priv->has_ibss || priv->has_port3) ) - err = -EINVAL; - else { - priv->iw_mode = IW_MODE_ADHOC; - changed = 1; - } - break; - - case IW_MODE_INFRA: - priv->iw_mode = IW_MODE_INFRA; - changed = 1; - break; - - default: - err = -EINVAL; - break; - } - set_port_type(priv); - dldwd_unlock(priv); - break; - - case SIOCGIWMODE: - DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); - dldwd_lock(priv); - wrq->u.mode = priv->iw_mode; - dldwd_unlock(priv); - break; - - case SIOCSIWENCODE: - DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); - if (! err) - changed = 1; - break; - - case SIOCGIWENCODE: - DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); - break; - - case SIOCSIWESSID: - DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); - err = dldwd_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); - break; - - case SIOCSIWNICKN: - DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); - err = dldwd_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); - break; - - case SIOCGIWFREQ: - DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); - wrq->u.freq.m = dldwd_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); - if (! err) - changed = 1; - break; - - case SIOCGIWSENS: - DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); - err = dldwd_ioctl_getsens(dev, &wrq->u.sens); - break; - - case SIOCSIWSENS: - DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); - err = dldwd_ioctl_setsens(dev, &wrq->u.sens); - if (! err) - changed = 1; - break; - - case SIOCGIWRTS: - DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); - wrq->u.rts.value = priv->rts_thresh; - wrq->u.rts.disabled = (wrq->u.rts.value == 2347); - wrq->u.rts.fixed = 1; - break; - - case SIOCSIWRTS: - DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); - err = dldwd_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); - if (! err) - changed = 1; - break; - - case SIOCGIWFRAG: - DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); - err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); - break; - - case SIOCSIWRATE: - DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); - err = dldwd_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); - break; - - case SIOCSIWPOWER: - DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); - err = dldwd_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); - break; - - case SIOCGIWTXPOW: - DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); - /* The card only supports one tx power, so this is easy */ - wrq->u.txpower.value = 15; /* dBm */ - wrq->u.txpower.fixed = 1; - wrq->u.txpower.disabled = 0; - wrq->u.txpower.flags = IW_TXPOW_DBM; - break; - -#if WIRELESS_EXT > 10 - case SIOCSIWRETRY: - DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); - err = dldwd_ioctl_setretry(dev, &wrq->u.retry); - if (! err) - changed = 1; - break; - - case SIOCGIWRETRY: - DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); - err = dldwd_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); - break; - - case SIOCGIWSPY: - DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); - - err = dldwd_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 + 0x2, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCDEVPRIVATE + 0x3, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCDEVPRIVATE + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCDEVPRIVATE + 0x5, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" } - }; - - err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); - if (err) - break; - - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - err = -EFAULT; - } - break; - - case SIOCDEVPRIVATE + 0x0: /* force_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - dldwd_reset(priv); - break; - - case SIOCDEVPRIVATE + 0x2: /* set_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_setport3(dev, wrq); - if (! err) - changed = 1; - break; - - case SIOCDEVPRIVATE + 0x3: /* get_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", - dev->name); - err = dldwd_ioctl_getport3(dev, wrq); - break; - - case SIOCDEVPRIVATE + 0x4: /* set_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - if(priv->has_preamble) { - int val = *( (int *) wrq->u.name ); - - dldwd_lock(priv); - if(val) - priv->preamble = 1; - else - priv->preamble = 0; - dldwd_unlock(priv); - changed = 1; - } else - err = -EOPNOTSUPP; - break; - - case SIOCDEVPRIVATE + 0x5: /* get_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", - dev->name); - if(priv->has_preamble) { - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->preamble; - dldwd_unlock(priv); - } else - err = -EOPNOTSUPP; - break; - - default: - err = -EOPNOTSUPP; - } - - if (! err && changed && netif_running(dev)) { - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - } - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu) -{ - TRACE_ENTER(dev->name); - - if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) - return -EINVAL; - - dev->mtu = new_mtu; - - TRACE_EXIT(dev->name); - - return 0; -} - -static void __dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - int promisc, allmulti, mc_count; - - 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) ) { - 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, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", - dev->name, err, promisc); - } 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; - - 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) ) { - 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; - } - - 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); - - 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, - 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; - } - - /* Since we can set the promiscuous flag when it wasn't asked - for, make sure the net_device knows about it. */ - if (priv->promiscuous) - dev->flags |= IFF_PROMISC; - else - dev->flags &= ~IFF_PROMISC; - - if (priv->allmulti) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; - - TRACE_EXIT(dev->name); -} - -/* - * procfs stuff - */ - -static struct proc_dir_entry *dir_base = NULL; - -/* - * This function updates the total amount of data printed so far. It then - * determines if the amount of data printed into a buffer has reached the - * offset requested. If it hasn't, then the buffer is shifted over so that - * the next bit of data can be printed over the old bit. If the total - * amount printed so far exceeds the total amount requested, then this - * function returns 1, otherwise 0. - */ -static int - -shift_buffer(char *buffer, int requested_offset, int requested_len, - int *total, int *slop, char **buf) -{ - int printed; - - printed = *buf - buffer; - if (*total + printed <= requested_offset) { - *total += printed; - *buf = buffer; - } - else { - if (*total < requested_offset) { - *slop = requested_offset - *total; - } - *total = requested_offset + printed - *slop; - } - if (*total > requested_offset + requested_len) { - return 1; - } - else { - return 0; - } -} - -/* - * This function calculates the actual start of the requested data - * in the buffer. It also calculates actual length of data returned, - * which could be less that the amount of data requested. - */ -#define PROC_BUFFER_SIZE 4096 -#define PROC_SAFE_SIZE 3072 - -static int -calc_start_len(char *buffer, char **start, int requested_offset, - int requested_len, int total, char *buf) -{ - int return_len, buffer_len; - - buffer_len = buf - buffer; - if (buffer_len >= PROC_BUFFER_SIZE - 1) { - printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); - } - - /* - * There may be bytes before and after the - * chunk that was actually requested. - */ - return_len = total - requested_offset; - if (return_len < 0) { - return_len = 0; - } - *start = buf - return_len; - if (return_len > requested_len) { - return_len = requested_len; - } - return return_len; -} - -static int -dldwd_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; - char *buf; - int total = 0, slop = 0; - - buf = page; - -#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) - - DHERMESREG(CMD); - DHERMESREG(PARAM0); - DHERMESREG(PARAM1); - DHERMESREG(PARAM2); - DHERMESREG(STATUS); - DHERMESREG(RESP0); - DHERMESREG(RESP1); - DHERMESREG(RESP2); - DHERMESREG(INFOFID); - DHERMESREG(RXFID); - DHERMESREG(ALLOCFID); - DHERMESREG(TXCOMPLFID); - DHERMESREG(SELECT0); - DHERMESREG(OFFSET0); - DHERMESREG(SELECT1); - DHERMESREG(OFFSET1); - DHERMESREG(EVSTAT); - DHERMESREG(INTEN); - DHERMESREG(EVACK); - DHERMESREG(CONTROL); - DHERMESREG(SWSUPPORT0); - DHERMESREG(SWSUPPORT1); - DHERMESREG(SWSUPPORT2); - DHERMESREG(AUXPAGE); - DHERMESREG(AUXOFFSET); - DHERMESREG(AUXDATA); -#undef DHERMESREG - - shift_buffer(page, requested_offset, requested_len, &total, - &slop, &buf); - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -struct { - uint16_t rid; - char *name; - int minlen, maxlen; - int displaytype; -#define DISPLAY_WORDS 0 -#define DISPLAY_BYTES 1 -#define DISPLAY_STRING 2 -} 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(PRISM2_TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_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 NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) - -static int -dldwd_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; - char *buf; - int total = 0, slop = 0; - int i; - uint16_t length; - int err; - - buf = page; - - /* print out all the config RIDs */ - for (i = 0; i < NUM_RIDS; i++) { - uint16_t rid = record_table[i].rid; - int minlen = record_table[i].minlen; - int maxlen = record_table[i].maxlen; - int len; - uint8_t *val8; - uint16_t *val16; - int j; - - val8 = kmalloc(maxlen + 2, GFP_KERNEL); - if (! val8) - return -ENOMEM; - - err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, - &length, val8); - if (err) { - DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); - continue; - } - val16 = (uint16_t *)val8; - - buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, - rid, length, (length-1)*2); - len = MIN( MAX(minlen, (length-1)*2), maxlen); - - switch (record_table[i].displaytype) { - case DISPLAY_WORDS: - for (j = 0; j < len / 2; j++) { - buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); - } - buf--; - break; - - case DISPLAY_BYTES: - default: - for (j = 0; j < len; j++) { - buf += sprintf(buf, "%02X:", val8[j]); - } - buf--; - break; - - case DISPLAY_STRING: - len = MIN(len, le16_to_cpu(val16[0])+2); - val8[len] = '\0'; - buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); - break; - } - - buf += sprintf(buf, "\n"); - - kfree(val8); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; - } - - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -/* initialise the /proc subsystem for the hermes driver, creating the - * separate entries */ -static int -dldwd_proc_init(void) -{ - int err = 0; - - TRACE_ENTER("dldwd"); - - /* 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(); - err = -ENOMEM; - } - - TRACE_EXIT("dldwd"); - - return err; -} - -static int -dldwd_proc_dev_init(dldwd_priv_t *dev) -{ - dev->dir_dev = NULL; - /* create the directory for it to sit in */ - dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (dev->dir_dev == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->node.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", dev->node.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", dev->node.dev_name); - goto fail; - } - - return 0; - fail: - dldwd_proc_dev_cleanup(dev); - return -ENOMEM; -} - -static void -dldwd_proc_dev_cleanup(dldwd_priv_t *priv) -{ - if (priv->dir_regs) { - remove_proc_entry("regs", priv->dir_dev); - priv->dir_regs = NULL; - } - if (priv->dir_recs) { - remove_proc_entry("recs", priv->dir_dev); - priv->dir_recs = NULL; - } - if (priv->dir_dev) { - remove_proc_entry(priv->node.dev_name, dir_base); - priv->dir_dev = NULL; - } -} - -static void -dldwd_proc_cleanup(void) -{ - TRACE_ENTER("dldwd"); - - if (dir_base) { - remove_proc_entry("hermes", &proc_root); - dir_base = NULL; - } - - TRACE_EXIT("dldwd"); -} - -/*====================================================================*/ - -/* - * From here on in, it's all PCMCIA junk, taken almost directly from - * dummy_cs.c - */ - -/* - The dev_info variable is the "key" that is used to match up this - device driver with appropriate cards, through the card configuration - database. -*/ - -static dev_info_t dev_info = "orinoco_cs"; - -/* - A linked list of "instances" of the dummy device. Each actual - PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). - - You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor - device numbers are used to derive the corresponding array index. -*/ - -static dev_link_t *dev_list = NULL; -static int num_instances = 0; - -/*====================================================================*/ - -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); -} - -/*====================================================================== - dldwd_attach() creates an "instance" of the driver, allocating - local data structures for one device. 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 *dldwd_attach(void) -{ - dldwd_priv_t *priv; - dev_link_t *link; - struct net_device *ndev; - client_reg_t client_reg; - int ret, i; - - TRACE_ENTER("dldwd"); - - /* Allocate space for private device-specific data */ - priv = kmalloc(sizeof(*priv), GFP_KERNEL); - if (! priv) { - link = NULL; - goto out; - } - - memset(priv, 0, sizeof(*priv)); - priv->instance = num_instances++; /* FIXME: Racy? */ - spin_lock_init(&priv->lock); - - link = &priv->link; - ndev = &priv->ndev; - link->priv = ndev->priv = priv; - - /* Initialize the dev_link_t structure */ - link->release.function = &dldwd_release; - link->release.data = (u_long) link; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - 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 = NULL; - - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - - /* Set up the net_device */ - ether_setup(ndev); - ndev->init = dldwd_init; - ndev->open = dldwd_open; - ndev->stop = dldwd_stop; - ndev->hard_start_xmit = dldwd_xmit; - ndev->tx_timeout = dldwd_tx_timeout; - ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ - - ndev->get_stats = dldwd_get_stats; - ndev->get_wireless_stats = dldwd_get_wireless_stats; - - ndev->do_ioctl = dldwd_ioctl; - - ndev->change_mtu = dldwd_change_mtu; - ndev->set_multicast_list = dldwd_set_multicast_list; - - netif_stop_queue(ndev); - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - 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_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_detach(link); - link = NULL; - goto out; - } - - out: - TRACE_EXIT("dldwd"); - return link; -} /* dldwd_attach */ - -/*====================================================================== - 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 dldwd_detach(dev_link_t * link) -{ - dev_link_t **linkp; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER("dldwd"); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) - break; - if (*linkp == NULL) - goto out; - - /* - 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) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); -#endif - link->state |= DEV_STALE_LINK; - goto out; - } - - /* Break the link with Card Services */ - if (link->handle) - CardServices(DeregisterClient, link->handle); - - /* Unlink device structure, and free it */ - *linkp = link->next; - DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); - if (link->dev) { - DEBUG(0, "orinoco_cs: About to unregister net device %p\n", - &priv->ndev); - unregister_netdev(&priv->ndev); - } - kfree(priv); - - num_instances--; /* FIXME: Racy? */ - - out: - TRACE_EXIT("dldwd"); -} /* dldwd_detach */ - -/* - * Do a soft reset of the Pcmcia card using the Configuration Option Register - * Can't do any harm, and actually may do some good on some cards... - */ -static int dldwd_cor_reset(dev_link_t *link) -{ - conf_reg_t reg; - u_long default_cor; - - /* Save original COR value */ - reg.Function = 0; - reg.Action = CS_READ; - reg.Offset = CISREG_COR; - reg.Value = 0; - CardServices(AccessConfigurationRegister, link->handle, ®); - default_cor = reg.Value; - - DEBUG(2, "dldwd : dldwd_cor_reset() : cor=0x%lX\n", default_cor); - - /* Soft-Reset card */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_COR; - reg.Value = (default_cor | COR_SOFT_RESET); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has acknowledged our reset */ - mdelay(1); - - /* Restore original COR configuration index */ - reg.Value = (default_cor & COR_CONFIG_MASK); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has finished restarting */ - mdelay(1); - - return(0); -} - -/*====================================================================== - dldwd_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. - ======================================================================*/ - -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry - -static void dldwd_config(dev_link_t * link) -{ - client_handle_t handle = link->handle; - dldwd_priv_t *priv = link->priv; - hermes_t *hw = &priv->hw; - struct net_device *ndev = &priv->ndev; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - cistpl_cftable_entry_t dflt = { 0 }; - cisinfo_t info; - - TRACE_ENTER("dldwd"); - - CS_CHECK(ValidateCIS, handle, &info); - - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); - link->conf.Vcc = conf.Vcc; - - DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", - link->conf.ConfigBase, link->conf.Vcc); - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - - DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n", - cfg->index, cfg->flags); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != - cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - 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_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n"); - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - CS_CHECK(GetNextTuple, handle, &tuple); - } - - /* - Allocate an interrupt line. Note that this does not assign a - handler to the interrupt, unless the 'Handler' member of the - irq structure is initialized. - */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) { - int i; - - 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 = dldwd_interrupt; - link->irq.Instance = priv; - - CS_CHECK(RequestIRQ, link->handle, &link->irq); - } - - /* We initialize the hermes structure before completing PCMCIA - configuration just in case the interrupt handler gets - called. */ - hermes_struct_init(hw, link->io.BasePort1); - - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); - - ndev->base_addr = link->io.BasePort1; - ndev->irq = link->irq.AssignedIRQ; - - /* Do a Pcmcia soft reset of the card (optional) */ - if(reset_cor) - dldwd_cor_reset(link); - - /* 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 "orinoco_cs: register_netdev() failed\n"); - goto failed; - } - strcpy(priv->node.dev_name, ndev->name); - - /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - priv->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq.AssignedIRQ); - if (link->io.NumPorts1) - printk(", io 0x%04x-0x%04x", link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - if (link->io.NumPorts2) - printk(" & 0x%04x-0x%04x", link->io.BasePort2, - link->io.BasePort2 + link->io.NumPorts2 - 1); - printk("\n"); - - /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) { - printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", - priv->node.dev_name); - goto failed; - } - - /* - At this point, the dev_node_t structure(s) need to be - initialized and arranged in a linked list at link->dev. - */ - priv->node.major = priv->node.minor = 0; - link->dev = &priv->node; - link->state &= ~DEV_CONFIG_PENDING; - - TRACE_EXIT("dldwd"); - - return; - - cs_failed: - cs_error(link->handle, last_fn, last_ret); - failed: - dldwd_release((u_long) link); - - TRACE_EXIT("dldwd"); -} /* dldwd_config */ - -/*====================================================================== - After a card is removed, dldwd_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_release(u_long arg) -{ - dev_link_t *link = (dev_link_t *) arg; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER(link->dev->dev_name); - - /* - If the device is currently in use, we won't release until it - is actually closed, because until then, we can't be sure that - no one will try to access the device or its data structures. - */ - if (link->open) { - DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - /* - In a normal driver, additional code may be needed to release - other kernel data structures associated with this device. - */ - - dldwd_proc_dev_cleanup(priv); - - /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); - link->state &= ~DEV_CONFIG; - - TRACE_EXIT(link->dev->dev_name); -} /* dldwd_release */ - -/*====================================================================== - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - ======================================================================*/ - -static int dldwd_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 net_device *dev = &priv->ndev; - - TRACE_ENTER("dldwd"); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - dldwd_shutdown(priv); - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) { - netif_stop_queue(dev); - 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_config(link); - break; - case CS_EVENT_PM_SUSPEND: - - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - dldwd_shutdown(priv); - /* Mark the device as stopped, to block IO until later */ - - if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue(dev); - 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 (dldwd_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_stop(dev); - } - } - } - /* - In a normal driver, additional code may go here to restore - the device state and restart IO. - */ - break; - } - - TRACE_EXIT("dldwd"); - - return 0; -} /* dldwd_event */ - -static int __init init_dldwd_cs(void) -{ - servinfo_t serv; - int err; - - TRACE_ENTER("dldwd"); - - printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); - - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "orinoco_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach); - - - err = dldwd_proc_init(); - - TRACE_EXIT("dldwd"); - return err; -} - -static void __exit exit_dldwd_cs(void) -{ - TRACE_ENTER("dldwd"); - - dldwd_proc_cleanup(); - - unregister_pccard_driver(&dev_info); - - if (dev_list) - DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); - while (dev_list != NULL) { - del_timer(&dev_list->release); - if (dev_list->state & DEV_CONFIG) - dldwd_release((u_long) dev_list); - dldwd_detach(dev_list); - } - - TRACE_EXIT("dldwd"); -} - -module_init(init_dldwd_cs); -module_exit(exit_dldwd_cs); diff -u --recursive --new-file v2.4.4/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c --- v2.4.4/linux/drivers/net/pppoe.c Tue Mar 6 19:44:35 2001 +++ linux/drivers/net/pppoe.c Wed May 16 10:31:27 2001 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.5 + * Version: 0.6.6 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -19,6 +19,7 @@ * 051000 : Initialization cleanup. * 111100 : Fix recvmsg. * 050101 : Fix PADT procesing. + * 140501 : Use pppoe_rcv_core to handle all backlog. (Alexey) * * Author: Michal Ostrowski * Contributors: @@ -376,22 +377,6 @@ return ret; } - -/************************************************************************ - * - * Receive wrapper called in process context. - * - ***********************************************************************/ -int pppoe_backlog_rcv(struct sock *sk, struct sk_buff *skb) -{ - lock_sock(sk); - pppoe_rcv_core(sk, skb); - release_sock(sk); - return 0; -} - - - /************************************************************************ * * Receive a PPPoE Discovery frame. @@ -481,7 +466,7 @@ sk->protocol = PX_PROTO_OE; sk->family = PF_PPPOX; - sk->backlog_rcv = pppoe_backlog_rcv; + sk->backlog_rcv = pppoe_rcv_core; sk->next = NULL; sk->pprev = NULL; sk->state = PPPOX_NONE; diff -u --recursive --new-file v2.4.4/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.4.4/linux/drivers/net/sunhme.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/net/sunhme.c Sun May 20 11:32:07 2001 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.117 2001/04/19 22:32:41 davem Exp $ +/* $Id: sunhme.c,v 1.119 2001/05/17 04:12:16 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -2206,6 +2206,7 @@ static int happy_meal_open(struct net_device *dev) { struct happy_meal *hp = dev->priv; + int res; HMD(("happy_meal_open: ")); @@ -2229,7 +2230,10 @@ } HMD(("to happy_meal_init\n")); - return happy_meal_init(hp, 0); + res = happy_meal_init(hp, 0); + if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)) + free_irq(dev->irq, dev); + return res; } static int happy_meal_close(struct net_device *dev) @@ -2441,7 +2445,7 @@ if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) return -EFAULT; - if (ecmd.cmd == SPARC_ETH_GSET) { + if (ecmd.cmd == ETHTOOL_GSET) { ecmd.supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | @@ -2480,7 +2484,7 @@ if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; - } else if (ecmd.cmd == SPARC_ETH_SSET) { + } else if (ecmd.cmd == ETHTOOL_SSET) { if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -2864,7 +2868,7 @@ prom_getstring(node, "name", prom_name, sizeof(prom_name)); #else -#warning This needs to be corrected... -DaveM +/* This needs to be corrected... -DaveM */ strcpy(prom_name, "qfe"); #endif diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/abyss.c linux/drivers/net/tokenring/abyss.c --- v2.4.4/linux/drivers/net/tokenring/abyss.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/net/tokenring/abyss.c Fri May 25 09:58:07 2001 @@ -137,8 +137,7 @@ */ dev->base_addr += 0x10; - ret = tmsdev_init(dev,0,pdev); - /* XXX: should be the max PCI32 DMA max */ + ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/ibmtr.h linux/drivers/net/tokenring/ibmtr.h --- v2.4.4/linux/drivers/net/tokenring/ibmtr.h Thu Mar 2 10:15:30 2000 +++ linux/drivers/net/tokenring/ibmtr.h Wed Dec 31 16:00:00 1969 @@ -1,454 +0,0 @@ -/* Definitions for an IBM Token Ring card. */ -/* This file is distributed under the GNU GPL */ - -/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ - -#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ -#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ -#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ -#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ -#define TR_RETRIES 6 /* number of open retries */ - -#define TR_ISA 1 -#define TR_MCA 2 -#define TR_ISAPNP 3 -#define NOTOK 0 -#define TOKDEBUG 1 - -#define IBMTR_SHARED_RAM_SIZE 0x10000 -#define IBMTR_IO_EXTENT 4 -#define IBMTR_MAX_ADAPTERS 2 - -#define CHANNEL_ID 0X1F30 -#define AIP 0X1F00 -#define AIPCHKSUM1 0X1F60 -#define AIPCHKSUM2 0X1FF0 -#define AIPADAPTYPE 0X1FA0 -#define AIPDATARATE 0X1FA2 -#define AIPEARLYTOKEN 0X1FA4 -#define AIPAVAILSHRAM 0X1FA6 -#define AIPSHRAMPAGE 0X1FA8 -#define AIP4MBDHB 0X1FAA -#define AIP16MBDHB 0X1FAC -#define AIPFID 0X1FBA - -/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything - the way my documentation had it, ie: 0x0A20. */ -#define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */ -#define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */ -#define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */ -#define ADAPTINTREL 0x3 /* Adapter interrupt release */ - -#define MMIOStartLocP 0x0a20 /* Primary adapter's starting MMIO area */ -#define MMIOStartLocA 0x0a24 /* Alternate adapter's starting MMIO area */ - -#define GLOBAL_INT_ENABLE 0x02f0 - -/* MMIO bits 0-4 select register */ -#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */ -/* Used to set the starting address of shared RAM */ -/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/ -/* ie: 0x02 sets RAM address to ...ato! issy su wazzoo !! GODZILLA!!! */ -#define RRR_ODD 0x01 -/* Bits 2 and 3 of this register can be read to determine shared RAM size */ -/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k */ -#define WRBR_EVEN 0x02 /* Write region base registers - even and odd */ -#define WRBR_ODD 0x03 -#define WWOR_EVEN 0x04 /* Write window open registers - even and odd */ -#define WWOR_ODD 0x05 -#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */ -#define WWCR_ODD 0x07 - -/* Interrupt status registers - PC system - even and odd */ -#define ISRP_EVEN 0x08 - -#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has - expired. */ -#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an - internal error. */ -#define ACCESS_INT 0x04 /* Bit 2 - Access interrupt. You have attempted to - write to an invalid area of shared RAM or an invalid - register within the MMIO. */ -/* In addition, the following bits within ISRP_EVEN can be turned on or off by you */ -/* to control the interrupt processing: */ -#define INT_IRQ 0x80 /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and - IRQ. This should normally be set (by you) to 1. */ -#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable. If 0, no interrupts will - occur. If 1, interrupts will occur normally. - Normally set to 1. */ -/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the primary adapter,*/ -/* 1 if this adapter is the alternate adapter. */ - - -#define ISRP_ODD 0x09 - -#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check. the adapter has - encountered a serious problem and has closed - itself. Whoa. */ -#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response. The adapter has accepted - an SRB request and set the return code within - the SRB. */ -#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free. The adapter has read the ASB - and this area can be safely reused. This interrupt - is only used if your application has set the ASB - free request bit in ISRA_ODD or if an error was - detected in your response. */ -#define ARB_CMD_INT 0x08 /* Bit 3 - ARB command. The adapter has given you a - command for action. The command is located in the - ARB area of shared memory. */ -#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response. The adapter has posted a - response to your SRB (the response is located in - the SSB area of shared memory). */ -/* Bit 1 - Bridge frame forward complete. */ - - - -#define ISRA_EVEN 0x0A /* Interrupt status registers - adapter - even and odd */ -/* Bit 7 - Internal parity error (on adapter's internal bus) */ -/* Bit 6 - Timer interrupt pending */ -/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */ -/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */ -/* Bit 3 - Adapter processor check status */ -/* Bit 2 - Reserved */ -/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */ -/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */ - -#define ISRA_ODD 0x0B -#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new - command in the SRB and are ready for the adapter to - process the command. */ -#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response - (an ASB) in the shared RAM which is available for - the adapter's use. */ -/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */ -/* command is still pending. The adapter will then interrupt you when the previous */ -/* command is completed */ -/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */ -/* ASB is still pending. The adapter will then interrupt you when the previous ASB */ -/* is copied. */ -#define ARB_FREE 0x2 -#define SSB_FREE 0x1 - -#define TCR_EVEN 0x0C /* Timer control registers - even and odd */ -#define TCR_ODD 0x0D -#define TVR_EVEN 0x0E /* Timer value registers - even and odd */ -#define TVR_ODD 0x0F -#define SRPR_EVEN 0x18 /* Shared RAM paging registers - even and odd */ -#define SRPR_ENABLE_PAGING 0xc0 -#define SRPR_ODD 0x19 /* Not used. */ -#define TOKREAD 0x60 -#define TOKOR 0x40 -#define TOKAND 0x20 -#define TOKWRITE 0x00 - -/* MMIO bits 5-6 select operation */ -/* 00 is used to write to a register */ -/* 01 is used to bitwise AND a byte with a register */ -/* 10 is used to bitwise OR a byte with a register */ -/* 11 is used to read from a register */ - -/* MMIO bits 7-8 select area of interest.. see below */ -/* 00 selects attachment control area. */ -/* 01 is reserved. */ -/* 10 selects adapter identification area A containing the adapter encoded address. */ -/* 11 selects the adapter identification area B containing test patterns. */ - -#define PCCHANNELID 5049434F3631313039393020 -#define MCCHANNELID 4D4152533633583435313820 - -#define ACA_OFFSET 0x1e00 -#define ACA_SET 0x40 -#define ACA_RESET 0x20 -#define ACA_RW 0x00 - -#ifdef ENABLE_PAGING -#define SET_PAGE(x) (isa_writeb((x), \ - ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN)) -#else -#define SET_PAGE(x) -#endif - -typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state; - -/* do_tok_int possible values */ -#define FIRST_INT 1 -#define NOT_FIRST 2 - -struct tok_info { - unsigned char irq; - __u32 mmio; - unsigned char hw_address[32]; - unsigned char adapter_type; - unsigned char data_rate; - unsigned char token_release; - unsigned char avail_shared_ram; - unsigned char shared_ram_paging; - unsigned short dhb_size4mb; - unsigned short rbuf_len4; - unsigned short rbuf_cnt4; - unsigned short maxmtu4; - unsigned short dhb_size16mb; - unsigned short rbuf_len16; - unsigned short rbuf_cnt16; - unsigned short maxmtu16; - /* Additions by David Morris */ - unsigned char do_tok_int; - wait_queue_head_t wait_for_tok_int; - wait_queue_head_t wait_for_reset; - unsigned char sram_base; - /* Additions by Peter De Schrijver */ - unsigned char page_mask; /* mask to select RAM page to Map*/ - unsigned char mapped_ram_size; /* size of RAM page */ - __u32 sram; /* Shared memory base address */ - __u32 init_srb; /* Initial System Request Block address */ - __u32 srb; /* System Request Block address */ - __u32 ssb; /* System Status Block address */ - __u32 arb; /* Adapter Request Block address */ - __u32 asb; /* Adapter Status Block address */ - __u8 init_srb_page; - __u8 srb_page; - __u8 ssb_page; - __u8 arb_page; - __u8 asb_page; - unsigned short exsap_station_id; - unsigned short global_int_enable; - struct sk_buff *current_skb; - struct net_device_stats tr_stats; - unsigned char auto_ringspeedsave; - open_state open_status; - unsigned char readlog_pending; - unsigned short adapter_int_enable; /* Adapter-specific int enable */ - struct timer_list tr_timer; - unsigned char ring_speed; - __u32 func_addr; - unsigned int retry_count; - spinlock_t lock; /* SMP protection */ -}; - -/* token ring adapter commands */ -#define DIR_INTERRUPT 0x00 /* struct srb_interrupt */ -#define DIR_MOD_OPEN_PARAMS 0x01 -#define DIR_OPEN_ADAPTER 0x03 /* struct dir_open_adapter */ -#define DIR_CLOSE_ADAPTER 0x04 -#define DIR_SET_GRP_ADDR 0x06 -#define DIR_SET_FUNC_ADDR 0x07 /* struct srb_set_funct_addr */ -#define DIR_READ_LOG 0x08 /* struct srb_read_log */ -#define DLC_OPEN_SAP 0x15 /* struct dlc_open_sap */ -#define DLC_CLOSE_SAP 0x16 -#define DATA_LOST 0x20 /* struct asb_rec */ -#define REC_DATA 0x81 /* struct arb_rec_req */ -#define XMIT_DATA_REQ 0x82 /* struct arb_xmit_req */ -#define DLC_STATUS 0x83 /* struct arb_dlc_status */ -#define RING_STAT_CHANGE 0x84 /* struct dlc_open_sap ??? */ - -/* DIR_OPEN_ADAPTER options */ -#define OPEN_PASS_BCON_MAC 0x0100 -#define NUM_RCV_BUF 2 -#define RCV_BUF_LEN 1024 -#define DHB_LENGTH 2048 -#define NUM_DHB 2 -#define DLC_MAX_SAP 2 -#define DLC_MAX_STA 1 - -/* DLC_OPEN_SAP options */ -#define MAX_I_FIELD 0x0088 -#define SAP_OPEN_IND_SAP 0x04 -#define SAP_OPEN_PRIORITY 0x20 -#define SAP_OPEN_STATION_CNT 0x1 -#define XMIT_DIR_FRAME 0x0A -#define XMIT_UI_FRAME 0x0d -#define XMIT_XID_CMD 0x0e -#define XMIT_TEST_CMD 0x11 - -/* srb close return code */ -#define SIGNAL_LOSS 0x8000 -#define HARD_ERROR 0x4000 -#define XMIT_BEACON 0x1000 -#define LOBE_FAULT 0x0800 -#define AUTO_REMOVAL 0x0400 -#define REMOVE_RECV 0x0100 -#define LOG_OVERFLOW 0x0080 -#define RING_RECOVER 0x0020 - -struct srb_init_response { - unsigned char command; - unsigned char init_status; - unsigned char init_status_2; - unsigned char reserved[3]; - __u16 bring_up_code; - __u16 encoded_address; - __u16 level_address; - __u16 adapter_address; - __u16 parms_address; - __u16 mac_address; -}; - -struct dir_open_adapter { - unsigned char command; - char reserved[7]; - __u16 open_options; - unsigned char node_address[6]; - unsigned char group_address[4]; - unsigned char funct_address[4]; - __u16 num_rcv_buf; - __u16 rcv_buf_len; - __u16 dhb_length; - unsigned char num_dhb; - char reserved2; - unsigned char dlc_max_sap; - unsigned char dlc_max_sta; - unsigned char dlc_max_gsap; - unsigned char dlc_max_gmem; - unsigned char dlc_t1_tick_1; - unsigned char dlc_t2_tick_1; - unsigned char dlc_ti_tick_1; - unsigned char dlc_t1_tick_2; - unsigned char dlc_t2_tick_2; - unsigned char dlc_ti_tick_2; - unsigned char product_id[18]; -}; - -struct srb_open_response { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2[3]; - __u16 error_code; - __u16 asb_addr; - __u16 srb_addr; - __u16 arb_addr; - __u16 ssb_addr; -}; - -struct dlc_open_sap { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - __u16 station_id; - unsigned char timer_t1; - unsigned char timer_t2; - unsigned char timer_ti; - unsigned char maxout; - unsigned char maxin; - unsigned char maxout_incr; - unsigned char max_retry_count; - unsigned char gsap_max_mem; - __u16 max_i_field; - unsigned char sap_value; - unsigned char sap_options; - unsigned char station_count; - unsigned char sap_gsap_mem; - unsigned char gsap[0]; -}; - -struct srb_xmit { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; - unsigned char reserved1; - __u16 station_id; -}; - -struct srb_interrupt { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; -}; - -struct srb_read_log { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - unsigned char line_errors; - unsigned char internal_errors; - unsigned char burst_errors; - unsigned char A_C_errors; - unsigned char abort_delimiters; - unsigned char reserved3; - unsigned char lost_frames; - unsigned char recv_congest_count; - unsigned char frame_copied_errors; - unsigned char frequency_errors; - unsigned char token_errors; -}; - -struct asb_xmit_resp { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; - unsigned char reserved; - __u16 station_id; - __u16 frame_length; - unsigned char hdr_length; - unsigned char rsap_value; -}; - -struct arb_xmit_req { - unsigned char command; - unsigned char cmd_corr; - unsigned char reserved1[2]; - __u16 station_id; - __u16 dhb_address; -}; - -struct arb_rec_req { - unsigned char command; - unsigned char reserved1[3]; - __u16 station_id; - __u16 rec_buf_addr; - unsigned char lan_hdr_len; - unsigned char dlc_hdr_len; - __u16 frame_len; - unsigned char msg_type; -}; - -struct asb_rec { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - __u16 station_id; - __u16 rec_buf_addr; -}; - -struct rec_buf { - /* unsigned char reserved1[2]; */ - __u16 buf_ptr; - unsigned char reserved2; - __u16 buf_len; - unsigned char data[0]; -}; - -struct arb_dlc_status { - unsigned char command; - unsigned char reserved1[3]; - __u16 station_id; - __u16 status; - unsigned char frmr_data[5]; - unsigned char access_prio; - unsigned char rem_addr[TR_ALEN]; - unsigned char rsap_value; -}; - -struct arb_ring_stat_change { - unsigned char command; - unsigned char reserved1[5]; - __u16 ring_status; -}; - -struct srb_close_adapter { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; -}; - -struct srb_set_funct_addr { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2[3]; - unsigned char funct_address[4]; -}; - diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/madgemc.c linux/drivers/net/tokenring/madgemc.c --- v2.4.4/linux/drivers/net/tokenring/madgemc.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/tokenring/madgemc.c Fri May 25 09:58:07 2001 @@ -349,6 +349,7 @@ printk(":%2.2x", dev->dev_addr[i]); printk("\n"); + /* XXX is ISA_MAX_ADDRESS correct here? */ if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) { printk("%s: unable to get memory for dev->priv.\n", dev->name); diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.4.4/linux/drivers/net/tokenring/olympic.c Wed Apr 18 11:39:21 2001 +++ linux/drivers/net/tokenring/olympic.c Sun May 20 12:11:38 2001 @@ -64,10 +64,7 @@ #define OLYMPIC_DEBUG 0 - -#include #include - #include #include #include diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c --- v2.4.4/linux/drivers/net/tokenring/smctr.c Thu Apr 19 09:34:52 2001 +++ linux/drivers/net/tokenring/smctr.c Wed May 16 10:31:27 2001 @@ -1,7 +1,7 @@ /* * smctr.c: A network driver for the SMC Token Ring Adapters. * - * Written by Jay Schulist + * Written by Jay Schulist * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. @@ -14,7 +14,7 @@ * - SMC TokenCard SDK. * * Maintainer(s): - * JS Jay Schulist + * JS Jay Schulist * * Changes: * 07102000 JS Fixed a timing problem in smctr_wait_cmd(); @@ -62,7 +62,7 @@ #include "smctr.h" /* Our Stuff */ #include "smctr_firmware.h" /* SMC adapter firmware */ -static char version[] __initdata = KERN_INFO "smctr.c: v1.4 7/12/00 by jschlst@turbolinux.com\n"; +static char version[] __initdata = KERN_INFO "smctr.c: v1.4 7/12/00 by jschlst@samba.org\n"; static const char cardname[] = "smctr"; diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/smctr.h linux/drivers/net/tokenring/smctr.h --- v2.4.4/linux/drivers/net/tokenring/smctr.h Wed May 10 16:56:42 2000 +++ linux/drivers/net/tokenring/smctr.h Wed May 16 10:31:27 2001 @@ -1,7 +1,7 @@ /* smctr.h: SMC Token Ring driver header for Linux * * Authors: - * - Jay Schulist + * - Jay Schulist */ #ifndef __LINUX_SMCTR_H diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/smctr_firmware.h linux/drivers/net/tokenring/smctr_firmware.h --- v2.4.4/linux/drivers/net/tokenring/smctr_firmware.h Mon Dec 11 12:59:51 2000 +++ linux/drivers/net/tokenring/smctr_firmware.h Wed May 16 10:31:27 2001 @@ -14,7 +14,7 @@ * - This is an 8K binary image. (MCT.BIN v6.3C1 03/01/95) * * Authors: - * - Jay Schulist + * - Jay Schulist */ #include diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c --- v2.4.4/linux/drivers/net/tokenring/tms380tr.c Thu Apr 19 09:34:52 2001 +++ linux/drivers/net/tokenring/tms380tr.c Wed May 16 10:31:27 2001 @@ -28,7 +28,7 @@ * - Various Madge employees * * Maintainer(s): - * JS Jay Schulist jschlst@turbolinux.com + * JS Jay Schulist jschlst@samba.org * CG Christoph Goos cgoos@syskonnect.de * AF Adam Fritzler mid@auk.cx * MLP Mike Phillips phillim@amtrak.com diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/tms380tr.h linux/drivers/net/tokenring/tms380tr.h --- v2.4.4/linux/drivers/net/tokenring/tms380tr.h Tue Mar 6 19:28:34 2001 +++ linux/drivers/net/tokenring/tms380tr.h Fri May 25 09:58:07 2001 @@ -461,7 +461,9 @@ * fragments following. */ +/* XXX is there some better way to do this? */ #define ISA_MAX_ADDRESS 0x00ffffff +#define PCI_MAX_ADDRESS 0xffffffff #pragma pack(1) typedef struct { diff -u --recursive --new-file v2.4.4/linux/drivers/net/tokenring/tmspci.c linux/drivers/net/tokenring/tmspci.c --- v2.4.4/linux/drivers/net/tokenring/tmspci.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/net/tokenring/tmspci.c Fri May 25 09:58:07 2001 @@ -142,8 +142,7 @@ printk(":%2.2x", dev->dev_addr[i]); printk("\n"); - ret = tmsdev_init(dev,0, pdev); - /* XXX: should be the max PCI32 DMA max */ + ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); goto err_out_irq; @@ -165,7 +164,7 @@ dev->stop = tms380tr_close; ret = register_trdev(dev); - if (!ret) + if (ret) goto err_out_tmsdev; pci_set_drvdata(pdev, dev); diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.4.4/linux/drivers/net/tulip/21142.c Tue Apr 3 10:19:43 2001 +++ linux/drivers/net/tulip/21142.c Wed May 16 10:25:39 2001 @@ -100,16 +100,14 @@ { struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - int csr14 = ((tp->to_advertise & 0x0780) << 9) | - ((tp->to_advertise&0x0020)<<1) | 0xffbf; - - DPRINTK("ENTER\n"); + int csr14 = ((tp->sym_advertise & 0x0780) << 9) | + ((tp->sym_advertise & 0x0020) << 1) | 0xffbf; dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; if (tp->chip_id == PNIC2) { - tp->csr6 = 0x01000000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); + tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0); return; } if (tulip_debug > 1) @@ -118,7 +116,7 @@ outl(0x0001, ioaddr + CSR13); udelay(100); outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); + tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0); tulip_outl_csr(tp, tp->csr6, CSR6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); @@ -129,6 +127,24 @@ } +void pnic2_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC-2 link status changed, CSR5/12/14 %8.8x" + " %8.8x, %8.8x.\n", + dev->name, csr12, csr5, (int)inl(ioaddr + CSR14)); + dev->if_port = 5; + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + tp->csr6 = 0x01000000 | (tp->csr6 & 0xffff); + outl(tp->csr6, ioaddr + CSR6); + +} + void t21142_lnk_change(struct net_device *dev, int csr5) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -142,7 +158,7 @@ /* If NWay finished and we have a negotiated partner capability. */ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { int setup_done = 0; - int negotiated = tp->to_advertise & (csr12 >> 16); + int negotiated = tp->sym_advertise & (csr12 >> 16); tp->lpar = csr12 >> 16; tp->nwayset = 1; if (negotiated & 0x0100) dev->if_port = 5; @@ -151,7 +167,7 @@ else if (negotiated & 0x0020) dev->if_port = 0; else { tp->nwayset = 0; - if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) + if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180)) dev->if_port = 3; } tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; @@ -160,7 +176,7 @@ if (tp->nwayset) printk(KERN_INFO "%s: Switching to %s based on link " "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], tp->to_advertise, + dev->name, medianame[dev->if_port], tp->sym_advertise, tp->lpar, negotiated); else printk(KERN_INFO "%s: Autonegotiation failed, using %s," @@ -173,7 +189,7 @@ for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == dev->if_port) { tp->cur_index = i; - tulip_select_media(dev, 0); + tulip_select_media(dev, 1); setup_done = 1; break; } diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog --- v2.4.4/linux/drivers/net/tulip/ChangeLog Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/tulip/ChangeLog Sat May 19 18:02:45 2001 @@ -1,3 +1,182 @@ +2001-05-18 Jeff Garzik + + * tulip_core.c: Added ethtool support. + ETHTOOL_GDRVINFO ioctl only, for now. + +2001-05-14 Robert Olsson + + * Restored HW_FLOWCONTROL from Linux 2.1 series tulip (ANK) + plus Jamal's NETIF_RX_* feedback control. + +2001-05-14 Robert Olsson + + * Added support for 21143's Interrupt Mitigation. + Jamal original instigator. + +2001-05-14 Robert Olsson + + * tulip_refill_rx prototype added to tulip.h + +2001-05-13 Jeff Garzik + + * tulip_core.c: Remove HAS_PCI_MWI flag from Comet, untested. + +2001-05-12 Jeff Garzik + + * tulip_core.c, tulip.h: Remove Conexant PCI id, no chip + docs are available to fix problems with support. + +2001-05-12 Jeff Garzik + + * tulip_core.c (tulip_init_one): Do not call + unregister_netdev in error cleanup. Remnant of old + usage of init_etherdev. + +2001-05-12 Jeff Garzik + + * media.c (tulip_find_mii): Simple write the updated BMCR + twice, as it seems the best thing to do for both broken and + sane chips. + If the mii_advert value, as read from MII_ADVERTISE, is zero, + then generate a value we should advertise from the capability + bits in BMSR. + Fill in tp->advertising for all cases. + Just to be safe, clear all unwanted bits. + +2001-05-12 Jeff Garzik + + * tulip_core.c (private_ioctl): Fill in tp->advertising + when advertising value is changed by the user. + +2001-05-12 Jeff Garzik + + * tulip_core.c: Mark Comet chips as needed the updated MWI + csr0 configuration. + +2001-05-12 Jeff Garzik + + * media.c, tulip_core.c: Move MII scan into + from inlined inside tulip_init_one to new function + tulip_find_mii in media.c. + +2001-05-12 Jeff Garzik + + * media.c (tulip_check_duplex): + Only restart Rx/Tx engines if they are active + (and csr6 changes) + +2001-05-12 Jeff Garzik + + * tulip_core.c (tulip_mwi_config): + Clamp values read from PCI cache line size register to + values acceptable to tulip chip. Done for safety and + -almost- certainly unneeded. + +2001-05-11 Jeff Garzik + + * tulip_core.c (tulip_init_one): + Instead of unconditionally enabling autonegotiation, disable + autonegotiation if not using the default port. Further, + flip the nway bit immediately, and then update the + speed/duplex in a separate MII transaction. We do this + because some boards require that nway be disabled separately, + before media selection is forced. + + TODO: Investigate if we can simply write the same value + to BMCR twice, to avoid setting unnecessarily changing + phy settings. + +2001-05-11 Jeff Garzik + + * tulip.h, tulip_core.c: If HAS_PCI_MWI is set for a + given chip, adjust the csr0 values not according to + provided values but according to system cache line size. + Currently cache alignment is matched as closely to cache + line size as possible. Currently programmable burst limit + is set (ie. never unlimited), and always equal to cache + alignment and system cache size. Currently MWI bit is set + only if the MWI bit is present in the PCI command register. + +2001-05-11 Jeff Garzik + + * media.c (tulip_select_media): + For media types 1 and 3, only use the provided eeprom + advertising value if it is non-zero. + (tulip_check_duplex): + Do not exit ASAP if full_duplex_lock is set. This + ensures that the csr6 value is written if an update + is needed. + +2001-05-10 Jeff Garzik + + Merge PNIC-II-specific stuff from Becker's tulip.c: + + * tulip.h, 21142.c (pnic2_lnk_change): new function + * tulip_core.c (tulip_init_one): use it + + * tulip_core.c (tulip_tx_timeout): Add specific + debugging for PNIC2. + +2001-05-10 Jeff Garzik + + * tulip_core.c (tulip_init_one): Print out + tulip%d instead of PCI device number, for + consistency. + +2001-05-10 Jeff Garzik + + * Merge changes from Becker's tulip.c: + Fix bugs in ioctl. + Fix several bugs by distinguishing between MII + and SYM advertising values. + Set CSR14 autonegotiation bit for media types 2 and 4, + where the SIA CSR setup values are not provided. + +2001-05-10 Jeff Garzik + + * media.c (tulip_select_media): Only update MII + advertising value if startup arg < 2. + + * tulip.h: Do not enable CSR13/14/15 autoconfiguration + for 21041. + + * tulip_core.c: + 21041: add specific code for reset, and do not set CAC bit + When resetting media, for media table type 11 media, pass + value 2 as 'startup' arg to select_media, to avoid updating + MII advertising value. + +2001-05-10 Jeff Garzik + + * pnic.c (pnic_check_duplex): remove + pnic.c (pnic_lnk_change, pnic_timer): use + tulip_check_duplex not pnic_check_duplex. + + * media.c (tulip_check_duplex): + Clean up to use symbolic names instead of numeric constants. + Set TxThreshold mode as necessary as well as clearing it. + Update csr6 if csr6 changes, not simply if duplex changes. + + (found by Manfred Spraul) + +2001-05-10 Jeff Garzik + + * 21142.c, eeprom.c, tulip.h, tulip_core.c: + Remove DPRINTK as another, better method of + debug message printing is available. + +2001-05-09 Jeff Garzik + + * 21142.c (t21142_lnk_change): Pass arg startup==1 + to tulip_select_media, in order to force csr13 to be + zeroed out prior to going to full duplex mode. Fixes + autonegotiation on a quad-port Znyx card. + (from Stephen Dengler) + +2001-05-09 Russell King + + * interrupt.c: Better PCI bus error reporting. + 2001-04-03 Jeff Garzik * tulip_core.c: Now that dev->name is only available late @@ -29,7 +208,7 @@ the following defines existed. These defines were never used by normal users in practice: TULIP_FULL_DUPLEX, TULIP_DEFAULT_MEDIA, and TULIP_NO_MEDIA_SWITCH. - + * tulip.h, eeprom.c: Move EE_* constants from tulip.h to eeprom.c. * tulip.h, media.c: Move MDIO_* constants from tulip.h to media.c. diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c --- v2.4.4/linux/drivers/net/tulip/eeprom.c Tue Apr 3 10:19:43 2001 +++ linux/drivers/net/tulip/eeprom.c Wed May 16 10:25:39 2001 @@ -167,7 +167,8 @@ /* there is no phy information, don't even try to build mtable */ if (count == 0) { - DPRINTK("no phy info, aborting mtable build\n"); + if (tulip_debug > 0) + printk(KERN_WARNING "%s: no phy info, aborting mtable build\n", dev->name); return; } @@ -259,7 +260,7 @@ leaf->type); } if (new_advertise) - tp->to_advertise = new_advertise; + tp->sym_advertise = new_advertise; } } /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.4.4/linux/drivers/net/tulip/interrupt.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/tulip/interrupt.c Sun May 20 12:11:38 2001 @@ -15,6 +15,7 @@ */ #include "tulip.h" +#include #include #include @@ -22,6 +23,42 @@ int tulip_rx_copybreak; unsigned int tulip_max_interrupt_work; +#ifdef CONFIG_NET_HW_FLOWCONTROL + +#define MIT_SIZE 15 +unsigned int mit_table[MIT_SIZE+1] = +{ + /* CRS11 21143 hardware Mitigation Control Interrupt + We use only RX mitigation we other techniques for + TX intr. mitigation. + + 31 Cycle Size (timer control) + 30:27 TX timer in 16 * Cycle size + 26:24 TX No pkts before Int. + 23:20 RX timer in Cycle size + 19:17 RX No pkts before Int. + 16 Continues Mode (CM) + */ + + 0x0, /* IM disabled */ + 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ + 0x80150000, + 0x80270000, + 0x80370000, + 0x80490000, + 0x80590000, + 0x80690000, + 0x807B0000, + 0x808B0000, + 0x809D0000, + 0x80AD0000, + 0x80BD0000, + 0x80CF0000, + 0x80DF0000, +// 0x80FF0000 /* RX time = 16, RX pkts = 7, CM = 1 */ + 0x80F10000 /* RX time = 16, RX pkts = 0, CM = 1 */ +}; +#endif int tulip_refill_rx(struct net_device *dev) @@ -70,6 +107,15 @@ int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; int received = 0; +#ifdef CONFIG_NET_HW_FLOWCONTROL + int drop = 0, mit_sel = 0; + +/* that one buffer is needed for mit activation; or might be a + bug in the ring buffer code; check later -- JHS*/ + + if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; +#endif + if (tulip_debug > 4) printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, tp->rx_ring[entry].status); @@ -116,6 +162,12 @@ tp->stats.rx_length_errors++; } #endif + +#ifdef CONFIG_NET_HW_FLOWCONTROL + drop = atomic_read(&netdev_dropping); + if (drop) + goto throttle; +#endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak @@ -157,7 +209,44 @@ tp->rx_buffers[entry].mapping = 0; } skb->protocol = eth_type_trans(skb, dev); +#ifdef CONFIG_NET_HW_FLOWCONTROL + mit_sel = +#endif netif_rx(skb); + +#ifdef CONFIG_NET_HW_FLOWCONTROL + switch (mit_sel) { + case NET_RX_SUCCESS: + case NET_RX_CN_LOW: + case NET_RX_CN_MOD: + break; + + case NET_RX_CN_HIGH: + rx_work_limit -= NET_RX_CN_HIGH; /* additional*/ + break; + case NET_RX_DROP: + rx_work_limit = -1; + break; + default: + printk("unknown feedback return code %d\n", mit_sel); + break; + } + + drop = atomic_read(&netdev_dropping); + if (drop) { +throttle: + rx_work_limit = -1; + mit_sel = NET_RX_DROP; + + if (tp->fc_bit) { + long ioaddr = dev->base_addr; + + /* disable Rx & RxNoBuf ints. */ + outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7); + set_bit(tp->fc_bit, &netdev_fc_xoff); + } + } +#endif dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; @@ -165,8 +254,41 @@ received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } +#ifdef CONFIG_NET_HW_FLOWCONTROL + /* We use this simplistic scheme for IM. It's proven by + real life installations. We can have IM enabled + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. + + We monitor the the device RX-ring and have: + + HW Interrupt Mitigation either ON or OFF. + + ON: More then 1 pkt received (per intr.) OR we are dropping + OFF: Only 1 pkt received + + Note. We only use min and max (0, 15) settings from mit_table */ + + + if( tp->flags & HAS_INTR_MITIGATION) { + if((received > 1 || mit_sel == NET_RX_DROP) + && tp->mit_sel != 15 ) { + tp->mit_sel = 15; + tp->mit_change = 1; /* Force IM change */ + } + if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { + tp->mit_sel = 0; + tp->mit_change = 1; /* Force IM change */ + } + } + + return RX_RING_SIZE+1; /* maxrx+1 */ +#else return received; +#endif } @@ -205,8 +327,22 @@ dev->name, csr5, inl(dev->base_addr + CSR5)); if (csr5 & (RxIntr | RxNoBuf)) { +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit) { + if (test_bit(tp->fc_bit, &netdev_fc_xoff)) { + tulip_refill_rx(dev); + } else { + tulip_refill_rx(dev); + rx += tulip_rx(dev); + } + } else { /* not in fc mode */ + rx += tulip_rx(dev); + tulip_refill_rx(dev); + } +#else rx += tulip_rx(dev); tulip_refill_rx(dev); +#endif } if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { @@ -308,9 +444,17 @@ } } if (csr5 & RxDied) { /* Missed a Rx frame. */ +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) { + tp->stats.rx_errors++; + tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6); + } + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; +#else tp->stats.rx_errors++; tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6); +#endif } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this @@ -344,6 +488,10 @@ if (tulip_debug > 2) printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", dev->name, csr5); +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff))) + if (net_ratelimit()) printk("BUG!! enabling interupt when FC off (timerintr.) \n"); +#endif outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; @@ -356,9 +504,16 @@ /* Acknowledge all interrupt sources. */ outl(0x8001ffff, ioaddr + CSR5); if (tp->flags & HAS_INTR_MITIGATION) { +#ifdef CONFIG_NET_HW_FLOWCONTROL + if(tp->mit_change) { + outl(mit_table[tp->mit_sel], ioaddr + CSR11); + tp->mit_change = 0; + } +#else /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); +#endif } else if (tp->chip_id == LC82C168) { /* the LC82C168 doesn't have a hw timer.*/ outl(0x00, ioaddr + CSR7); @@ -366,8 +521,10 @@ } else { /* Mask all interrupting sources, set timer to re-enable. */ +#ifndef CONFIG_NET_HW_FLOWCONTROL outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); outl(0x0012, ioaddr + CSR11); +#endif } break; } diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.4.4/linux/drivers/net/tulip/media.c Tue Apr 3 10:19:43 2001 +++ linux/drivers/net/tulip/media.c Wed May 16 10:25:39 2001 @@ -14,6 +14,10 @@ */ +#include +#include +#include +#include #include "tulip.h" @@ -228,7 +232,7 @@ outl(csr13val, ioaddr + CSR13); } else { csr13val = 1; - csr14val = 0x0003FF7F; + csr14val = 0x0003FFFF; csr15dir = (setup[0]<<16) | 0x0008; csr15val = (setup[1]<<16) | 0x0008; if (dev->if_port <= 4) @@ -253,8 +257,7 @@ case 1: case 3: { int phy_num = p[0]; int init_length = p[1]; - u16 *misc_info; - u16 to_advertise; + u16 *misc_info, tmp_info; dev->if_port = 11; new_csr6 = 0x020E0000; @@ -281,13 +284,17 @@ for (i = 0; i < init_length; i++) outl(init_sequence[i], ioaddr + CSR12); } - to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; - tp->advertising[phy_num] = to_advertise; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", - dev->name, to_advertise, phy_num, tp->phys[phy_num]); - /* Bogus: put in by a committee? */ - tulip_mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + tmp_info = get_u16(&misc_info[1]); + if (tmp_info) + tp->advertising[phy_num] = tmp_info | 1; + if (tmp_info && startup < 2) { + if (tp->mii_advertise == 0) + tp->mii_advertise = tp->advertising[phy_num]; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on MII %d.\n", + dev->name, tp->mii_advertise, tp->phys[phy_num]); + tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise); + } break; } case 5: case 6: { @@ -397,52 +404,164 @@ } /* - Check the MII negotiated duplex, and change the CSR6 setting if + Check the MII negotiated duplex and change the CSR6 setting if required. Return 0 if everything is OK. Return < 0 if the transceiver is missing or has no link beat. */ int tulip_check_duplex(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int mii_reg1, mii_reg5, negotiated, duplex; + long ioaddr = dev->base_addr; + struct tulip_private *tp = dev->priv; + unsigned int bmsr, lpa, negotiated, new_csr6; - if (tp->full_duplex_lock) - return 0; - mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); - mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); + lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA); if (tulip_debug > 1) printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, mii_reg1, mii_reg5); - if (mii_reg1 == 0xffff) + "%4.4x.\n", dev->name, bmsr, lpa); + if (bmsr == 0xffff) return -2; - if ((mii_reg1 & 0x0004) == 0) { - int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); - if ((new_reg1 & 0x0004) == 0) { + if ((bmsr & BMSR_LSTATUS) == 0) { + int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); + if ((new_bmsr & BMSR_LSTATUS) == 0) { if (tulip_debug > 1) printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_reg1); + " status %4.4x.\n", dev->name, new_bmsr); return -1; } } - negotiated = mii_reg5 & tp->advertising[0]; - duplex = ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040); - /* 100baseTx-FD or 10T-FD, but not 100-HD */ - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - if (negotiated & 0x038) /* 100mbps. */ - tp->csr6 &= ~0x00400000; - if (tp->full_duplex) tp->csr6 |= 0x0200; - else tp->csr6 &= ~0x0200; - tulip_restart_rxtx(tp, tp->csr6); + negotiated = lpa & tp->advertising[0]; + tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated); + + new_csr6 = tp->csr6; + + if (negotiated & LPA_100) new_csr6 &= ~TxThreshold; + else new_csr6 |= TxThreshold; + if (tp->full_duplex) new_csr6 |= FullDuplex; + else new_csr6 &= ~FullDuplex; + + if (new_csr6 != tp->csr6) { + if (inl(ioaddr + CSR6) & (csr6_st | csr6_sr)) + tulip_restart_rxtx(tp, new_csr6); + else + outl(new_csr6, ioaddr + CSR6); + tp->csr6 = new_csr6; + if (tulip_debug > 0) printk(KERN_INFO "%s: Setting %s-duplex based on MII" "#%d link partner capability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); + tp->phys[0], lpa); return 1; } + return 0; } +void __devinit tulip_find_mii (struct net_device *dev, int board_idx) +{ + struct tulip_private *tp = dev->priv; + int phyn, phy_idx = 0; + int mii_reg0; + int mii_advert; + unsigned int to_advert, new_bmcr, ane_switch; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phyn = 1; phyn <= 32 && phy_idx < sizeof (tp->phys); phyn++) { + int phy = phyn & 0x1f; + int mii_status = tulip_mdio_read (dev, phy, MII_BMSR); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & BMSR_100BASE4) == 0 + && (mii_status & 0x7800) != 0)) { + /* preserve Becker logic, gain indentation level */ + } else { + continue; + } + + mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR); + mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE); + ane_switch = 0; + + /* if not advertising at all, gen an + * advertising value from the capability + * bits in BMSR + */ + if ((mii_advert & ADVERTISE_ALL) == 0) { + unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR); + mii_advert = ((tmpadv >> 6) & 0x3e0) | 1; + } + + if (tp->mii_advertise) { + tp->advertising[phy_idx] = + to_advert = tp->mii_advertise; + } else if (tp->advertising[phy_idx]) { + to_advert = tp->advertising[phy_idx]; + } else { + tp->advertising[phy_idx] = + tp->mii_advertise = + to_advert = mii_advert; + } + + tp->phys[phy_idx++] = phy; + + printk (KERN_INFO "tulip%d: MII transceiver #%d " + "config %4.4x status %4.4x advertising %4.4x.\n", + board_idx, phy, mii_reg0, mii_status, mii_advert); + + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != to_advert) { + printk (KERN_DEBUG "tulip%d: Advertising %4.4x on PHY %d," + " previously advertising %4.4x.\n", + board_idx, to_advert, phy, mii_advert); + tulip_mdio_write (dev, phy, 4, to_advert); + } + + /* Enable autonegotiation: some boards default to off. */ + if (tp->default_port == 0) { + new_bmcr = mii_reg0 | BMCR_ANENABLE; + if (new_bmcr != mii_reg0) { + new_bmcr |= BMCR_ANRESTART; + ane_switch = 1; + } + } + /* ...or disable nway, if forcing media */ + else { + new_bmcr = mii_reg0 & ~BMCR_ANENABLE; + if (new_bmcr != mii_reg0) + ane_switch = 1; + } + + /* clear out bits we never want at this point */ + new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE | + BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK | + BMCR_RESET); + + if (tp->full_duplex) + new_bmcr |= BMCR_FULLDPLX; + if (tulip_media_cap[tp->default_port] & MediaIs100) + new_bmcr |= BMCR_SPEED100; + + if (new_bmcr != mii_reg0) { + /* some phys need the ANE switch to + * happen before forced media settings + * will "take." However, we write the + * same value twice in order not to + * confuse the sane phys. + */ + if (ane_switch) { + tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr); + udelay (10); + } + tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printk (KERN_INFO "tulip%d: ***WARNING***: No MII transceiver found!\n", + board_idx); + tp->phys[0] = 1; + } +} diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.4.4/linux/drivers/net/tulip/pnic.c Tue Apr 3 10:19:43 2001 +++ linux/drivers/net/tulip/pnic.c Sat May 19 18:02:45 2001 @@ -51,62 +51,6 @@ } } -/* Modified version of tulip_check_duplex: - * Always update the 100mbps bit, even if the - * full duplex bit didn't change. - * Manfred Spraul - */ -int pnic_check_duplex(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int mii_reg1, mii_reg5, negotiated, duplex; - int new_csr6; - - mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); - mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); - if (tulip_debug > 1) - printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, mii_reg1, mii_reg5); - if (mii_reg1 == 0xffff) - return -2; - if ((mii_reg1 & 0x0004) == 0) { - int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); - if ((new_reg1 & 0x0004) == 0) { - if (tulip_debug > 1) - printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_reg1); - return -1; - } - } - negotiated = mii_reg5 & tp->advertising[0]; - /* 100baseTx-FD or 10T-FD, but not 100-HD */ - duplex = ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040) || - tp->full_duplex_lock; - - new_csr6 = tp->csr6; - if (negotiated & 0x0380) /* 100mbps. */ - new_csr6 &= ~0x00400000; - else - new_csr6 |= 0x00400000; - if (duplex) - new_csr6 |= 0x0200; - else - new_csr6 &= ~0x0200; - if (new_csr6 != tp->csr6) { - tp->full_duplex = duplex; - tp->csr6 = new_csr6; - if (tulip_debug > 0) - printk(KERN_INFO "%s: Setting %s-duplex based on MII" - "#%d link partner capability of %4.4x.\n", - dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); - tulip_restart_rxtx(tp, tp->csr6); - return 1; - } - return 0; -} - void pnic_lnk_change(struct net_device *dev, int csr5) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -133,7 +77,7 @@ } else if (inl(ioaddr + CSR5) & TPLnkPass) { if (tulip_media_cap[dev->if_port] & MediaIsMII) { spin_lock(&tp->lock); - pnic_check_duplex(dev); + tulip_check_duplex(dev); spin_unlock(&tp->lock); } else { pnic_do_nway(dev); @@ -142,8 +86,6 @@ } } -int tulip_refill_rx(struct net_device *dev); - void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -162,7 +104,7 @@ if (tulip_media_cap[dev->if_port] & MediaIsMII) { spin_lock_irq(&tp->lock); - if (pnic_check_duplex(dev) > 0) + if (tulip_check_duplex(dev) > 0) next_tick = 3*HZ; spin_unlock_irq(&tp->lock); } else { diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.4.4/linux/drivers/net/tulip/tulip.h Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/tulip/tulip.h Sun May 20 12:11:38 2001 @@ -16,6 +16,7 @@ #ifndef __NET_TULIP_H__ #define __NET_TULIP_H__ +#include #include #include #include @@ -27,17 +28,7 @@ /* undefine, or define to various debugging levels (>4 == obscene levels) */ -#undef TULIP_DEBUG - - -#ifdef TULIP_DEBUG -/* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - - +#define TULIP_DEBUG 1 struct tulip_chip_table { @@ -62,6 +53,7 @@ IS_ASIX = 0x0200, HAS_8023X = 0x0400, COMET_MAC_ADDR = 0x0800, + HAS_PCI_MWI = 0x1000, }; @@ -83,7 +75,6 @@ COMPEX9881, I21145, DM910X, - CONEXANT, }; @@ -145,8 +136,9 @@ }; -enum tulip_rx_modes { - FullDuplex = 0x0200, +enum tulip_mode_bits { + TxThreshold = (1 << 22), + FullDuplex = (1 << 9), AcceptBroadcast = 0x0100, AcceptAllMulticast = 0x0080, AcceptAllPhys = 0x0040, @@ -154,6 +146,15 @@ }; +enum tulip_busconfig_bits { + MWI = (1 << 24), + MRL = (1 << 23), + MRM = (1 << 21), + CALShift = 14, + BurstLenShift = 8, +}; + + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -184,8 +185,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_cac | csr13_srl), - csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl), + csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_srl), + csr13_mask_10bt = (csr13_eng | csr13_srl), }; enum t21143_csr6_bits { @@ -255,6 +256,18 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#define TULIP_MIN_CACHE_LINE 8 /* in units of 32-bit words */ + +#if defined(__sparc__) || defined(__hppa__) +/* The UltraSparc PCI controllers will disconnect at every 64-byte + * crossing anyways so it makes no sense to tell Tulip to burst + * any more than that. + */ +#define TULIP_MAX_CACHE_LINE 16 /* in units of 32-bit words */ +#else +#define TULIP_MAX_CACHE_LINE 32 /* in units of 32-bit words */ +#endif + /* Ring-wrap flag in length field, use for last ring entry. 0x01000000 means chain on buffer2 address, @@ -333,6 +346,13 @@ spinlock_t mii_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. */ + +#ifdef CONFIG_NET_HW_FLOWCONTROL +#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */ + int fc_bit; + int mit_sel; + int mit_change; /* Signal for Interrupt Mitigtion */ +#endif unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; unsigned int fake_addr:1; /* Multiport board faked address. */ @@ -345,7 +365,7 @@ unsigned int csr6; /* Current CSR6 control settings. */ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ void (*link_change) (struct net_device * dev, int csr5); - u16 to_advertise; /* NWay capabilities advertised. */ + u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */ u16 lpar; /* 21143 Link partner ability. */ u16 advertising[4]; signed char phys[4], mii_cnt; /* MII device addresses. */ @@ -375,6 +395,7 @@ void t21142_timer(unsigned long data); void t21142_start_nway(struct net_device *dev); void t21142_lnk_change(struct net_device *dev, int csr5); +void pnic2_lnk_change(struct net_device *dev, int csr5); /* eeprom.c */ void tulip_parse_eeprom(struct net_device *dev); @@ -384,12 +405,14 @@ extern unsigned int tulip_max_interrupt_work; extern int tulip_rx_copybreak; void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +int tulip_refill_rx(struct net_device *dev); /* media.c */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location); void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value); void tulip_select_media(struct net_device *dev, int startup); int tulip_check_duplex(struct net_device *dev); +void tulip_find_mii (struct net_device *dev, int board_idx); /* pnic.c */ void pnic_do_nway(struct net_device *dev); diff -u --recursive --new-file v2.4.4/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.4/linux/drivers/net/tulip/tulip_core.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/tulip/tulip_core.c Sun May 20 12:11:38 2001 @@ -14,16 +14,24 @@ */ +#define DRV_NAME "tulip" +#define DRV_VERSION "0.9.15-pre2" +#define DRV_RELDATE "May 16, 2001" + +#include #include #include "tulip.h" #include #include #include #include +#include +#include #include +#include static char version[] __devinitdata = - "Linux Tulip driver version 0.9.14e (April 20, 2001)\n"; + "Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; /* A few user-configurable values. */ @@ -100,8 +108,7 @@ MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#define TULIP_MODULE_NAME "tulip" -#define PFX TULIP_MODULE_NAME ": " +#define PFX DRV_NAME ": " #ifdef TULIP_DEBUG int tulip_debug = TULIP_DEBUG; @@ -127,12 +134,12 @@ /* DC21140 */ { "Digital DS21140 Tulip", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer }, /* DC21142, DC21143 */ { "Digital DS21143 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY - | HAS_INTR_MITIGATION, t21142_timer }, + | HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer }, /* LC82C168 */ { "Lite-On 82c168 PNIC", 256, 0x0001fbef, @@ -152,11 +159,12 @@ /* AX88140 */ { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer }, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY + | IS_ASIX, tulip_timer }, /* PNIC2 */ { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer }, + HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, t21142_timer }, /* COMET */ { "ADMtek Comet", 256, 0x0001abef, @@ -168,18 +176,13 @@ /* I21145 */ { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY, - t21142_timer }, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI + | HAS_NWAY | HAS_PCI_MWI, t21142_timer }, /* DM910X */ { "Davicom DM9102/DM9102A", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer }, - - /* CONEXANT */ - { "Conexant LANfinity", 0x100, 0x0001ebef, - HAS_MII | HAS_ACPI, - tulip_timer }, }; @@ -208,7 +211,6 @@ { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT }, { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); @@ -269,8 +271,6 @@ int next_tick = 3*HZ; int i; - DPRINTK("ENTER\n"); - /* Wake the chip from sleep/snooze mode. */ tulip_set_power_state (tp, 0, 0); @@ -379,10 +379,30 @@ tp->csr6 = 0; tp->cur_index = i; tp->nwayset = 0; - if (dev->if_port == 0 && tp->chip_id == DC21041) - tp->nway = 1; - if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (dev->if_port) { + if (tp->chip_id == DC21143 && + (tulip_media_cap[dev->if_port] & MediaIsMII)) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } + tulip_select_media(dev, 1); + } else if (tp->chip_id == DC21041) { + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + tp->csr6 = 0x80020000; + if (tp->sym_advertise & 0x0040) + tp->csr6 |= FullDuplex; + outl(tp->csr6, ioaddr + CSR6); + outl(0x0000EF01, ioaddr + CSR13); + + } else if (tp->chip_id == DC21142) { if (tp->mii_cnt) { tulip_select_media(dev, 1); if (tulip_debug > 1) @@ -424,12 +444,6 @@ tp->csr6 = 0x01a80200; outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); - } else if (tp->chip_id == DC21143 && - tulip_media_cap[dev->if_port] & MediaIsMII) { - /* We must reset the media CSRs when we force-select MII mode. */ - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); } else if (tp->chip_id == COMET) { /* Enable automatic Tx underrun recovery. */ outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88); @@ -464,10 +478,27 @@ add_timer(&tp->timer); } +#ifdef CONFIG_NET_HW_FLOWCONTROL +/* Enable receiver */ +void tulip_xon(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + clear_bit(tp->fc_bit, &netdev_fc_xoff); + if (netif_running(dev)){ + + tulip_refill_rx(dev); + outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); + } +} +#endif static int tulip_open(struct net_device *dev) { +#ifdef CONFIG_NET_HW_FLOWCONTROL + struct tulip_private *tp = (struct tulip_private *)dev->priv; +#endif int retval; MOD_INC_USE_COUNT; @@ -480,6 +511,10 @@ tulip_up (dev); +#ifdef CONFIG_NET_HW_FLOWCONTROL + tp->fc_bit = netdev_register_fc(dev, tulip_xon); +#endif + netif_start_queue (dev); return 0; @@ -492,8 +527,6 @@ long ioaddr = dev->base_addr; unsigned long flags; - DPRINTK("ENTER\n"); - spin_lock_irqsave (&tp->lock, flags); if (tulip_media_cap[dev->if_port] & MediaIsMII) { @@ -549,6 +582,11 @@ printk(KERN_WARNING "%s: transmit timed out, switching to %s " "media.\n", dev->name, medianame[dev->if_port]); } + } else if (tp->chip_id == PNIC2) { + printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, " + "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n", + dev->name, (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR6), + (int)inl(ioaddr + CSR7), (int)inl(ioaddr + CSR12)); } else { printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " "%8.8x, resetting...\n", @@ -584,6 +622,10 @@ #endif /* Stop and restart the chip's Tx processes . */ +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff)) + printk("BUG tx_timeout restarting rx when fc on\n"); +#endif tulip_restart_rxtx(tp, tp->csr6); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -603,8 +645,6 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - DPRINTK("ENTER\n"); - tp->cur_rx = tp->cur_tx = 0; tp->dirty_rx = tp->dirty_tx = 0; tp->susp_rx = 0; @@ -742,6 +782,13 @@ netif_stop_queue (dev); +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (tp->fc_bit) { + int bit = tp->fc_bit; + tp->fc_bit = 0; + netdev_unregister_fc(bit); + } +#endif tulip_down (dev); if (tulip_debug > 1) @@ -803,16 +850,43 @@ } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct tulip_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + strcpy(info.bus_info, np->pdev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + /* Provide ioctl() calls to examine the MII xcvr state. */ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct tulip_private *tp = dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *) & rq->ifr_data; - int phy = tp->phys[0] & 0x1f; + const unsigned int phy_idx = 0; + int phy = tp->phys[phy_idx] & 0x1f; unsigned int regnum = data[1]; switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; @@ -828,26 +902,31 @@ int csr14 = inl (ioaddr + CSR14); switch (regnum) { case 0: - data[3] = (csr14 << 5) & 0x1000; + if (((csr14<<5) & 0x1000) || + (dev->if_port == 5 && tp->nwayset)) + data[3] = 0x1000; + else + data[3] = (tulip_media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0) + | (tulip_media_cap[dev->if_port]&MediaIsFD ? 0x0100 : 0); break; case 1: - data[3] = - 0x7848 + - ((csr12 & 0x7000) == 0x5000 ? 0x20 : 0) + - (csr12 & 0x06 ? 0x04 : 0); + data[3] = + 0x1848 + + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + ((csr12&0x06) == 6 ? 0 : 4); + if (tp->chip_id != DC21041) + data[3] |= 0x6048; break; case 4: - data[3] = - ((csr14 >> 9) & 0x07C0) + - ((inl (ioaddr + CSR6) >> 3) & 0x0040) + - ((csr14 >> 1) & 0x20) + 1; - break; - case 5: - data[3] = csr12 >> 16; - break; - default: - data[3] = 0; + /* Advertised value, bogus 10baseTx-FD value from CSR6. */ + data[3] = + ((inl(ioaddr + CSR6) >> 3) & 0x0040) + + ((csr14 >> 1) & 0x20) + 1; + if (tp->chip_id != DC21041) + data[3] |= ((csr14 >> 9) & 0x03C0); break; + case 5: data[3] = tp->lpar; break; + default: data[3] = 0; break; } } else { data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum); @@ -867,7 +946,8 @@ tp->full_duplex = (value & 0x0100) ? 1 : 0; break; case 4: - tp->to_advertise = data[2]; + tp->advertising[phy_idx] = + tp->mii_advertise = data[2]; break; } } @@ -877,7 +957,7 @@ if ((value & 0x1200) == 0x1200) t21142_start_nway (dev); } else if (regnum == 4) - tp->to_advertise = value; + tp->sym_advertise = value; } else { tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]); } @@ -998,8 +1078,6 @@ long ioaddr = dev->base_addr; int csr6; - DPRINTK("ENTER\n"); - csr6 = inl(ioaddr + CSR6) & ~0x00D5; tp->csr6 &= ~0x00D5; @@ -1119,6 +1197,91 @@ tulip_outl_csr(tp, csr6 | 0x0000, CSR6); } +static void __devinit tulip_mwi_config (struct pci_dev *pdev, + struct net_device *dev) +{ + struct tulip_private *tp = dev->priv; + u8 pci_cacheline; + u16 pci_command, new_command; + unsigned mwi = 1; + + if (tulip_debug > 3) + printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pdev->slot_name); + + /* get a sane cache line size, if possible */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + if (pci_cacheline < (SMP_CACHE_BYTES / 4)) + pci_cacheline = SMP_CACHE_BYTES / 4; + if (pci_cacheline > TULIP_MAX_CACHE_LINE) + pci_cacheline = TULIP_MAX_CACHE_LINE; + switch (pci_cacheline) { + case 8: + case 16: + case 32: break; + default: pci_cacheline = TULIP_MIN_CACHE_LINE; break; + } + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); + + /* read back the result. if zero, or if a buggy chip rev, + * disable MWI + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + if (!pci_cacheline || (tp->chip_id == DC21143 && tp->revision == 65)) + mwi = 0; + + /* re-clamp cache line values to ones supported by tulip */ + /* From this point forward, 'pci_cacheline' is really + * the value used for csr0 cache alignment and + * csr0 programmable burst length + */ + switch (pci_cacheline) { + case 0: + case 8: + case 16: + case 32: break; + default: pci_cacheline = TULIP_MIN_CACHE_LINE; break; + } + + /* set or disable MWI in the standard PCI command bit. + * Check for the case where mwi is desired but not available + */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (mwi) new_command = pci_command | PCI_COMMAND_INVALIDATE; + else new_command = pci_command & ~PCI_COMMAND_INVALIDATE; + if (new_command != pci_command) { + pci_write_config_word(pdev, PCI_COMMAND, new_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if ((new_command != pci_command) && mwi && + ((pci_command & PCI_COMMAND_INVALIDATE) == 0)) + mwi = 0; + } + + tp->csr0 = MRL | MRM; + + /* if no PCI cache line size, bail out with minimal + * burst size and cache alignment of 8 dwords. + * We always want to have some sort of limit. + */ + if (!pci_cacheline) { + tp->csr0 |= (8 << BurstLenShift) | (1 << CALShift); + goto out; + } + + /* finally, build the csr0 value */ + if (mwi) + tp->csr0 |= MWI; + tp->csr0 |= (pci_cacheline << BurstLenShift); + switch (pci_cacheline) { + case 8: tp->csr0 |= (1 << CALShift); + case 16: tp->csr0 |= (2 << CALShift); + case 32: tp->csr0 |= (3 << CALShift); + } + +out: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: MWI config mwi=%d, cacheline=%d, csr0=%08x\n", + pdev->slot_name, mwi, pci_cacheline, tp->csr0); +} static int __devinit tulip_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1136,8 +1299,9 @@ long ioaddr; static int board_idx = -1; int chip_idx = ent->driver_data; - int t2104x_mode = 0; - int eeprom_missing = 0; + unsigned int t2104x_mode = 0; + unsigned int eeprom_missing = 0; + unsigned int force_csr0 = 0; #ifndef MODULE static int did_version; /* Already printed version info. */ @@ -1183,12 +1347,26 @@ thankfully its an old 486 chipset. */ - if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) - csr0 = 0x00A04800; + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) { + csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); + force_csr0 = 1; + } /* The dreaded SiS496 486 chipset. Same workaround as above. */ - if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) - csr0 = 0x00A04800; + if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) { + csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); + force_csr0 = 1; + } + /* bugfix: the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == AX88140) { + if ((csr0 & 0x3f00) == 0) + csr0 |= 0x2000; + } + + /* PNIC doesn't have MWI/MRL/MRM... */ + if (chip_idx == LC82C168) + csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */ + /* * And back to business */ @@ -1255,13 +1433,8 @@ dev->base_addr = ioaddr; dev->irq = irq; - /* bugfix: the ASIX must have a burst limit or horrible things happen. */ - if (chip_idx == AX88140) { - if ((tp->csr0 & 0x3f00) == 0) - tp->csr0 |= 0x2000; - } - else if (chip_idx == DC21143 && chip_rev == 65) - tp->csr0 &= ~0x01000000; + if (!force_csr0 && (tp->flags & HAS_PCI_MWI)) + tulip_mwi_config (pdev, dev); /* Stop the chip's Tx and Rx processes. */ tulip_stop_rxtx(tp, inl(ioaddr + CSR6)); @@ -1373,8 +1546,8 @@ if (dev->mem_start & MEDIA_MASK) tp->default_port = dev->mem_start & MEDIA_MASK; if (tp->default_port) { - printk(KERN_INFO "%s: Transceiver selection forced to %s.\n", - pdev->slot_name, medianame[tp->default_port & MEDIA_MASK]); + printk(KERN_INFO "tulip%d: Transceiver selection forced to %s.\n", + board_idx, medianame[tp->default_port & MEDIA_MASK]); tp->medialock = 1; if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) tp->full_duplex = 1; @@ -1384,11 +1557,9 @@ if (tulip_media_cap[tp->default_port] & MediaIsMII) { u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; - tp->to_advertise = media2advert[tp->default_port - 9]; - } else if (tp->flags & HAS_8023X) - tp->to_advertise = 0x05e1; - else - tp->to_advertise = 0x01e1; + tp->mii_advertise = media2advert[tp->default_port - 9]; + tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */ + } if (tp->flags & HAS_MEDIA_TABLE) { memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); @@ -1401,55 +1572,21 @@ if ((tp->flags & ALWAYS_CHECK_MII) || (tp->mtable && tp->mtable->has_mii) || ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phyn, phy_idx = 0; if (tp->mtable && tp->mtable->has_mii) { for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == 11) { tp->cur_index = i; tp->saved_if_port = dev->if_port; - tulip_select_media(dev, 1); + tulip_select_media(dev, 2); dev->if_port = tp->saved_if_port; break; } } + /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, - but takes much time. */ - for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) { - int phy = phyn & 0x1f; - int mii_status = tulip_mdio_read(dev, phy, 1); - if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { - int mii_reg0 = tulip_mdio_read(dev, phy, 0); - int mii_advert = tulip_mdio_read(dev, phy, 4); - int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; - tp->phys[phy_idx] = phy; - tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " - "config %4.4x status %4.4x advertising %4.4x.\n", - pdev->slot_name, phy, mii_reg0, mii_status, mii_advert); - /* Fixup for DLink with miswired PHY. */ - if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," - " previously advertising %4.4x.\n", - pdev->slot_name, reg4, phy, mii_advert); - printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" - " is %4.4x).\n", - pdev->slot_name, reg4, tp->to_advertise); - tulip_mdio_write(dev, phy, 4, reg4); - } - /* Enable autonegotiation: some boards default to off. */ - tulip_mdio_write(dev, phy, 0, mii_reg0 | - (tp->full_duplex ? 0x1100 : 0x1000) | - (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); - } - } - tp->mii_cnt = phy_idx; - if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - pdev->slot_name); - tp->phys[0] = 1; - } + Doing this in open() would allow detecting external xcvrs + later, but takes much time. */ + tulip_find_mii (dev, board_idx); } /* The Tulip-specific entries in the device structure. */ @@ -1481,18 +1618,21 @@ if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) tp->link_change = t21142_lnk_change; + else if (tp->chip_id == PNIC2) + tp->link_change = pnic2_lnk_change; else if (tp->flags & HAS_PNICNWAY) tp->link_change = pnic_lnk_change; /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_idx) { case DC21041: - tp->to_advertise = 0x0061; + if (tp->sym_advertise == 0) + tp->sym_advertise = 0x0061; outl(0x00000000, ioaddr + CSR13); outl(0xFFFFFFFF, ioaddr + CSR14); outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ tulip_outl_csr(tp, inl(ioaddr + CSR6) | csr6_fd, CSR6); - outl(0x0000EF05, ioaddr + CSR13); + outl(0x0000EF01, ioaddr + CSR13); break; case DC21040: outl(0x00000000, ioaddr + CSR13); @@ -1552,7 +1692,6 @@ err_out_free_res: pci_release_regions (pdev); err_out_free_netdev: - unregister_netdev (dev); kfree (dev); return -ENODEV; } @@ -1610,7 +1749,7 @@ static struct pci_driver tulip_driver = { - name: TULIP_MODULE_NAME, + name: DRV_NAME, id_table: tulip_pci_tbl, probe: tulip_init_one, remove: tulip_remove_one, diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/comx-hw-comx.c linux/drivers/net/wan/comx-hw-comx.c --- v2.4.4/linux/drivers/net/wan/comx-hw-comx.c Mon Oct 2 12:00:16 2000 +++ linux/drivers/net/wan/comx-hw-comx.c Tue May 22 10:23:16 2001 @@ -1044,10 +1044,20 @@ if (!(page = (char *)__get_free_page(GFP_KERNEL))) { return -ENOMEM; } - copy_from_user(page, buffer, count = (min(count, PAGE_SIZE))); - if (*(page + count - 1) == '\n') { - *(page + count - 1) = 0; + if(copy_from_user(page, buffer, count = (min(count, PAGE_SIZE)))) + { + count = -EFAULT; + goto out; + } + if (page[count-1] == '\n') + page[count-1] = '\0'; + else if (count < PAGE_SIZE) + page[count] = '\0'; + else if (page[count]) { + count = -EINVAL; + goto out; } + page[count]=0; /* Null terminate */ } else { byte *tmp; @@ -1140,7 +1150,7 @@ hw->clock = kbps ? COMX_CLOCK_CONST/kbps : 0; } } - +out: free_page((unsigned long)page); return count; } diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c --- v2.4.4/linux/drivers/net/wan/comx.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/comx.c Tue May 22 10:23:16 2001 @@ -621,9 +621,20 @@ if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; - copy_from_user(page, buffer, count); + if(copy_from_user(page, buffer, count)) + { + count = -EFAULT; + goto out; + } - if (*(page + count - 1) == '\n') *(page + count - 1) = 0; + if (page[count-1] == '\n') + page[count-1] = '\0'; + else if (count < PAGE_SIZE) + page[count] = '\0'; + else if (page[count]) { + count = -EINVAL; + goto out; + } if (strcmp(entry->name, FILENAME_DEBUG) == 0) { int i; @@ -764,7 +775,7 @@ } } } - +out: free_page((unsigned long)page); return count; } diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c --- v2.4.4/linux/drivers/net/wan/cycx_main.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/wan/cycx_main.c Tue May 22 10:23:16 2001 @@ -3,7 +3,7 @@ * * Author: Arnaldo Carvalho de Melo * -* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo +* Copyright: (c) 1998-2001 Arnaldo Carvalho de Melo * * Based on sdlamain.c by Gene Kozin & * Jaspreet Singh @@ -13,8 +13,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2001/05/09 acme Fix MODULE_DESC for debug, .bss nitpicks, +* some cleanups * 2000/07/13 acme remove useless #ifdef MODULE and crap -* #if KERNEL_VERSION > blah +* #if KERNEL_VERSION > blah * 2000/07/06 acme __exit at cyclomx_cleanup * 2000/04/02 acme dprintk and cycx_debug * module_init/module_exit @@ -38,7 +40,7 @@ #include /* offsetof(), etc. */ #include /* return codes */ #include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ +#include /* kmalloc(), kfree() */ #include /* printk(), and other useful stuff */ #include /* support for loadable modules */ #include /* request_region(), release_region() */ @@ -50,17 +52,17 @@ /* Debug */ -unsigned int cycx_debug = 0; +unsigned int cycx_debug; MODULE_AUTHOR("Arnaldo Carvalho de Melo"); MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver."); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "cyclomx debug level"); +MODULE_PARM(cycx_debug, "i"); +MODULE_PARM_DESC(cycx_debug, "cyclomx debug level"); /* Defines & Macros */ #define DRV_VERSION 0 /* version number */ -#define DRV_RELEASE 9 /* release (minor version) number */ +#define DRV_RELEASE 10 /* release (minor version) number */ #define MAX_CARDS 1 /* max number of adapters */ #define CONFIG_CYCLOMX_CARDS 1 @@ -82,10 +84,10 @@ /* private data */ static char drvname[] = "cyclomx"; static char fullname[] = "CYCLOM 2X(tm) Sync Card Driver"; -static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo " +static char copyright[] = "(c) 1998-2001 Arnaldo Carvalho de Melo " ""; static int ncards = CONFIG_CYCLOMX_CARDS; -static cycx_t *card_array = NULL; /* adapter data space */ +static cycx_t *card_array; /* adapter data space */ /* Kernel Loadable Module Entry Points */ @@ -103,7 +105,7 @@ */ int __init cyclomx_init (void) { - int cnt, err = 0; + int cnt, err = -ENOMEM; printk(KERN_INFO "%s v%u.%u %s\n", fullname, DRV_VERSION, DRV_RELEASE, copyright); @@ -112,9 +114,8 @@ ncards = min(ncards, MAX_CARDS); ncards = max(ncards, 1); card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL); - if (!card_array) - return -ENOMEM; + goto out; memset(card_array, 0, sizeof(cycx_t) * ncards); @@ -127,9 +128,9 @@ wandev->magic = ROUTER_MAGIC; wandev->name = card->devname; wandev->private = card; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; + wandev->setup = setup; + wandev->shutdown = shutdown; + wandev->ioctl = ioctl; err = register_wan_device(wandev); if (err) { @@ -140,14 +141,14 @@ } } - if (cnt) - ncards = cnt; /* adjust actual number of cards */ - else { + err = -ENODEV; + if (!cnt) { kfree(card_array); - err = -ENODEV; + goto out; } - - return err; + err = 0; + ncards = cnt; /* adjust actual number of cards */ +out: return err; } /* @@ -182,29 +183,31 @@ */ static int setup (wan_device_t *wandev, wandev_conf_t *conf) { + int err = -EFAULT; cycx_t *card; - int err = 0; int irq; /* Sanity checks */ + if (!wandev || !wandev->private || !conf) - return -EFAULT; + goto out; card = wandev->private; - + err = -EBUSY; if (wandev->state != WAN_UNCONFIGURED) - return -EBUSY; + goto out; + err = -EINVAL; if (!conf->data_size || !conf->data) { printk(KERN_ERR "%s: firmware not found in configuration " "data!\n", wandev->name); - return -EINVAL; + goto out; } if (conf->irq <= 0) { printk(KERN_ERR "%s: can't configure without IRQ!\n", wandev->name); - return -EINVAL; + goto out; } /* Allocate IRQ */ @@ -213,23 +216,21 @@ if (request_irq(irq, cycx_isr, 0, wandev->name, card)) { printk(KERN_ERR "%s: can't reserve IRQ %d!\n", wandev->name, irq); - return -EINVAL; + goto out; } /* Configure hardware, load firmware, etc. */ memset(&card->hw, 0, sizeof(cycxhw_t)); - card->hw.irq = irq; + card->hw.irq = irq; card->hw.dpmbase = conf->maddr; card->hw.dpmsize = CYCX_WINDOWSIZE; - card->hw.fwid = CFID_X25_2X; - card->lock = SPIN_LOCK_UNLOCKED; + card->hw.fwid = CFID_X25_2X; + card->lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&card->wait_stats); - err = cycx_setup(&card->hw, conf->data, conf->data_size); - if (err) { - free_irq(irq, card); - return err; - } + err = cycx_setup(&card->hw, conf->data, conf->data_size); + if (err) + goto out_irq; /* Initialize WAN device data space */ wandev->irq = irq; @@ -254,11 +255,14 @@ if (err) { cycx_down(&card->hw); - free_irq(irq, card); - return err; + goto out_irq; } - return 0; + err = 0; +out: return err; +out_irq: + free_irq(irq, card); + goto out; } /* @@ -271,14 +275,16 @@ */ static int shutdown (wan_device_t *wandev) { + int ret = -EFAULT; cycx_t *card; /* sanity checks */ if (!wandev || !wandev->private) - return -EFAULT; + goto out; + ret = 0; if (wandev->state == WAN_UNCONFIGURED) - return 0; + goto out; card = wandev->private; wandev->state = WAN_UNCONFIGURED; @@ -286,8 +292,7 @@ printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name, wandev->irq); free_irq(wandev->irq, card); - - return 0; +out: return ret; } /* @@ -313,19 +318,20 @@ */ static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs) { -#define card ((cycx_t*)dev_id) + cycx_t *card = (cycx_t *)dev_id; + if (!card || card->wandev.state == WAN_UNCONFIGURED) - return; + goto out; if (card->in_isr) { printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", card->devname, card->wandev.irq); - return; + goto out; } if (card->isr) card->isr(card); -#undef card +out: return; } /* @@ -355,10 +361,10 @@ /* Set WAN device state. */ void cyclomx_set_state (cycx_t *card, int state) { - unsigned long host_cpu_flags; + unsigned long flags; char *string_state = NULL; - spin_lock_irqsave(&card->lock, host_cpu_flags); + spin_lock_irqsave(&card->lock, flags); if (card->wandev.state != state) { switch (state) { @@ -376,10 +382,8 @@ } card->state_tick = jiffies; - spin_unlock_irqrestore(&card->lock, host_cpu_flags); + spin_unlock_irqrestore(&card->lock, flags); } module_init(cyclomx_init); module_exit(cyclomx_cleanup); - -/* End */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.4.4/linux/drivers/net/wan/sdla_ppp.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/wan/sdla_ppp.c Sun May 20 12:11:39 2001 @@ -115,7 +115,6 @@ #endif #include -#include #include /* PPP firmware API definitions */ #include /* S514 Type Definition */ /****** Defines & Macros ****************************************************/ diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.4.4/linux/drivers/net/wan/sdladrv.c Thu Apr 12 12:11:39 2001 +++ linux/drivers/net/wan/sdladrv.c Sun May 20 12:11:39 2001 @@ -90,6 +90,7 @@ #if defined(_LINUX_) /****** Linux *******************************/ +#include #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.4.4/linux/drivers/net/wan/syncppp.c Wed Apr 18 14:40:07 2001 +++ linux/drivers/net/wan/syncppp.c Tue May 22 10:23:16 2001 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -128,7 +129,7 @@ static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; -static spinlock_t spppq_lock; +static spinlock_t spppq_lock = SPIN_LOCK_UNLOCKED; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, @@ -975,6 +976,14 @@ if(ifr->ifr_flags) sp->pp_flags|=PP_DEBUG; break; + case SPPPIOCGFLAGS: + if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) + return -EFAULT; + break; + case SPPPIOCSFLAGS: + if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) + return -EFAULT; + break; default: return -EINVAL; } @@ -1397,7 +1406,6 @@ debug=PP_DEBUG; printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); - spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); return 0; diff -u --recursive --new-file v2.4.4/linux/drivers/net/wan/wanpipe_multppp.c linux/drivers/net/wan/wanpipe_multppp.c --- v2.4.4/linux/drivers/net/wan/wanpipe_multppp.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/wan/wanpipe_multppp.c Tue May 22 10:23:16 2001 @@ -599,6 +599,18 @@ chdlc_priv_area->if_ptr = pppdev; /* prepare network device data space for registration */ + +#ifdef LINUX_2_4 + strcpy(dev->name,card->u.c.if_name); +#else + dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); + if(dev->name == NULL) + { + kfree(chdlc_priv_area); + return -ENOMEM; + } + sprintf(dev->name, "%s", card->u.c.if_name); +#endif /* Attach PPP protocol layer to pppdev * The sppp_attach() will initilize the dev structure @@ -607,24 +619,17 @@ * if_open(), if_close(), if_send() and get_stats() functions. */ sppp_attach(pppdev); - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) dev = pppdev->dev; - #else +#else dev = &pppdev->dev; - #endif +#endif sp = &pppdev->sppp; /* Enable PPP Debugging */ // FIXME Fix this up somehow //sp->pp_flags |= PP_DEBUG; sp->pp_flags &= ~PP_CISCO; - - #ifdef LINUX_2_4 - strcpy(dev->name,card->u.c.if_name); - #else - dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); - sprintf(dev->name, "%s", card->u.c.if_name); - #endif dev->init = &if_init; dev->priv = chdlc_priv_area; @@ -678,9 +683,9 @@ chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; wan_device_t* wandev = &card->wandev; - #ifdef LINUX_2_0 +#ifdef LINUX_2_0 int i; - #endif +#endif /* NOTE: Most of the dev initialization was * done in sppp_attach(), called by new_if() @@ -693,15 +698,15 @@ dev->stop = &if_close; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; - #ifdef LINUX_2_4 +#ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - #endif +#endif - #ifdef LINUX_2_0 +#ifdef LINUX_2_0 dev->family = AF_INET; - #endif +#endif /* Initialize hardware parameters */ dev->irq = wandev->irq; @@ -719,10 +724,10 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ - #if !defined(LINUX_2_1) && !defined(LINUX_2_4) +#if !defined(LINUX_2_1) && !defined(LINUX_2_4) for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]); - #endif +#endif return 0; } @@ -768,13 +773,13 @@ /* Only one open per interface is allowed */ - #ifdef LINUX_2_4 +#ifdef LINUX_2_4 if (netif_running(dev)) return -EBUSY; - #else +#else if (dev->start) return -EBUSY; /* only one open is allowed */ - #endif +#endif /* Start PPP Layer */ if (sppp_open(dev)){ @@ -784,13 +789,13 @@ do_gettimeofday(&tv); chdlc_priv_area->router_start_time = tv.tv_sec; - #ifdef LINUX_2_4 +#ifdef LINUX_2_4 netif_start_queue(dev); - #else +#else dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - #endif +#endif wanpipe_open(card); @@ -813,9 +818,9 @@ sppp_close(dev); stop_net_queue(dev); - #ifndef LINUX_2_4 +#ifndef LINUX_2_4 dev->start=0; - #endif +#endif wanpipe_close(card); @@ -849,9 +854,9 @@ unsigned long smp_flags; int err=0; - #ifdef LINUX_2_4 +#ifdef LINUX_2_4 netif_stop_queue(dev); - #endif +#endif if (skb == NULL){ @@ -865,7 +870,7 @@ return 0; } - #ifndef LINUX_2_4 +#ifndef LINUX_2_4 if (dev->tbusy){ /* If our device stays busy for at least 5 seconds then we will @@ -885,7 +890,7 @@ /* unbusy the interface */ dev->tbusy = 0; } - #endif +#endif if (ntohs(skb->protocol) != htons(PVC_PROT)){ /* check the udp packet type */ @@ -927,12 +932,12 @@ }else{ ++card->wandev.stats.tx_packets; - #if defined(LINUX_2_1) || defined(LINUX_2_4) +#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += skb->len; - #endif - #ifdef LINUX_2_4 +#endif +#ifdef LINUX_2_4 dev->trans_start = jiffies; - #endif +#endif start_net_queue(dev); } @@ -1499,15 +1504,15 @@ goto rx_exit; } - #ifdef LINUX_2_4 +#ifdef LINUX_2_4 if (!netif_running(dev)){ goto rx_exit; } - #else +#else if (!dev->start){ goto rx_exit; } - #endif +#endif chdlc_priv_area = dev->priv; @@ -2352,28 +2357,28 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) { - #if defined(__SMP__) || defined(LINUX_2_4) +#if defined(__SMP__) || defined(LINUX_2_4) spin_lock_irqsave(&card->wandev.lock, *smp_flags); if (card->next){ /* It is ok to use spin_lock here, since we * already turned off interrupts */ spin_lock(&card->next->wandev.lock); } - #else +#else disable_irq(card->hw.irq); - #endif +#endif } void s508_unlock (sdla_t *card, unsigned long *smp_flags) { - #if defined(__SMP__) || defined(LINUX_2_4) +#if defined(__SMP__) || defined(LINUX_2_4) if (card->next){ spin_unlock(&card->next->wandev.lock); } spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); - #else +#else enable_irq(card->hw.irq); - #endif +#endif } diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/Config.in linux/drivers/net/wireless/Config.in --- v2.4.4/linux/drivers/net/wireless/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/Config.in Mon May 7 19:42:14 2001 @@ -0,0 +1,22 @@ +# +# Wireless LAN device configuration +# + +###tristate ' Hermes chipset support' CONFIG_NET_ORINOCO +###dep_tristate ' PCMCIA Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_NET_ORINOCO $CONFIG_PCMCIA + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + tristate ' Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT +fi + +# If Pcmcia is compiled in, offer Pcmcia cards... +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + comment 'Wireless Pcmcia cards support' + + dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA + +# If one of the Pcmcia cards above is enabled, activate Pcmcia network support + if [ "$CONFIG_PCMCIA_HERMES" = "y" ]; then + define_bool CONFIG_PCMCIA_NETCARD y + fi +fi diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/Makefile linux/drivers/net/wireless/Makefile --- v2.4.4/linux/drivers/net/wireless/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/Makefile Mon May 7 19:42:14 2001 @@ -0,0 +1,27 @@ +# +# drivers/net/wireless/Makefile +# +# Makefile for the Linux Wireless network device drivers. +# + +O_TARGET := orinoco_drvs.o + +obj-y := +obj-m := +obj-n := +obj- := + +# Things that need to export symbols +export-objs := orinoco.o hermes.o + +# ISA Bus cards + +# PCI bus cards + +# Other cards +obj-$(CONFIG_APPLE_AIRPORT) += airport.o orinoco.o hermes.o + +# 16-bit Pcmcia wireless client drivers +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o orinoco.o hermes.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/README linux/drivers/net/wireless/README --- v2.4.4/linux/drivers/net/wireless/README Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/README Mon May 7 19:42:14 2001 @@ -0,0 +1,25 @@ + README + ------ + + This directory is mostly for Wireless LAN drivers, in their +various incarnations (ISA, PCI, Pcmcia...). + This separate directory is needed because a lot of driver work +on different bus (typically PCI + Pcmcia) and share 95% of the +code. This allow the code and the config options to be in one single +place instead of scattered all over the driver tree, which is never +100% satisfactory. + + Note : if you want more info on the topic of Wireless LANs, +you are kindly invited to have a look at the Wireless Howto : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + Some Wireless LAN drivers, like orinoco_cs, require the use of +Wireless Tools to be configured : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + + Special notes for distribution maintainers : + 1) wvlan_cs will be discontinued soon in favor of orinoco_cs + 2) Please add Wireless Tools support in your scripts + + Have fun... + + Jean diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c --- v2.4.4/linux/drivers/net/wireless/airport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/airport.c Mon May 7 19:42:14 2001 @@ -0,0 +1,270 @@ +/* airport.c 0.05 + * + * A driver for "Hermes" chipset based Apple Airport wireless + * card. + * + * Copyright notice & release notes in file orinoco.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hermes.h" +#include "orinoco.h" + +typedef struct dldwd_card { + struct device_node* node; + int irq_requested; + int ndev_registered; + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "airport.c 0.05 (Benjamin Herrenschmidt )"; + +/* + * 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 int airport_open(struct net_device *dev); +static int airport_stop(struct net_device *dev); + +/* + A linked list of "instances" of the dummy device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + 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; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + int rc; + + TRACE_ENTER(priv->ndev.name); + + MOD_INC_USE_COUNT; + + feature_set_airport_power(card->node, 1); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + rc = dldwd_init(dev); + if (rc) { + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + priv->hw_ready = 1; + + MOD_DEC_USE_COUNT; + + return rc; +} + +static int +airport_open(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + int rc; + + TRACE_ENTER(priv->ndev.name); + + netif_device_attach(dev); + rc = dldwd_reset(priv); + if (rc) + airport_stop(dev); + else + 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; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +static dldwd_priv_t* +airport_attach(struct device_node* of_node) +{ + dldwd_priv_t *priv; + struct net_device *ndev; + dldwd_card_t* card; + hermes_t *hw; + + TRACE_ENTER("dldwd"); + + if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { + printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); + return NULL; + } + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + printk(KERN_ERR "airport: can't allocate device datas\n"); + return NULL; + } + memset(card, 0, sizeof(*card)); + + priv = &(card->priv); + priv->card = card; + ndev = &priv->ndev; + hw = &priv->hw; + card->node = of_node; + + /* Setup the common part */ + if (dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->init = airport_init; + ndev->open = airport_open; + ndev->stop = airport_stop; + + /* Setup interrupts & base address */ + ndev->irq = of_node->intrs[0].line; + ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE; + + hermes_struct_init(hw, ndev->base_addr); + + if (request_irq(ndev->irq, dldwd_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"); + goto failed; + } + printk(KERN_INFO "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) + printk(KERN_ERR "airport: Failed to create /proc node for %s\n", + ndev->name); + + return priv; + +failed: + airport_detach(priv); + return NULL; +} /* airport_attach */ + +/*====================================================================== + This deletes a driver "instance". + ======================================================================*/ + +static void +airport_detach(dldwd_priv_t *priv) +{ + dldwd_card_t* card = (dldwd_card_t *)priv->card; + + priv->hw_ready = 0; + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + if (card->ndev_registered) + unregister_netdev(&priv->ndev); + card->ndev_registered = 0; + + if (card->irq_requested) + 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; + + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + kfree(card); +} /* airport_detach */ + +static int __init +init_airport(void) +{ + struct device_node* airport_node; + + printk(KERN_INFO "%s\n", version); + + MOD_INC_USE_COUNT; + + /* Lookup card in device tree */ + airport_node = find_devices("radio"); + if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) + airport_dev = airport_attach(airport_node); + + MOD_DEC_USE_COUNT; + + return airport_dev ? 0 : -ENODEV; +} + +static void __exit +exit_airport(void) +{ + if (airport_dev) + airport_detach(airport_dev); + airport_dev = NULL; +} + +MODULE_DESCRIPTION("Apple Airport driver"); + +module_init(init_airport); +module_exit(exit_airport); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/hermes.c linux/drivers/net/wireless/hermes.c --- v2.4.4/linux/drivers/net/wireless/hermes.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/hermes.c Mon May 7 19:42:14 2001 @@ -0,0 +1,502 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * This file distributed under the GPL, version 2. + */ + +static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" + +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +/* + * Debugging helpers + */ + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG + +#include + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ + printk(#stuff);} while (0) + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + +/* + * Prototypes + */ + +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); + +/* + * Internal inline functions + */ + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) +{ + uint16_t reg; +/* unsigned long k = CMD_BUSY_TIMEOUT; */ + + /* First check that the command register is not busy */ + reg = hermes_read_regn(hw, CMD); + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, 0); + hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +void hermes_struct_init(hermes_t *hw, uint io) +{ + hw->iobase = io; + hw->inten = 0x0; +} + +int hermes_reset(hermes_t *hw) +{ + uint16_t status, reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Because we hope we can reset the card even if it gets into + a stupid state, we actually wait to see if the command + register will unbusy itself */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - hermes_issue_cmd() will + probably return -EBUSY */ + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (! hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = status & HERMES_STATUS_RESULT; + + out: + return err; +} + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) +{ + int err; + int k; + uint16_t reg; + + err = hermes_issue_cmd(hw, cmd, parm0); + if (err) { + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", + hw->iobase); + err = -ENODEV; + } else + printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", + hw->iobase); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", + hw->iobase); + err = -ETIMEDOUT; + goto out; + } + + resp->status = hermes_read_regn(hw, STATUS); + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = resp->status & HERMES_STATUS_RESULT; + + out: + return err; +} + +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) +{ + int err = 0; + hermes_response_t resp; + int k; + uint16_t reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); + if (err) { + printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", + hw->iobase, err); + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + int l = BAP_ERROR_RETRY; + uint16_t reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + + if (reg & HERMES_OFFSET_BUSY) + return -EBUSY; + + /* Now we actually set up the transfer */ + retry: + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* For some reason, seeking the BAP seems to randomly fail somewhere + (firmware bug?). We retry a few times before giving up. */ + if (reg & HERMES_OFFSET_ERR) { + if (l--) { + udelay(1); + goto retry; + } else + return -EIO; + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + uint16_t rlength, rtype; + hermes_response_t resp; + int count; + + if (buflen % 2) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); + if (err) + goto out; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + rlength = hermes_read_reg(hw, dreg); + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " + "not match type (0x%04x)\n", rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) + printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); + + /* For now we always read the whole buffer, the + lengths in the records seem to be wrong, frequently */ + count = buflen / 2; + +#if 0 + if (length) + count = (MIN(buflen, rlength) + 1) / 2; + else { + count = buflen / 2; + if (rlength != buflen) + printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ +record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); + } +#endif + hermes_read_data(hw, dreg, buf, count); + + out: + return err; +} + +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + hermes_response_t resp; + int count; + + DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", + bap, rid, length, * ((uint16_t *)value)); + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_data(hw, dreg, value, count); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, &resp); + + out: + return err; +} + +EXPORT_SYMBOL(hermes_struct_init); +EXPORT_SYMBOL(hermes_reset); +EXPORT_SYMBOL(hermes_docmd_wait); +EXPORT_SYMBOL(hermes_allocate); + +EXPORT_SYMBOL(hermes_bap_pread); +EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_read_ltv); +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + printk(KERN_INFO "%s\n", version); + + return 0; +} + +module_init(init_hermes); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/hermes.h linux/drivers/net/wireless/hermes.h --- v2.4.4/linux/drivers/net/wireless/hermes.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/hermes.h Mon May 7 19:42:14 2001 @@ -0,0 +1,402 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include +#include + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN (4) +#define HERMES_ALLOC_LEN_MAX (2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX (4096) +#define HERMES_BAP_OFFSET_MAX (4096) +#define HERMES_PORTID_MAX (7) +#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) +#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX (200) /* a guess */ +#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX (35) +#define HERMES_CHINFORESULT_MAX (8) +#define HERMES_FRAME_LEN_MAX (2304) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY (0x8000) +#define HERMES_CMD_AINFO (0x7f00) +#define HERMES_CMD_MACPORT (0x0700) +#define HERMES_CMD_RECL (0x0100) +#define HERMES_CMD_WRITE (0x0100) +#define HERMES_CMD_PROGMODE (0x0300) +#define HERMES_CMD_CMDCODE (0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT (0x7f00) +#define HERMES_STATUS_CMDCODE (0x003f) + +/* + * OFFSET refister bitmasks + */ +#define HERMES_OFFSET_BUSY (0x8000) +#define HERMES_OFFSET_ERR (0x4000) +#define HERMES_OFFSET_DATAOFF (0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK (0x8000) +#define HERMES_EV_WTERR (0x4000) +#define HERMES_EV_INFDROP (0x2000) +#define HERMES_EV_INFO (0x0080) +#define HERMES_EV_DTIM (0x0020) +#define HERMES_EV_CMD (0x0010) +#define HERMES_EV_ALLOC (0x0008) +#define HERMES_EV_TXEXC (0x0004) +#define HERMES_EV_TX (0x0002) +#define HERMES_EV_RX (0x0001) + +/* + * Command codes + */ +/*--- Controller Commands --------------------------*/ +#define HERMES_CMD_INIT (0x0000) +#define HERMES_CMD_ENABLE (0x0001) +#define HERMES_CMD_DISABLE (0x0002) +#define HERMES_CMD_DIAG (0x0003) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HERMES_CMD_ALLOC (0x000A) +#define HERMES_CMD_TX (0x000B) +#define HERMES_CMD_CLRPRST (0x0012) + +/*--- Regulate Commands --------------------------*/ +#define HERMES_CMD_NOTIFY (0x0010) +#define HERMES_CMD_INQ (0x0011) + +/*--- Configure Commands --------------------------*/ +#define HERMES_CMD_ACCESS (0x0021) +#define HERMES_CMD_DOWNLD (0x0022) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_MONITOR (0x0038) +#define HERMES_MONITOR_ENABLE (0x000b) +#define HERMES_MONITOR_DISABLE (0x000f) + +/* + * Configuration RIDs + */ + +#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_PRISM2_WEP_ON (0xfc28) +#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_PRISM2_TX_KEY (0xfc23) +#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) +#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) +#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) +#define HERMES_RID_CNF_PRISM2_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_PRIMARY_VER (0xfd03) +#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) +#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) + +/* + * Frame structures and constants + */ + +typedef struct hermes_frame_desc { + /* Hermes - i.e. little-endian byte-order */ + uint16_t status; /* 0x0 */ + uint16_t res1, res2; /* 0x2, 0x4 */ + uint16_t q_info; /* 0x6 */ + uint16_t res3, res4; /* 0x8, 0xA */ + uint16_t tx_ctl; /* 0xC */ +} __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) + +#ifdef __KERNEL__ + +/* Basic control structure */ +typedef struct hermes { + uint iobase; + + uint16_t inten; /* Which interrupts should be enabled? */ +} hermes_t; + +typedef struct hermes_response { + uint16_t status, resp0, resp1, resp2; +} hermes_response_t; + +/* Firmware information structure */ +typedef struct hermes_identity { + uint16_t id, vendor, major, minor; +} __attribute__ ((packed)) hermes_identity_t; + +/* "ID" structure - used for ESSID and station nickname */ +typedef struct hermes_id { + uint16_t len; + uint16_t val[16]; +} __attribute__ ((packed)) hermes_id_t; + +typedef struct hermes_commsqual { + uint16_t qual, signal, noise; +} __attribute__ ((packed)) hermes_commsqual_t; + +typedef struct hermes_multicast { + uint8_t 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))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, uint io); +int hermes_reset(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); + + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) +{ + hw->inten |= events; + hermes_write_regn(hw, INTEN, hw->inten); +} + +static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) +{ + uint16_t rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) +{ + uint16_t rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->id); + le16_to_cpus(&buf->vendor); + le16_to_cpus(&buf->major); + le16_to_cpus(&buf->minor); + + return 0; +} + +static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->qual); + le16_to_cpus(&buf->signal); + le16_to_cpus(&buf->noise); + + return 0; +} + +#else /* ! __KERNEL__ */ + +/* These are provided for the benefit of userspace drivers and testing programs + which use ioperm() or iopl() */ + +#define hermes_read_reg(base, off) (inw((base) + (off))) +#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) + +#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) +#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) +#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) + +#endif /* ! __KERNEL__ */ + +#endif /* _HERMES_H */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco.c linux/drivers/net/wireless/orinoco.c --- v2.4.4/linux/drivers/net/wireless/orinoco.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco.c Mon May 7 19:42:14 2001 @@ -0,0 +1,3551 @@ +/* orinoco.c 0.05 - (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/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright (C) 2000 David Gibson, Linuxcare Australia + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David + * A. Hinds 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 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 by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +/* 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()). + * + * The kernel's IRQ handling stuff ensures that the interrupt handler + * does not re-enter itself. The interrupt handler is written such + * that everything it does is safe without a lock: chiefly this means + * that the Rx path uses one of the Hermes chipset's BAPs while + * everything else uses the other. + * + * For the moment access to the device statistics from the interrupt + * handler is unsafe - we just put up with any resulting errors in the + * statisics. FIXME: This should probably be changed to store the + * stats in atomic types. + * + * EXCEPT that we don't want the irq handler running when we actually + * reset or shut down the card, because strange things might happen + * (probably the worst would be one packet of garbage, but you can't + * be too careful). For this we use __dldwd_stop_irqs() which will set + * a flag to disable the interrupt handler, and wait for any + * outstanding instances of the handler to complete. THIS WILL LOSE + * INTERRUPTS! so it shouldn't be used except for resets, when we + * don't care about that.*/ + +/* + * Tentative changelog... + * + * v0.01 -> v0.02 - 21/3/2001 - Jean II + * o Allow to use regular ethX device name instead of dldwdX + * o Warning on IBSS with ESSID=any for firmware 6.06 + * o Put proper range.throughput values (optimistic) + * o IWSPY support (IOCTL and stat gather in Rx path) + * o Allow setting frequency in Ad-Hoc mode + * o Disable WEP setting if !has_wep to work on old firmware + * o Fix txpower range + * o Start adding support for Samsung/Compaq firmware + * + * v0.02 -> v0.03 - 23/3/2001 - Jean II + * o Start adding Symbol support - need to check all that + * o Fix Prism2/Symbol WEP to accept 128 bits keys + * o Add Symbol WEP (add authentication type) + * o Add Prism2/Symbol rate + * o Add PM timeout (holdover duration) + * o Enable "iwconfig eth0 key off" and friends (toggle flags) + * o Enable "iwconfig eth0 power unicast/all" (toggle flags) + * o Try with an intel card. It report firmware 1.01, behave like + * an antiquated firmware, however on windows it says 2.00. Yuck ! + * o Workaround firmware bug in allocate buffer (Intel 1.01) + * o Finish external renaming to orinoco... + * o Testing with various Wavelan firmwares + * + * v0.03 -> v0.04 - 30/3/2001 - Jean II + * o Update to Wireless 11 -> add retry limit/lifetime support + * o Tested with a D-Link DWL 650 card, fill in firmware support + * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) + * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( + * It work on D-Link *only* after a tcpdump. Weird... + * And still doesn't work on Intel card. Grrrr... + * o Update the mode after a setport3 + * o Add preamble setting for Symbol cards (not yet enabled) + * o Don't complain as much about Symbol cards... + * + * v0.04 -> v0.04b - 22/4/2001 - David Gibson + * o Removed the 'eth' parameter - always use ethXX as the + * interface name instead of dldwdXX. The other was racy + * anyway. + * o Clean up RID definitions in hermes.h, other cleanups + * + * v0.04b -> v0.04c - 24/4/2001 - Jean II + * o Tim Hurley reported a D-Link card + * with vendor 02 and firmware 0.08. Added in the capabilities... + * o Tested Lucent firmware 7.28, everything works... + * + * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt + * o Spin-off Pcmcia code. This file is renamed orinoco.c, + * and orinoco_cs.c now contains only the Pcmcia specific stuff + * o Add Airport driver support on top of orinoco.c (see airport.c) + * + * v0.05 -> v0.05a - 4/5/2001 - Jean II + * o Revert to old Pcmcia code to fix breakage of Ben's changes... + * + * v0.05a -> v0.05b - 4/5/2001 - Jean II + * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V + * o D-Link firmware doesn't support multicast. We just print a few + * error messages, but otherwise everything works... + * o For David : set/getport3 works fine, just upgrade iwpriv... + * + * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt + * o Adapt airport.c to latest changes in orinoco.c + * o Remove deferred power enabling code + * + * v0.05c -> v0.05d - 5/5/2001 - Jean II + * o Workaround to SNAP decapsulate frame from LinkSys AP + * original patch from : Dong Liu + * (note : the memcmp bug was mine - fixed) + * o Remove set_retry stuff, no firmware support it (bloat--). + * + * TODO - Jean II + * o inline functions (lot's of candidate, need to reorder code) + * o Test PrismII/Symbol cards & firmware versions + * o Mini-PCI support + */ + +#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 "hermes.h" +#include "orinoco.h" + +static char *version = "orinoco.c 0.05d (David Gibson and others)"; + +/* Level of debugging. Used in the macros in orinoco.h */ +#ifdef ORINOCO_DEBUG +int dldwd_debug = ORINOCO_DEBUG; +MODULE_PARM(dldwd_debug, "i"); +#endif + +const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#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 { + uint16_t frame_ctl; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctl; + uint8_t addr4[ETH_ALEN]; + uint16_t data_len; +} __attribute__ ((packed)); + +/* 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 + +struct p8022_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t oui[3]; +} __attribute__ ((packed)); + +struct dldwd_frame_hdr { + hermes_frame_desc_t desc; + struct p80211_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + uint16_t ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ + sizeof(struct p80211_hdr)) +#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) + +/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ +struct p8022_hdr encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + +/* + * Function prototypes + */ + +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_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); + +/* 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, + 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); + +/* /proc debugging stuff */ +static int dldwd_proc_init(void); +static void dldwd_proc_cleanup(void); + +/* + * Inline functions + */ +static inline void +dldwd_lock(dldwd_priv_t *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +dldwd_unlock(dldwd_priv_t *priv) +{ + spin_unlock_bh(&priv->lock); +} + +static inline int +dldwd_irqs_allowed(dldwd_priv_t *priv) +{ + return test_bit(DLDWD_STATE_DOIRQ, &priv->state); +} + +static inline void +__dldwd_stop_irqs(dldwd_priv_t *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)) + ; +} + +static inline void +__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) +{ + hermes_t *hw = &priv->hw; + + TRACE_ENTER(priv->ndev.name); + + __cli(); + set_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, irqmask); + __sti(); + + TRACE_EXIT(priv->ndev.name); +} + +static inline void +set_port_type(dldwd_priv_t *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->allow_ibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->allow_ibss = 0; + } else { + priv->port_type = 1; + priv->allow_ibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev.name); + } +} + +extern void +dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + dldwd_lock(priv); + __dldwd_set_multicast_list(dev); + dldwd_unlock(priv); +} + +/* + * Hardware control routines + */ + +static int +__dldwd_hw_reset(dldwd_priv_t *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; + } +} + +void +dldwd_shutdown(dldwd_priv_t *priv) +{ +/* hermes_t *hw = &priv->hw; */ + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + __dldwd_stop_irqs(priv); + + err = __dldwd_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); + + TRACE_EXIT(priv->ndev.name); +} + +int +dldwd_reset(dldwd_priv_t *priv) +{ + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t idbuf; + int frame_size; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err) + goto out; + + frame_size = TX_NICBUF_SIZE; + /* This stupid bug is present in Intel firmware 1.10, and + * may be fixed in later firmwares - Jean II */ + if(priv->broken_allocate) + frame_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, frame_size, &priv->txfid); + if (err) + goto out; + + /* Now set up all the parameters on the card */ + + /* Set up the link mode */ + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + if (err) + goto out; + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + priv->allow_ibss); + if (err) + goto out; + if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an \ +ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __dldwd_hw_setup_wep(priv); + if (err) + goto out; + } + + /* Set the desired ESSID */ + 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_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) + goto out; + + /* 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, + 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); + if (err) + goto out; + + /* Set AP density */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, 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); + 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); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_FRAG_THRESH, 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); + if (err) + goto out; + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + priv->pm_on); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + priv->pm_mcast); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + priv->pm_period); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + priv->pm_timeout); + if (err) + goto out; + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, + priv->preamble); + if (err) { + printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); + goto out; + } + } + + /* 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; + + __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + + out: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int extra_wep_flag = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + char keybuf[LARGE_KEY_SIZE+1]; + int keylen; + int i; + + /* Write all 4 keys */ + for(i = 0; i < MAX_KEYS; i++) { + keylen = priv->keys[i].len; + keybuf[keylen] = '\0'; + memcpy(keybuf, priv->keys[i].data, keylen); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_KEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen + 1), + &keybuf); + if (err) + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, + priv->tx_key); + if (err) + return err; + + /* Authentication is where Prism2 and Symbol + * firmware differ... */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + /* Symbol cards : set the authentication : + * 0 -> no encryption, 1 -> open, + * 2 -> shared key, 3 -> shared key 128bit */ + if(priv->wep_restrict) { + if(priv->keys[priv->tx_key].len > + SMALL_KEY_SIZE) + extra_wep_flag = 3; + else + extra_wep_flag = 2; + } else + extra_wep_flag = 1; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); + if (err) + return err; + } else { + /* Prism2 card : we need to modify master + * WEP setting */ + if(priv->wep_restrict) + extra_wep_flag = 2; + else + extra_wep_flag = 0; + } + } + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); + if (err) + return err; + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev.name); + return -EINVAL; + } + } + + return 0; +} + +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + dldwd_lock(priv); + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + ETH_ALEN, NULL, buf); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + + TRACE_ENTER(priv->ndev.name); + + dldwd_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 + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + uint16_t rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : + HERMES_RID_CNF_DESIRED_SSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + + memset(buf, 0, sizeof(buf)); + memcpy(buf, p, len); + buf[len] = '\0'; + + fail_unlock: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static long dldwd_hw_get_freq(dldwd_priv_t *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t channel; + long freq = 0; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + if (err) + goto out; + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + struct net_device *dev = &priv->ndev; + + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + dldwd_unlock(priv); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max) +{ + hermes_t *hw = &priv->hw; + hermes_id_t 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); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = MIN(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +#ifndef PCMCIA_DEBUG +static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +#else +static void show_rx_frame(struct dldwd_frame_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 "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); + + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); +} +#endif + +/* + * Interrupt handler + */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +{ + dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + hermes_t *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + int count = IRQ_LOOP_MAX; + uint16_t evstat, events; + static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + + if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + BUG(); + + if (! dldwd_irqs_allowed(priv)) { + clear_bit(DLDWD_STATE_INIRQ, &priv->state); + return; + } + + DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name); + + while (1) { + if (jiffies != old_time) + timecount = 0; + if ( (++timecount > 50) || (! count--) ) { + 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); + 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"); + break; + } + + if (events & HERMES_EV_TICK) + __dldwd_ev_tick(priv, hw); + if (events & HERMES_EV_WTERR) + __dldwd_ev_wterr(priv, hw); + if (events & HERMES_EV_INFDROP) + __dldwd_ev_infdrop(priv, hw); + if (events & HERMES_EV_INFO) + __dldwd_ev_info(priv, hw); + if (events & HERMES_EV_RX) + __dldwd_ev_rx(priv, hw); + if (events & HERMES_EV_TXEXC) + __dldwd_ev_txexc(priv, hw); + if (events & HERMES_EV_TX) + __dldwd_ev_tx(priv, hw); + if (events & HERMES_EV_ALLOC) + __dldwd_ev_alloc(priv, hw); + + hermes_write_regn(hw, EVACK, events); + } + + clear_bit(DLDWD_STATE_INIRQ, &priv->state); +} + +static void __dldwd_ev_tick(dldwd_priv_t *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) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", + priv->ndev.name); +} + +static void __dldwd_ev_infdrop(dldwd_priv_t *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) +{ + 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 */ +} + +static void __dldwd_ev_rx(dldwd_priv_t *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; + uint16_t rxfid, status; + int length, data_len, data_off; + char *p; + struct dldwd_frame_hdr hdr; + struct ethhdr *eh; + int err; + + rxfid = hermes_read_regn(hw, RXFID); + DEBUG(3, "__dldwd_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. */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + status = le16_to_cpu(hdr.desc.status); + + if (status & HERMES_RXSTAT_ERR) { + if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { + stats->rx_crc_errors++; + printk(KERN_WARNING "%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++; + printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + wstats->discard.misc++; + printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", + dev->name, status & HERMES_RXSTAT_ERR); + } + stats->rx_errors++; + goto drop; + } + + length = le16_to_cpu(hdr.p80211.data_len); + /* Yes, you heard right, that's le16. 802.2 and 802.3 are + big-endian, but 802.11 is little-endian believe it or + not. */ + /* Correct. 802.3 is big-endian byte order and little endian bit + * order, whereas 802.11 is little endian for both byte and bit + * order. That's specified in the 802.11 spec. - Jean II */ + + /* Sanity check */ + if (length > MAX_FRAME_SIZE) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + stats->rx_dropped++; + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves (note : only 3 bytes out of 6). + */ + if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + (!memcmp(&hdr.p8022, &encaps_hdr, 3))) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. + IEEE and ISO OSI have a lot to answer for. */ + + /* Remove SNAP header, reconstruct EthernetII frame */ + data_len = length - ENCAPS_OVERHEAD; + data_off = sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); + eh->h_proto = hdr.ethertype; + } else { + /* All other cases indicate a genuine 802.3 frame. + * No decapsulation needed */ + + /* Otherwise, we just throw the whole thing in, + * and hope the protocol layer can deal with it + * as 802.3 */ + data_len = length; + data_off = P8023_OFFSET; + } + + p = skb_put(skb, data_len); + if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off) != 0) { + printk(KERN_WARNING "%s: Error reading packet data\n", + dev->name); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + dldwd_stat_gather(dev, skb, &hdr); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + if (skb) + dev_kfree_skb_irq(skb); + return; +} + +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + printk(KERN_WARNING "%s: Tx error!\n", dev->name); + + netif_wake_queue(dev); + stats->tx_errors++; +} + +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + DEBUG(3, "%s: Transmit completed\n", dev->name); + + stats->tx_packets++; + netif_wake_queue(dev); +} + +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +{ + uint16_t allocfid; + + allocfid = hermes_read_regn(hw, ALLOCFID); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + + /* For some reason we don't seem to get transmit completed events properly */ + if (allocfid == priv->txfid) + __dldwd_ev_tx(priv, hw); + +/* hermes_write_regn(hw, ALLOCFID, 0); */ +} + +/* + * struct net_device methods + */ + +int +dldwd_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t nickbuf; + uint16_t reclen; + int len; + char *vendor_str; + uint32_t firmver; + + TRACE_ENTER("dldwd"); + + dldwd_lock(priv); + + err = hermes_reset(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); + goto out; + } + + /* Get the firmware version */ + err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); + if (err) { + printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + dev->name, err); + memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); + } + + firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; + DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); + + /* Determine capabilities from the firmware version */ + + switch (priv->firmware_info.vendor) { + case 0x1: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + * ELSA, Melco, HP, IBM, Dell 1150 cards */ + vendor_str = "Lucent"; + /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ + + priv->firmware_type = FIRMWARE_TYPE_LUCENT; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; /* Still works in 7.28 */ + priv->has_ibss = (firmver >= 0x60006); + priv->has_ibss_any = (firmver >= 0x60010); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); + priv->has_preamble = 0; + /* Tested with Lucent firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case 0x2: + vendor_str = "Generic Prism II"; + /* Some D-Link cards report vendor 0x02... */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + + /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ + + /* Special case for Symbol cards */ + if(firmver == 0x10001) { + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + vendor_str = "Symbol"; + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + + /* FIXME : probably need to use SYMBOL_***ARY_VER + * to get proper firmware version */ + priv->firmware_type = FIRMWARE_TYPE_SYMBOL; + priv->broken_reset = 0; + priv->broken_allocate = 1; + priv->has_port3 = 1; + priv->has_ibss = 1; /* FIXME */ + priv->has_wep = 1; /* FIXME */ + priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ + priv->has_mwo = 0; + priv->has_pm = 1; /* FIXME */ + priv->has_preamble = 0; /* FIXME */ + /* Tested with Intel firmware : v15 => Jean II */ + } + break; + case 0x3: + vendor_str = "Samsung"; + /* To check - Should cover Samsung & Compaq */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; /* FIXME */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + priv->has_preamble = 0; + break; + case 0x6: + /* D-Link DWL 650, ... */ + vendor_str = "LinkSys/D-Link"; + /* D-Link MAC : 00:40:05:* */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + /* Tested with D-Link firmware 0.07 => Jean II */ + /* Note : with 0.07, IBSS to a Lucent card seem flaky */ + break; + default: + vendor_str = "UNKNOWN"; + + priv->firmware_type = 0; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 0; + priv->has_ibss = 0; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = 0; + priv->has_preamble = 0; + } + + printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", + dev->name, priv->firmware_info.id, priv->firmware_info.vendor, + vendor_str, priv->firmware_info.major, priv->firmware_info.minor); + + if (priv->has_port3) + printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); + if (priv->has_ibss) + printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", + dev->name); + if (priv->has_wep) { + printk(KERN_INFO "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("\"128\"-bit key.\n"); + else + printk("40-bit key.\n"); + } + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name!n", + dev->name); + goto out; + } + if ( nickbuf.len ) + len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + else + len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_INFO "%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); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &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); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + goto out; + } + + /* Set initial bitrate control*/ + priv->tx_rate_ctrl = 3; + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + &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, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); + if (err) + goto out; + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + + priv->promiscuous = 0; + priv->allmulti = 0; + priv->wep_on = 0; + priv->tx_key = 0; + + printk(KERN_INFO "%s: ready\n", dev->name); + + out: + dldwd_unlock(priv); + + TRACE_EXIT("dldwd"); + + return err; +} + +struct net_device_stats * +dldwd_get_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + + return &priv->stats; +} + +struct iw_statistics * +dldwd_get_wireless_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + hermes_commsqual_t cq; + + if (!priv->hw_ready) + return NULL; + + dldwd_lock(priv); + + if (priv->port_type == 3) { + 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) { + 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 { + err = hermes_read_commsqual(hw, USER_BAP, &cq); + + DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + /* Why are we using MIN/MAX ? We don't really care + * if the value goes above max, because we export the + * raw dBm values anyway. The normalisation should be done + * in user space - Jean II */ + wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); + wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; + wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.updated = 7; + } + + dldwd_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +#ifdef WIRELESS_SPY +static inline void dldwd_spy_gather(struct net_device *dev, + u_char *mac, + hermes_commsqual_t *cq) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); + priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +void +dldwd_stat_gather( struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_commsqual_t cq; + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ +#ifdef WIRELESS_EXT + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if ( +#ifdef WIRELESS_SPY + (priv->spy_number > 0) || +#endif + 0 ) + { + u_char *stats = (u_char *) &(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 */ + cq.signal = stats[1]; /* High order byte */ + cq.noise = stats[0]; /* Low order byte */ + cq.qual = stats[0] - stats[1]; /* Better than nothing */ + + DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + +#ifdef WIRELESS_SPY + dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); +#endif + } +#endif /* WIRELESS_EXT */ +} + +int +dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct dldwd_frame_hdr hdr; + hermes_response_t resp; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return 1; + + } + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR "%s: Tx while transmitter busy!\n", + dev->name); + return 1; + } + + dldwd_lock(priv); + + /* Length of the packet body */ + len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)skb->data; + + /* Build the IEEE 802.11 header */ + 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; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ + data_len = len; + data_off = sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); + + /* 802.3 header */ + memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); + hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + 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) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = P8023_OFFSET; + p = skb->data; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(len); + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + + /* Finally, we actually initiate the send */ + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); + if (err) { + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + netif_stop_queue(dev); + + dldwd_unlock(priv); + + dev_kfree_skb(skb); + + return 0; + fail: + + dldwd_unlock(priv); + return err; +} + +void +dldwd_tx_timeout(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); + + stats->tx_errors++; + + err = dldwd_reset(priv); + if (err) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, err); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int ptype; + struct iw_range range; + int numrates; + int i, k; + + TRACE_ENTER(dev->name); + + err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); + if (err) + return err; + + rrq->length = sizeof(range); + + dldwd_lock(priv); + ptype = priv->port_type; + dldwd_unlock(priv); + + memset(&range, 0, sizeof(range)); + + /* Much of this shamelessly taken from wvlan_cs.c. No idea + * what it all means -dgibson */ +#if WIRELESS_EXT > 10 + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 11; +#endif /* WIRELESS_EXT > 10 */ + + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ + + /* Set available channels/frequencies */ + range.num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range.freq[k].i = i + 1; + range.freq[k].m = channel_frequency[i] * 100000; + range.freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range.num_frequency = k; + + range.sensitivity = 3; + + if ((ptype == 3) && (priv->spy_number == 0)){ + /* Quality stats meaningless in ad-hoc mode */ + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } else { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } + + err = dldwd_hw_get_bitratelist(priv, &numrates, + range.bitrate, IW_MAX_BITRATES); + if (err) + return err; + range.num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if(numrates > 2) + range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; + + dldwd_lock(priv); + if (priv->has_wep) { + range.max_encoding_tokens = MAX_KEYS; + + range.encoding_size[0] = SMALL_KEY_SIZE; + range.num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range.encoding_size[1] = LARGE_KEY_SIZE; + range.num_encoding_sizes = 2; + } + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + dldwd_unlock(priv); + + range.min_pmp = 0; + range.max_pmp = 65535000; + range.min_pmt = 0; + range.max_pmt = 65535 * 1000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = IW_POWER_TIMEOUT; + range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range.num_txpower = 1; + range.txpower[0] = 15; /* 15dBm */ + range.txpower_capa = IW_TXPOW_DBM; + +#if WIRELESS_EXT > 10 + range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range.retry_flags = IW_RETRY_LIMIT; + range.r_time_flags = IW_RETRY_LIFETIME; + range.min_retry = 0; + range.max_retry = 65535; /* ??? */ + range.min_r_time = 0; + range.max_r_time = 65535 * 1000; /* ??? */ +#endif /* WIRELESS_EXT > 10 */ + + if (copy_to_user(rrq->pointer, &range, sizeof(range))) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *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; + uint16_t xlen = 0; + int err = 0; + char keybuf[MAX_KEY_SIZE]; + + if (erq->pointer) { + /* We actually have a key to set */ + + if (copy_from_user(keybuf, erq->pointer, erq->length)) + return -EFAULT; + } + + dldwd_lock(priv); + + if (erq->pointer) { + if (erq->length > MAX_KEY_SIZE) { + err = -E2BIG; + goto out; + } + + if ( (erq->length > LARGE_KEY_SIZE) + || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { + err = -EINVAL; + goto out; + } + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((!enable) && (xlen > 0)) { + setindex = index; + enable = 1; + } + } else { + /* 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 != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + enable = 0; + /* Only for Prism2 & Symbol cards (so far) - Jean II */ + if (erq->flags & IW_ENCODE_OPEN) + restricted = 0; + if (erq->flags & IW_ENCODE_RESTRICTED) + restricted = 1; + + if (erq->pointer) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + priv->wep_on = enable; + priv->wep_restrict = restricted; + + out: + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + uint16_t xlen = 0; + char keybuf[MAX_KEY_SIZE]; + + + dldwd_lock(priv); + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (! priv->wep_on) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + /* Only for symbol cards - Jean II */ + if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { + if(priv->wep_restrict) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + } + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + if (erq->pointer) { + memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + } + + dldwd_unlock(priv); + + if (erq->pointer) { + if (copy_to_user(erq->pointer, keybuf, xlen)) + return -EFAULT; + } + + return 0; +} + +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + memset(&essidbuf, 0, sizeof(essidbuf)); + + if (erq->flags) { + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (copy_from_user(&essidbuf, erq->pointer, erq->length)) + return -EFAULT; + + essidbuf[erq->length] = '\0'; + } + + dldwd_lock(priv); + + memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *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); + if (err) + return err; + + erq->flags = 1; + erq->length = strlen(essidbuf) + 1; + if (erq->pointer) + if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + memset(nickbuf, 0, sizeof(nickbuf)); + + if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) + return -EFAULT; + + nickbuf[nrq->length] = '\0'; + + dldwd_lock(priv); + + memcpy(priv->nick, nickbuf, sizeof(priv->nick)); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + dldwd_lock(priv); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + dldwd_unlock(priv); + + nrq->length = strlen(nickbuf)+1; + + if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +{ + dldwd_priv_t *priv = dev->priv; + int chan = -1; + + /* We can only use this in Ad-Hoc demo mode to set the operating + * frequency, or in IBSS mode to set the frequency where the IBSS + * will be created - Jean II */ + if (priv->iw_mode != IW_MODE_ADHOC) + return -EOPNOTSUPP; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + dldwd_lock(priv); + priv->channel = chan; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + uint16_t val; + int err; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); + dldwd_unlock(priv); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + int val = srq->value; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + dldwd_lock(priv); + priv->ap_density = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = rrq->value; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + dldwd_lock(priv); + priv->rts_thresh = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + dldwd_lock(priv); + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation not \ +supported on this firmware. Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + + dldwd_lock(priv); + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int rate_ctrl = -1; + int fixed, upto; + int brate; + int i; + + dldwd_lock(priv); + + /* Normalise value */ + brate = rrq->value / 500000; + + 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_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + switch(brate) { + case 0: + fixed = 0x0; + upto = 0x15; + 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 = 0x15; + 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; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t 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; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + + if (val == 6) + brate = 11; + else + brate = 2*val; + } else + rrq->fixed = 1; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II 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; + + if(val >= 8) + brate = 22; + else if(val >= 4) + brate = 11; + else if(val >= 2) + brate = 4; + else + brate = 2; + break; + } + + rrq->value = brate * 500000; + rrq->disabled = 0; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + } + if (err) + goto out; + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t enable, period, timeout, mcast; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + dldwd_unlock(priv); + + return err; +} + +#if WIRELESS_EXT > 10 +static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t short_limit, long_limit, lifetime; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + if (err) + goto out; + + rrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the retry number */ + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1000; /* ??? */ + } else { + /* By default, display the min number */ + if ((rrq->flags & IW_RETRY_MAX)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + rrq->value = long_limit; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = short_limit; + if(short_limit != long_limit) + rrq->flags |= IW_RETRY_MIN; + } + } + + out: + dldwd_unlock(priv); + + return err; +} +#endif /* WIRELESS_EXT > 10 */ + +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = *( (int *) wrq->u.name ); + int err = 0; + + dldwd_lock(priv); + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name); + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name); + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + if (! err) + /* Actually update the mode we are using */ + set_port_type(priv); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->prefer_port3; + dldwd_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) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + int err = 0; + + /* Check the number of addresses */ + if (number > IW_MAX_SPY) + return -E2BIG; + + /* Get the data in the driver */ + if (srq->pointer) { + if (copy_from_user(address, srq->pointer, + sizeof(struct sockaddr) * number)) + return -EFAULT; + } + + /* Make sure nobody mess with the structure while we do */ + dldwd_lock(priv); + + /* dldwd_lock() doesn't disable interrupts, so make sure the + * interrupt rx path don't get confused while we copy */ + priv->spy_number = 0; + + if (number > 0) { + /* Extract the addresses */ + for (i = 0; i < number; i++) + memcpy(priv->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(priv->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + /* Set number of addresses */ + priv->spy_number = number; + } + + /* Time to show what we have done... */ + DEBUG(0, "%s: New spy list:\n", dev->name); + for (i = 0; i < number; i++) { + DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, i+1, + priv->spy_address[i][0], priv->spy_address[i][1], + priv->spy_address[i][2], priv->spy_address[i][3], + priv->spy_address[i][4], priv->spy_address[i][5]); + } + + /* Now, let the others play */ + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + dldwd_lock(priv); + + number = priv->spy_number; + if ((number > 0) && (srq->pointer)) { + /* Create address struct */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, priv->spy_address[i], + ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats */ + /* In theory, we should disable irqs while copying the stats + * because the rx path migh update it in the middle... + * Bah, who care ? - Jean II */ + memcpy(&spy_stat, priv->spy_stat, + sizeof(struct iw_quality) * IW_MAX_SPY); + for (i=0; i < number; i++) + priv->spy_stat[i].updated = 0; + } + + dldwd_unlock(priv); + + /* Push stuff to user space */ + srq->length = number; + if(copy_to_user(srq->pointer, address, + sizeof(struct sockaddr) * number)) + return -EFAULT; + if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), + &spy_stat, sizeof(struct iw_quality) * number)) + return -EFAULT; + + return 0; +} + +int +dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + dldwd_priv_t *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) + return -ENODEV; + + switch (cmd) { + case SIOCGIWNAME: + DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + 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); + break; + + case SIOCGIWRANGE: + DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); + err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + break; + + case SIOCSIWMODE: + DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); + dldwd_lock(priv); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + if (! (priv->has_ibss || priv->has_port3) ) + err = -EINVAL; + else { + priv->iw_mode = IW_MODE_ADHOC; + changed = 1; + } + break; + + case IW_MODE_INFRA: + priv->iw_mode = IW_MODE_INFRA; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + dldwd_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); + dldwd_lock(priv); + wrq->u.mode = priv->iw_mode; + dldwd_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + break; + + case SIOCGIWENCODE: + DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); + err = dldwd_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); + break; + + case SIOCSIWNICKN: + DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); + err = dldwd_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); + break; + + case SIOCGIWFREQ: + DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); + wrq->u.freq.m = dldwd_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); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); + err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); + err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + if (! err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value = priv->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); + err = dldwd_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); + if (! err) + changed = 1; + break; + + case SIOCGIWFRAG: + DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); + err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + break; + + case SIOCSIWRATE: + DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); + err = dldwd_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); + break; + + case SIOCSIWPOWER: + DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); + err = dldwd_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); + break; + + case SIOCGIWTXPOW: + DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + wrq->u.txpower.value = 15; /* dBm */ + wrq->u.txpower.fixed = 1; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.flags = IW_TXPOW_DBM; + break; + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); + err = -EOPNOTSUPP; + break; + + case SIOCGIWRETRY: + DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); + err = dldwd_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); + break; + + case SIOCGIWSPY: + DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); + + err = dldwd_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 + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCDEVPRIVATE + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" }, + { SIOCDEVPRIVATE + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_preamble" }, + { SIOCDEVPRIVATE + 0x5, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_preamble" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } + break; + + case SIOCDEVPRIVATE + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + dldwd_reset(priv); + break; + + case SIOCDEVPRIVATE + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_setport3(dev, wrq); + if (! err) + changed = 1; + break; + + case SIOCDEVPRIVATE + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + dev->name); + err = dldwd_ioctl_getport3(dev, wrq); + break; + + case SIOCDEVPRIVATE + 0x4: /* set_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + /* 802.11b has recently defined some short preamble. + * Basically, the Phy header has been reduced in size. + * This increase performance, especially at high rates + * (the preamble is transmitted at 1Mb/s), unfortunately + * this give compatibility troubles... - Jean II */ + if(priv->has_preamble) { + int val = *( (int *) wrq->u.name ); + + dldwd_lock(priv); + if(val) + priv->preamble = 1; + else + priv->preamble = 0; + dldwd_unlock(priv); + changed = 1; + } else + err = -EOPNOTSUPP; + break; + + case SIOCDEVPRIVATE + 0x5: /* get_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", + dev->name); + if(priv->has_preamble) { + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->preamble; + dldwd_unlock(priv); + } else + err = -EOPNOTSUPP; + break; + + default: + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + err = dldwd_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; + } + } + + TRACE_EXIT(dev->name); + + return err; +} + +int +dldwd_change_mtu(struct net_device *dev, int new_mtu) +{ + TRACE_ENTER(dev->name); + + if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + return -EINVAL; + + dev->mtu = new_mtu; + + TRACE_EXIT(dev->name); + + return 0; +} + +static void +__dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, allmulti, 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) + 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) ) { + 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, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", + dev->name, err, promisc); + } 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; + + 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) ) { + 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; + } + + 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); + + 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, + 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; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; + + if (priv->allmulti) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; + + TRACE_EXIT(dev->name); +} + +/* + * procfs stuff + */ + +static struct proc_dir_entry *dir_base = NULL; + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int + +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +#define PROC_BUFFER_SIZE 4096 +#define PROC_SAFE_SIZE 3072 + +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + return return_len; +} + +static int +dldwd_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; + char *buf; + int total = 0, slop = 0; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + +#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) + + DHERMESREG(CMD); + DHERMESREG(PARAM0); + DHERMESREG(PARAM1); + DHERMESREG(PARAM2); + DHERMESREG(STATUS); + DHERMESREG(RESP0); + DHERMESREG(RESP1); + DHERMESREG(RESP2); + DHERMESREG(INFOFID); + DHERMESREG(RXFID); + DHERMESREG(ALLOCFID); + DHERMESREG(TXCOMPLFID); + DHERMESREG(SELECT0); + DHERMESREG(OFFSET0); + DHERMESREG(SELECT1); + DHERMESREG(OFFSET1); + DHERMESREG(EVSTAT); + DHERMESREG(INTEN); + DHERMESREG(EVACK); + DHERMESREG(CONTROL); + DHERMESREG(SWSUPPORT0); + DHERMESREG(SWSUPPORT1); + DHERMESREG(SWSUPPORT2); + DHERMESREG(AUXPAGE); + DHERMESREG(AUXOFFSET); + DHERMESREG(AUXDATA); +#undef DHERMESREG + + shift_buffer(page, requested_offset, requested_len, &total, + &slop, &buf); + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +struct { + uint16_t rid; + char *name; + int minlen, maxlen; + int displaytype; +#define DISPLAY_WORDS 0 +#define DISPLAY_BYTES 1 +#define DISPLAY_STRING 2 +} 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(PRISM2_TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_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 NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) + +static int +dldwd_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; + char *buf; + int total = 0, slop = 0; + int i; + uint16_t length; + int err; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + + /* print out all the config RIDs */ + for (i = 0; i < NUM_RIDS; i++) { + uint16_t rid = record_table[i].rid; + int minlen = record_table[i].minlen; + int maxlen = record_table[i].maxlen; + int len; + uint8_t *val8; + uint16_t *val16; + int j; + + val8 = kmalloc(maxlen + 2, GFP_KERNEL); + if (! val8) + return -ENOMEM; + + err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, + &length, val8); + if (err) { + DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); + continue; + } + val16 = (uint16_t *)val8; + + buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, + rid, length, (length-1)*2); + len = MIN( MAX(minlen, (length-1)*2), maxlen); + + switch (record_table[i].displaytype) { + case DISPLAY_WORDS: + for (j = 0; j < len / 2; j++) { + buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); + } + buf--; + break; + + case DISPLAY_BYTES: + default: + for (j = 0; j < len; j++) { + buf += sprintf(buf, "%02X:", val8[j]); + } + buf--; + break; + + case DISPLAY_STRING: + len = MIN(len, le16_to_cpu(val16[0])+2); + val8[len] = '\0'; + buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + break; + } + + buf += sprintf(buf, "\n"); + + kfree(val8); + + if (shift_buffer(page, requested_offset, requested_len, + &total, &slop, &buf)) + break; + + if ( (buf - page) > PROC_SAFE_SIZE ) + break; + } + + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +/* initialise the /proc subsystem for the hermes driver, creating the + * separate entries */ +static int +dldwd_proc_init(void) +{ + int err = 0; + + TRACE_ENTER("dldwd"); + + /* 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(); + err = -ENOMEM; + } + + TRACE_EXIT("dldwd"); + + return err; +} + +int +dldwd_proc_dev_init(dldwd_priv_t *dev) +{ + struct net_device *ndev = &dev->ndev; + + dev->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); + 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); + 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); + goto fail; + } + + return 0; + fail: + dldwd_proc_dev_cleanup(dev); + return -ENOMEM; +} + +void +dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +{ + struct net_device *ndev = &priv->ndev; + + if (priv->dir_regs) { + remove_proc_entry("regs", priv->dir_dev); + priv->dir_regs = NULL; + } + if (priv->dir_recs) { + remove_proc_entry("recs", priv->dir_dev); + priv->dir_recs = NULL; + } + if (priv->dir_dev) { + remove_proc_entry(ndev->name, dir_base); + priv->dir_dev = NULL; + } +} + +static void +dldwd_proc_cleanup(void) +{ + TRACE_ENTER("dldwd"); + + if (dir_base) { + remove_proc_entry("hermes", &proc_root); + dir_base = NULL; + } + + TRACE_EXIT("dldwd"); +} + +int +dldwd_setup(dldwd_priv_t* priv) +{ + struct net_device *ndev = &priv->ndev;; + + spin_lock_init(&priv->lock); + + /* Set up the net_device */ + ether_setup(ndev); + ndev->priv = priv; + + /* Setup up default routines */ + ndev->init = dldwd_init; + ndev->open = NULL; /* Caller *must* override */ + ndev->stop = NULL; + ndev->hard_start_xmit = dldwd_xmit; + ndev->tx_timeout = dldwd_tx_timeout; + ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ + + ndev->get_stats = dldwd_get_stats; + ndev->get_wireless_stats = dldwd_get_wireless_stats; + + ndev->do_ioctl = dldwd_ioctl; + + ndev->change_mtu = dldwd_change_mtu; + ndev->set_multicast_list = dldwd_set_multicast_list; + + netif_stop_queue(ndev); + + return 0; +} + +#ifdef ORINOCO_DEBUG +EXPORT_SYMBOL(dldwd_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); + +static int __init init_dldwd(void) +{ + int err; + + err = dldwd_proc_init(); + + printk(KERN_INFO "%s\n", version); + + return 0; +} + +static void __exit exit_dldwd(void) +{ + dldwd_proc_cleanup(); +} + +module_init(init_dldwd); +module_exit(exit_dldwd); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco.h linux/drivers/net/wireless/orinoco.h --- v2.4.4/linux/drivers/net/wireless/orinoco.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco.h Mon May 7 19:42:14 2001 @@ -0,0 +1,145 @@ +/* orinoco.h + * + * Common definitions to all pieces of the various orinoco + * drivers + */ + +#ifndef _ORINOCO_H +#define _ORINOCO_H + +/* To enable debug messages */ +//#define ORINOCO_DEBUG 3 + +#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) +#error "orinoco_cs requires Wireless extensions v10 or later." +#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ +#define WIRELESS_SPY // enable iwspy support + + +#define DLDWD_MIN_MTU 256 +#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) + +#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 Intel 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; + char data[MAX_KEY_SIZE]; +} __attribute__ ((packed)) dldwd_key_t; + +typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; + +/*====================================================================*/ + + +typedef struct dldwd_priv { + void* card; /* Pointer to card dependant structure */ + + spinlock_t lock; + long state; +#define DLDWD_STATE_INIRQ 0 +#define DLDWD_STATE_DOIRQ 1 + int hw_ready; /* HW may be suspended by platform */ + + /* 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; + + /* Capabilities of the hardware/firmware */ + hermes_identity_t firmware_info; + int firmware_type; +#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_PRISM2 2 +#define FIRMWARE_TYPE_SYMBOL 3 + int has_ibss, has_port3, prefer_port3, has_ibss_any; + int has_wep, has_big_wep; + int has_mwo; + int has_pm; + int has_preamble; + int broken_reset, broken_allocate; + uint16_t channel_mask; + + /* Current configuration */ + uint32_t iw_mode; + int port_type, allow_ibss; + uint16_t wep_on, wep_restrict, tx_key; + dldwd_keys_t keys; + 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; + + int promiscuous, allmulti, mc_count; + +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif + + /* /proc based debugging stuff */ + struct proc_dir_entry *dir_dev; + struct proc_dir_entry *dir_regs; + struct proc_dir_entry *dir_recs; +} dldwd_priv_t; + +/*====================================================================*/ + +extern int dldwd_debug; +extern struct list_head dldwd_instances; + +#ifdef ORINOCO_DEBUG +#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args) +#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#define DEBUGMORE(n, args...) do { } while (0) +#endif /* ORINOCO_DEBUG */ + +#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); +#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#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); + +/* 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); + + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c --- v2.4.4/linux/drivers/net/wireless/orinoco_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco_cs.c Mon May 7 19:42:14 2001 @@ -0,0 +1,789 @@ +/* orinoco_cs.c 0.05 - (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/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright notice & release notes in file orinoco.c + */ + +#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 "hermes.h" +#include "orinoco.h" + +/* Pcmcia specific structure */ +typedef struct dldwd_card { + dev_link_t link; + dev_node_t node; + int instance; + + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "orinoco_cs.c 0.05 (David Gibson and others)"; + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static uint irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; +/* Do a Pcmcia soft reset (may help some cards) */ +static int reset_cor = 0; +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc = 0; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(reset_cor, "i"); +MODULE_PARM(ignore_cis_vcc, "i"); + +/* + * Function prototypes + */ + +/* struct net_device methods */ +static int dldwd_cs_open(struct net_device *dev); +static int dldwd_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, + event_callback_args_t * args); + +static dev_link_t *dldwd_cs_attach(void); +static void dldwd_cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "orinoco_cs"; + +/* + A linked list of "instances" of the dummy device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; +static int num_instances = 0; + +/*====================================================================*/ + +static void +cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +static int +dldwd_cs_open(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + int err; + + TRACE_ENTER(priv->ndev.name); + + link->open++; + netif_device_attach(dev); + + err = dldwd_reset(priv); + if (err) + dldwd_cs_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int +dldwd_cs_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + link->open--; + + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +/*====================================================================== + dldwd_cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. 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 * +dldwd_cs_attach(void) +{ + dldwd_card_t *card; + dldwd_priv_t *priv; + dev_link_t *link; + struct net_device *ndev; + client_reg_t client_reg; + int ret, i; + + TRACE_ENTER("dldwd"); + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (! card) { + link = NULL; + goto out; + } + memset(card, 0, sizeof(*card)); + + /* 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.data = (u_long) link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + 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 = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Setup the common part */ + if(dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->open = dldwd_cs_open; + ndev->stop = dldwd_cs_stop; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + 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.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); + link = NULL; + goto out; + } + + out: + TRACE_EXIT("dldwd"); + return link; +} /* dldwd_cs_attach */ + +/*====================================================================== + 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 +dldwd_cs_detach(dev_link_t * link) +{ + dev_link_t **linkp; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER("dldwd"); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + goto out; + + /* + 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) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + if (link->dev) { + DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + &priv->ndev); + unregister_netdev(&priv->ndev); + } + kfree(priv->card); + + num_instances--; /* FIXME: Racy? */ + + out: + TRACE_EXIT("dldwd"); +} /* dldwd_cs_detach */ + +/* + * Do a soft reset of the Pcmcia card using the Configuration Option Register + * Can't do any harm, and actually may do some good on some cards... + */ +static int +dldwd_cs_cor_reset(dev_link_t *link) +{ + conf_reg_t reg; + u_long default_cor; + + /* Save original COR value */ + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + CardServices(AccessConfigurationRegister, link->handle, ®); + default_cor = reg.Value; + + DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor); + + /* Soft-Reset card */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = (default_cor | COR_SOFT_RESET); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has acknowledged our reset */ + mdelay(1); + + /* Restore original COR configuration index */ + reg.Value = (default_cor & COR_CONFIG_MASK); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has finished restarting */ + mdelay(1); + + return(0); +} + +/*====================================================================== + dldwd_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. + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void +dldwd_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; + hermes_t *hw = &priv->hw; + struct net_device *ndev = &priv->ndev; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cistpl_cftable_entry_t dflt = { 0 }; + cisinfo_t info; + + TRACE_ENTER("dldwd"); + + CS_CHECK(ValidateCIS, handle, &info); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + link->conf.ConfigBase, link->conf.Vcc); + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", + cfg->index, cfg->flags); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + 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); + 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); + if(!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + 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"); + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = + (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = + io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = + link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + + /* If we got this far, we're cool! */ + + break; + + next_entry: + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + int i; + + 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 = dldwd_interrupt; + link->irq.Instance = priv; + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* We initialize the hermes structure before completing PCMCIA + configuration just in case the interrupt handler gets + called. */ + hermes_struct_init(hw, link->io.BasePort1); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + ndev->base_addr = link->io.BasePort1; + ndev->irq = link->irq.AssignedIRQ; + + /* Do a Pcmcia soft reset of the card (optional) */ + if(reset_cor) + dldwd_cs_cor_reset(link); + + /* 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 "orinoco_cs: register_netdev() failed\n"); + goto failed; + } + strcpy(card->node.dev_name, ndev->name); + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + ndev->name, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + printk("\n"); + + /* Allow /proc & ioctls to act */ + priv->hw_ready = 1; + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) { + printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", + ndev->name); + goto failed; + } + + /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ + SET_MODULE_OWNER(ndev); + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + card->node.major = card->node.minor = 0; + link->dev = &card->node; + link->state &= ~DEV_CONFIG_PENDING; + + TRACE_EXIT("dldwd"); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + dldwd_cs_release((u_long) link); + + TRACE_EXIT("dldwd"); +} /* dldwd_cs_config */ + +/*====================================================================== + After a card is removed, dldwd_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) +{ + dev_link_t *link = (dev_link_t *) arg; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER(link->dev->dev_name); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + TRACE_EXIT(link->dev->dev_name); +} /* dldwd_cs_release */ + +/*====================================================================== + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + ======================================================================*/ + +static int +dldwd_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 net_device *dev = &priv->ndev; + + TRACE_ENTER("dldwd"); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + priv->hw_ready = 0; + dldwd_shutdown(priv); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + 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); + break; + case CS_EVENT_PM_SUSPEND: + + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + dldwd_shutdown(priv); + /* Mark the device as stopped, to block IO until later */ + + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + 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 (dldwd_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); + } + } + } + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + + TRACE_EXIT("dldwd"); + + return 0; +} /* dldwd_cs_event */ + +static int __init +init_dldwd_cs(void) +{ + servinfo_t serv; + + TRACE_ENTER("dldwd"); + + printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); + + DEBUG(0, "%s\n", version); + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "orinoco_cs: Card Services release " + "does not match!\n"); + return -1; + } + + register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach); + + + TRACE_EXIT("dldwd"); + return 0; +} + +static void __exit +exit_dldwd_cs(void) +{ + TRACE_ENTER("dldwd"); + + unregister_pccard_driver(&dev_info); + + if (dev_list) + DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + 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); + } + + TRACE_EXIT("dldwd"); +} + +module_init(init_dldwd_cs); +module_exit(exit_dldwd_cs); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/todo.txt linux/drivers/net/wireless/todo.txt --- v2.4.4/linux/drivers/net/wireless/todo.txt Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/todo.txt Mon May 7 19:42:14 2001 @@ -0,0 +1,24 @@ + Wireless Todo + ------------- + +1) Bring other kernel Wireless LAN drivers here + Already done : + o hermes.c/orinoco.c -> Wavelan IEEE driver + Airport driver + Drivers I have control over : + o wavelan.c -> old Wavelan ISA driver + o wavelan_cs.c -> old Wavelan Pcmcia driver (warning : header) + o netwave_cs.c -> Netwave Pcmcia driver + Drivers likely to go : + o ray_cs.c -> Raytheon/Aviator driver (maintainer MIA) + Drivers I have absolutely no control over : + o arlan.c -> old Aironet Arlan 655 (need to ask Elmer) + o aironet4500_xxx.c -> Elmer's Aironet driver (need to ask Elmer) + o airo.c/airo_cs.c -> Ben's Aironet driver (not yet in kernel) + o strip.c -> Metricom's stuff. Not a wlan. Hum... + + ETA : Kernel 2.5.X + +2) Bring new Wireless LAN driver not yet in the kernel there + See my web page for details + + Jean II diff -u --recursive --new-file v2.4.4/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.4.4/linux/drivers/net/yellowfin.c Fri Apr 20 11:54:23 2001 +++ linux/drivers/net/yellowfin.c Wed May 16 10:25:39 2001 @@ -29,6 +29,11 @@ LK1.1.2 (jgarzik): * Merge in becker version 1.05 + LK1.1.3 (jgarzik): + * Various cleanups + * Update yellowfin_timer to correctly calculate duplex. + (suggested by Manfred Spraul) + */ /* The user-configurable values. @@ -99,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -111,7 +117,7 @@ static char version[] __devinitdata = KERN_INFO "yellowfin.c:v1.05 1/09/2001 Written by Donald Becker \n" KERN_INFO " http://www.scyld.com/network/yellowfin.html\n" -KERN_INFO " (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n"; +KERN_INFO " (unofficial 2.4.x port, LK1.1.3, May 10, 2001)\n"; /* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) @@ -652,22 +658,19 @@ } if (yp->mii_cnt) { - int mii_reg1 = mdio_read(ioaddr, yp->phys[0], 1); - int mii_reg5 = mdio_read(ioaddr, yp->phys[0], 5); - int negotiated = mii_reg5 & yp->advertising; + int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR); + int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA); + int negotiated = lpa & yp->advertising; if (yellowfin_debug > 1) printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, " "link partner capability %4.4x.\n", - dev->name, yp->phys[0], mii_reg1, mii_reg5); + dev->name, yp->phys[0], bmsr, lpa); - if ( ! yp->duplex_lock && - ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040)) { - yp->full_duplex = 1; - } + yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated); + outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); - if (mii_reg1 & 0x0004) + if (bmsr & BMSR_LSTATUS) next_tick = 60*HZ; else next_tick = 3*HZ; diff -u --recursive --new-file v2.4.4/linux/drivers/parport/BUGS-parport linux/drivers/parport/BUGS-parport --- v2.4.4/linux/drivers/parport/BUGS-parport Mon Jun 19 13:42:38 2000 +++ linux/drivers/parport/BUGS-parport Sat May 19 18:07:04 2001 @@ -3,4 +3,7 @@ o lp doesn't allow you to read status while printing is in progress (is this still true?). +o parport_pc_ecp_read_block_pio() is broken. parport will revert to the + software-driven mode in ieee1284_ops.c + See . diff -u --recursive --new-file v2.4.4/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.4/linux/drivers/parport/ChangeLog Fri Apr 20 16:23:12 2001 +++ linux/drivers/parport/ChangeLog Tue May 22 19:54:04 2001 @@ -1,3 +1,43 @@ +2001-05-22 Juan Quintela + + * parport_amiga.c: Set printk levels. + * parport_gsc.c: Likewise. + * parport_mfc3.c: Likewise. + * parport_pc.c: Likewise. + * parport_sunbpp.c: Likewise. + * probe.c: Likewise. + * share.c: Likewise. + +2001-05-10 Fred Barnes + + * parport_pc.c (parport_pc_epp_read_data): added support for + reading from a w91284pic peripheral, flag is PARPORT_W91284PIC. + +2001-05-07 Fred Barnes + + * parport_pc.c (parport_pc_epp_read_data, + parport_pc_epp_write_data, parport_pc_epp_read_addr, + parport_pc_epp_write_addr): support for fast reads/writes using + the PARPORT_EPP_FAST flag. + + * ieee1284.c (parport_read, parport_write): added code to handle + software EPP mode (IEEE1284_MODE_EPPSWE). Added code to allow + BYTE mode reverse transfers (previously always went for NIBBLE + mode). + + * ieee1284_ops.c (parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_data): fixed various polarity problems. + Also (theoretically) fixed address versions (.._addr), but no + hardware to test this on. + + * parport_pc.h: added parport_dump_state() function for debugging. + Needs to have DEBUG_PARPORT to be defined for it to be included. + +2001-05-03 Tim Waugh + + * parport_pc.c: Fix the compile problem I introduce from the last + change. + 2001-04-20 Paul Gortmaker * parport_pc.c: Cut down the size quite a bit (more than 4k off diff -u --recursive --new-file v2.4.4/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c --- v2.4.4/linux/drivers/parport/ieee1284.c Thu Jan 4 13:00:55 2001 +++ linux/drivers/parport/ieee1284.c Sat May 19 18:07:04 2001 @@ -12,6 +12,8 @@ * Any part of this program may be used in documents licensed under * the GNU Free Documentation License, Version 1.1 or any later version * published by the Free Software Foundation. + * + * Various hacks, Fred Barnes , 04/2000 */ #include @@ -523,9 +525,10 @@ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { DPRINTK (KERN_INFO "%s: Timeout at event 31\n", - port->name); + port->name); + } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", @@ -614,6 +617,7 @@ /* Use the mode we're in. */ switch (mode) { case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: parport_negotiate (port, IEEE1284_MODE_COMPAT); case IEEE1284_MODE_COMPAT: DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n", @@ -623,19 +627,29 @@ case IEEE1284_MODE_EPP: DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->epp_write_addr; - else + } else { fn = port->ops->epp_write_data; + } + break; + case IEEE1284_MODE_EPPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n", + port->name); + if (addr) { + fn = parport_ieee1284_epp_write_addr; + } else { + fn = parport_ieee1284_epp_write_data; + } break; - case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->ecp_write_addr; - else + } else { fn = port->ops->ecp_write_data; + } break; case IEEE1284_MODE_ECPSWE: @@ -643,10 +657,11 @@ port->name); /* The caller has specified that it must be emulated, * even if we have ECP hardware! */ - if (addr) + if (addr) { fn = parport_ieee1284_ecp_write_addr; - else + } else { fn = parport_ieee1284_ecp_write_data; + } break; default: @@ -656,8 +671,7 @@ } retval = (*fn) (port, buffer, len, 0); - DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, - len); + DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, len); return retval; #endif /* IEEE1284 support */ } @@ -696,8 +710,22 @@ /* Use the mode we're in. */ switch (mode) { case IEEE1284_MODE_COMPAT: - if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) + /* if we can tri-state use BYTE mode instead of NIBBLE mode, + * if that fails, revert to NIBBLE mode -- ought to store somewhere + * the device's ability to do BYTE mode reverse transfers, so we don't + * end up needlessly calling negotiate(BYTE) repeately.. (fb) + */ + if ((port->physport->modes & PARPORT_MODE_TRISTATE) && + !parport_negotiate (port, IEEE1284_MODE_BYTE)) { + /* got into BYTE mode OK */ + DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name); + fn = port->ops->byte_read_data; + break; + } + if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) { return -EIO; + } + /* fall through to NIBBLE */ case IEEE1284_MODE_NIBBLE: DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name); fn = port->ops->nibble_read_data; @@ -710,12 +738,21 @@ case IEEE1284_MODE_EPP: DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->epp_read_addr; - else + } else { fn = port->ops->epp_read_data; + } + break; + case IEEE1284_MODE_EPPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n", + port->name); + if (addr) { + fn = parport_ieee1284_epp_read_addr; + } else { + fn = parport_ieee1284_epp_read_data; + } break; - case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); diff -u --recursive --new-file v2.4.4/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c --- v2.4.4/linux/drivers/parport/ieee1284_ops.c Fri Mar 2 18:43:03 2001 +++ linux/drivers/parport/ieee1284_ops.c Sat May 19 18:07:04 2001 @@ -10,6 +10,7 @@ * * Author: Tim Waugh * Fixed AUTOFD polarity in ecp_forward_to_reverse(). Fred Barnes, 1999 + * Software emulated EPP fixes, Fred Barnes, 04/2001. */ @@ -18,7 +19,7 @@ #include #include -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef CONFIG_LP_CONSOLE #undef DEBUG /* Don't want a garbled console */ @@ -725,31 +726,32 @@ const void *buffer, size_t len, int flags) { - /* This is untested */ unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; + /* set EPP idle state (just to make sure) with strobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_INIT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { - /* Event 62: Write data and strobe data */ + /* Event 62: Write data and set autofd low */ parport_write_data (port, *bp); parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); - /* Event 58 */ + /* Event 58: wait for busy (nWait) to go high */ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; - /* Event 63 */ + /* Event 63: set nAutoFd (nDStrb) high */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - /* Event 60 */ + /* Event 60: wait for busy (nWait) to go low */ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, 5)) break; @@ -757,7 +759,7 @@ ret++; } - /* Event 61 */ + /* Event 61: set strobe (nWrite) high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); return ret; @@ -768,29 +770,37 @@ void *buffer, size_t len, int flags) { - /* This is untested. */ unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; + /* set EPP idle state (just to make sure) with strobe high */ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT, 0); + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - - /* Event 58 */ - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 67: set nAutoFd (nDStrb) low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + /* Event 58: wait for Busy to go high */ + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { break; + } *bp = parport_read_data (port); - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); + /* Event 63: set nAutoFd (nDStrb) high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for Busy to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) { break; + } ret++; } @@ -873,3 +883,5 @@ return ret; } + + diff -u --recursive --new-file v2.4.4/linux/drivers/parport/init.c linux/drivers/parport/init.c --- v2.4.4/linux/drivers/parport/init.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/parport/init.c Wed May 16 10:25:39 2001 @@ -165,6 +165,8 @@ return 0; } +__initcall(parport_init); + #endif /* Exported symbols for modules. */ diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c --- v2.4.4/linux/drivers/parport/parport_amiga.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/parport/parport_amiga.c Tue May 22 19:54:04 2001 @@ -34,7 +34,7 @@ static void amiga_write_data(struct parport *p, unsigned char data) { - DPRINTK("write_data %c\n",data); + DPRINTK(KERN_DEBUG "write_data %c\n",data); /* Triggers also /STROBE. This behavior cannot be changed */ ciaa.prb = data; mb(); @@ -73,13 +73,13 @@ static void amiga_write_control(struct parport *p, unsigned char control) { - DPRINTK("write_control %02x\n",control); + DPRINTK(KERN_DEBUG "write_control %02x\n",control); /* No implementation possible */ } static unsigned char amiga_read_control( struct parport *p) { - DPRINTK("read_control \n"); + DPRINTK(KERN_DEBUG "read_control \n"); return control_amiga_to_pc(0); } @@ -87,7 +87,7 @@ { unsigned char old; - DPRINTK("frob_control mask %02x, value %02x\n",mask,val); + DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val); old = amiga_read_control(p); amiga_write_control(p, (old & ~mask) ^ val); return old; @@ -132,7 +132,7 @@ unsigned char status; status = status_amiga_to_pc(ciab.pra & 7); - DPRINTK("read_status %02x\n", status); + DPRINTK(KERN_DEBUG "read_status %02x\n", status); return status; } @@ -154,14 +154,14 @@ static void amiga_data_forward(struct parport *p) { - DPRINTK("forward\n"); + DPRINTK(KERN_DEBUG "forward\n"); ciaa.ddrb = 0xff; /* all pins output */ mb(); } static void amiga_data_reverse(struct parport *p) { - DPRINTK("reverse\n"); + DPRINTK(KERN_DEBUG "reverse\n"); ciaa.ddrb = 0; /* all pins input */ mb(); } diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_gsc.c linux/drivers/parport/parport_gsc.c --- v2.4.4/linux/drivers/parport/parport_gsc.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/parport/parport_gsc.c Tue May 22 19:54:04 2001 @@ -473,7 +473,7 @@ irq = busdevice_alloc_irq(d); if (!irq) { - printk("IRQ not found for parallel device at 0x%p\n", d->hpa); + printk(KERN_DEBUG "IRQ not found for parallel device at 0x%p\n", d->hpa); return -ENODEV; } @@ -484,10 +484,10 @@ */ if (!pdc_add_valid( (void *)(port+4))) { /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ - printk("%s: initialize bidirectional-mode.\n", __FUNCTION__); + printk(KERN_DEBUG "%s: initialize bidirectional-mode.\n", __FUNCTION__); parport_writeb ( (0x10 + 0x20), port + 4); } else { - printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__); + printk(KERN_DEBUG "%s: enhanced parport-modes not supported.\n", __FUNCTION__); } if (parport_gsc_probe_port(port, 0, diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c --- v2.4.4/linux/drivers/parport/parport_mfc3.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/parport/parport_mfc3.c Tue May 22 19:54:04 2001 @@ -82,7 +82,7 @@ static void mfc3_write_data(struct parport *p, unsigned char data) { -DPRINTK("write_data %c\n",data); +DPRINTK(KERN_DEBUG "write_data %c\n",data); dummy = pia(p)->pprb; /* clears irq bit */ /* Triggers also /STROBE.*/ @@ -91,7 +91,7 @@ static unsigned char mfc3_read_data(struct parport *p) { - /* clears interupt bit. Triggers also /STROBE. */ + /* clears interrupt bit. Triggers also /STROBE. */ return pia(p)->pprb; } @@ -126,13 +126,13 @@ static void mfc3_write_control(struct parport *p, unsigned char control) { -DPRINTK("write_control %02x\n",control); +DPRINTK(KERN_DEBUG "write_control %02x\n",control); pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control); } static unsigned char mfc3_read_control( struct parport *p) { -DPRINTK("read_control \n"); +DPRINTK(KERN_DEBUG "read_control \n"); return control_mfc3_to_pc(pia(p)->ppra & 0xe0); } @@ -140,7 +140,7 @@ { unsigned char old; -DPRINTK("frob_control mask %02x, value %02x\n",mask,val); +DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val); old = mfc3_read_control(p); mfc3_write_control(p, (old & ~mask) ^ val); return old; @@ -186,7 +186,7 @@ #if 0 /* currently unused */ static void mfc3_write_status( struct parport *p, unsigned char status) { -DPRINTK("write_status %02x\n",status); +DPRINTK(KERN_DEBUG "write_status %02x\n",status); pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status); } #endif @@ -196,7 +196,7 @@ unsigned char status; status = status_mfc3_to_pc(pia(p)->ppra & 0x1f); -DPRINTK("read_status %02x\n", status); +DPRINTK(KERN_DEBUG "read_status %02x\n", status); return status; } @@ -234,7 +234,7 @@ static void mfc3_data_forward(struct parport *p) { - DPRINTK("forward\n"); + DPRINTK(KERN_DEBUG "forward\n"); pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */ pia(p)->pddrb = 255; /* all pins output */ pia(p)->crb |= PIA_DDR; /* make data register visible - default */ @@ -242,7 +242,7 @@ static void mfc3_data_reverse(struct parport *p) { - DPRINTK("reverse\n"); + DPRINTK(KERN_DEBUG "reverse\n"); pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */ pia(p)->pddrb = 0; /* all pins input */ pia(p)->crb |= PIA_DDR; /* make data register visible - default */ diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.4/linux/drivers/parport/parport_pc.c Fri Apr 20 16:23:12 2001 +++ linux/drivers/parport/parport_pc.c Tue May 22 19:54:04 2001 @@ -12,6 +12,7 @@ * DMA support - Bert De Jonghe * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. + * Various hacks, Fred Barnes, 04/2001 */ /* This driver should work with any hardware that is broadly compatible @@ -117,7 +118,7 @@ unsigned char oecr; int mode; - DPRINTK("parport change_mode ECP-ISA to mode 0x%02x\n",m); + DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m); if (!priv->ecr) { printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); @@ -211,6 +212,7 @@ /* Back to PS2 mode. */ frob_econtrol (p, 0xe0, ECR_PS2 << 5); + DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p))); return residue; } #endif /* IEEE 1284 support */ @@ -367,9 +369,60 @@ size_t length, int flags) { size_t got = 0; + + if (flags & PARPORT_W91284PIC) { + unsigned char status; + size_t left = length; + + /* use knowledge about data lines..: + * nFault is 0 if there is at least 1 byte in the Warp's FIFO + * pError is 1 if there are 16 bytes in the Warp's FIFO + */ + status = inb (STATUS (port)); + + while (!(status & 0x08) && (got < length)) { + if ((left >= 16) && (status & 0x20) && !(status & 0x08)) { + /* can grab 16 bytes from warp fifo */ + if (!((long)buf & 0x03)) { + insl (EPPDATA (port), buf, 4); + } else { + insb (EPPDATA (port), buf, 16); + } + buf += 16; + got += 16; + left -= 16; + } else { + /* grab single byte from the warp fifo */ + *((char *)buf)++ = inb (EPPDATA (port)); + got++; + left--; + } + status = inb (STATUS (port)); + if (status & 0x01) { + /* EPP timeout should never occur... */ + printk (KERN_DEBUG "%s: EPP timeout occured while talking to " + "w91284pic (should not have done)\n", port->name); + clear_epp_timeout (port); + } + } + return got; + } + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + if (!(((long)buf | length) & 0x03)) { + insl (EPPDATA (port), buf, (length >> 2)); + } else { + insb (EPPDATA (port), buf, length); + } + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; got < length; got++) { *((char*)buf)++ = inb (EPPDATA(port)); - if (inb (STATUS(port)) & 0x01) { + if (inb (STATUS (port)) & 0x01) { + /* EPP timeout */ clear_epp_timeout (port); break; } @@ -382,6 +435,19 @@ size_t length, int flags) { size_t written = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + if (!(((long)buf | length) & 0x03)) { + outsl (EPPDATA (port), buf, (length >> 2)); + } else { + outsb (EPPDATA (port), buf, length); + } + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; written < length; written++) { outb (*((char*)buf)++, EPPDATA(port)); if (inb (STATUS(port)) & 0x01) { @@ -397,6 +463,15 @@ size_t length, int flags) { size_t got = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + insb (EPPADDR (port), buf, length); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; got < length; got++) { *((char*)buf)++ = inb (EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -413,6 +488,15 @@ int flags) { size_t written = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + outsb (EPPADDR (port), buf, length); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; written < length; written++) { outb (*((char*)buf)++, EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -500,7 +584,8 @@ /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); - frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + /* set nErrIntrEn and serviceIntr */ + frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Forward mode. */ parport_pc_data_forward (port); /* Must be in PS2 mode */ @@ -575,6 +660,7 @@ left--; } +dump_parport_state ("leave fifo_write_block_dma", port); return length - left; } @@ -590,6 +676,7 @@ unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; +dump_parport_state ("enter fifo_write_block_dma", port); if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) @@ -608,7 +695,8 @@ /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); - frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + /* set nErrIntrEn and serviceIntr */ + frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Forward mode. */ parport_pc_data_forward (port); /* Must be in PS2 mode */ @@ -698,6 +786,7 @@ if (dma_handle) pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); +dump_parport_state ("leave fifo_write_block_dma", port); return length - left; } @@ -740,10 +829,10 @@ /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { - if (inb (ECONTROL (port)) & 0x2) + if (inb (ECONTROL (port)) & 0x2) { /* Full up. */ break; - + } outb (0, FIFO (port)); } @@ -791,9 +880,10 @@ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { printk (KERN_DEBUG "%s: PError timeout (%d) " "in ecp_write_block_pio\n", port->name, r); + } } /* Set up ECP parallel port mode.*/ @@ -824,10 +914,10 @@ /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { - if (inb (ECONTROL (port)) & 0x2) + if (inb (ECONTROL (port)) & 0x2) { /* Full up. */ break; - + } outb (0, FIFO (port)); } @@ -879,58 +969,99 @@ char *bufp = buf; port = port->physport; +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) return parport_ieee1284_ecp_read_data (port, buf, length, flags); - fifofull = fifo_depth; - if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) + if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) { /* If the peripheral is allowed to send RLE compressed * data, it is possible for a byte to expand to 128 * bytes in the FIFO. */ fifofull = 128; + } else { + fifofull = fifo_depth; + } /* If the caller wants less than a full FIFO's worth of data, - * go through software emulation. Otherwise we may have to through + * go through software emulation. Otherwise we may have to throw * away data. */ if (length < fifofull) return parport_ieee1284_ecp_read_data (port, buf, length, flags); - /* Switch to reverse mode if necessary. */ - if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) && - (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) { - /* Event 38: Set nAutoFd low */ + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { + /* change to reverse-idle phase (must be in forward-idle) */ + + /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */ parport_frob_control (port, - PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD + | PARPORT_CONTROL_STROBE, PARPORT_CONTROL_AUTOFD); parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); - /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); - - /* Event 40: PError goes low */ + /* Event 40: Wait for nAckReverse (PError) to go low */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); - if (r) + if (r) { printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " "in ecp_read_block_pio\n", port->name, r); + return 0; + } } /* Set up ECP FIFO mode.*/ - parport_pc_data_reverse (port); /* Must be in PS2 mode */ - parport_pc_frob_control (port, +/* parport_pc_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, - 0); + PARPORT_CONTROL_AUTOFD); */ r = change_mode (port, ECR_ECP); /* ECP FIFO */ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + /* the first byte must be collected manually */ +dump_parport_state ("pre 43", port); + /* Event 43: Wait for nAck to go low */ + r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); + if (r) { + /* timed out while reading -- no data */ + printk (KERN_DEBUG "PIO read timed out (initial byte)\n"); + goto out_no_data; + } + /* read byte */ + *bufp++ = inb (DATA (port)); + left--; +dump_parport_state ("43-44", port); + /* Event 44: nAutoFd (HostAck) goes high to acknowledge */ + parport_pc_frob_control (port, + PARPORT_CONTROL_AUTOFD, + 0); +dump_parport_state ("pre 45", port); + /* Event 45: Wait for nAck to go high */ +/* r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */ +dump_parport_state ("post 45", port); +r = 0; + if (r) { + /* timed out while waiting for peripheral to respond to ack */ + printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n"); + + /* keep hold of the byte we've got already */ + goto out_no_data; + } + /* Event 46: nAutoFd (HostAck) goes low to accept more data */ + parport_pc_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + +dump_parport_state ("rev idle", port); /* Do the transfer. */ while (left > fifofull) { int ret; @@ -949,31 +1080,35 @@ if (ecrval & 0x01) { /* FIFO is empty. Wait for interrupt. */ +dump_parport_state ("FIFO empty", port); /* Anyone else waiting for the port? */ if (port->waithead) { - printk (KERN_DEBUG - "Somebody wants the port\n"); + printk (KERN_DEBUG "Somebody wants the port\n"); break; } /* Clear serviceIntr */ outb (ecrval & ~(1<<2), ECONTROL (port)); false_alarm: +dump_parport_state ("waiting", port); ret = parport_wait_event (port, HZ); - if (ret < 0) break; +DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret); + if (ret < 0) + break; ret = 0; if (!time_before (jiffies, expire)) { /* Timed out. */ +dump_parport_state ("timeout", port); printk (KERN_DEBUG "PIO read timed out\n"); break; } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { if (current->need_resched && - time_before (jiffies, expire)) + time_before (jiffies, expire)) { schedule (); - + } goto false_alarm; } @@ -986,12 +1121,15 @@ if (ecrval & 0x02) { /* FIFO is full. */ +dump_parport_state ("FIFO full", port); insb (fifo, bufp, fifo_depth); bufp += fifo_depth; left -= fifo_depth; continue; } +DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n"); + /* FIFO not filled. We will cycle this loop for a while * and either the peripheral will fill it faster, * tripping a fast empty with insb, or we empty it. */ @@ -999,17 +1137,29 @@ left--; } + /* scoop up anything left in the FIFO */ + while (left && !(inb (ECONTROL (port) & 0x01))) { + *bufp++ = inb (fifo); + left--; + } + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; +dump_parport_state ("rev idle2", port); + +out_no_data: + + /* Go to forward idle mode to shut the peripheral up (event 47). */ + parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); - /* Go to forward idle mode to shut the peripheral up. */ - parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + /* event 49: PError goes high */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { printk (KERN_DEBUG "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", port->name, r); + } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; @@ -1022,13 +1172,21 @@ port->name, lost); } +dump_parport_state ("fwd idle", port); return length - left; } #endif /* IEEE 1284 support */ - #endif /* Allowed to use FIFO/DMA */ + +/* + * ****************************************** + * INITIALISATION AND MODULE STUFF BELOW HERE + * ****************************************** + */ + + void parport_pc_inc_use_count(void) { #ifdef MODULE @@ -1107,20 +1265,20 @@ cr27=inb(io+1); outb(0xaa,io); - printk ("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " + printk (KERN_INFO "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n", cr1,cr4,cra,cr23,cr26,cr27); /* The documentation calls DMA and IRQ-Lines by letters, so the board maker can/will wire them appropriately/randomly... G=reserved H=IDE-irq, */ - printk ("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, " + printk (KERN_INFO "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, " "fifo threshold=%d\n", cr23*4, (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-', (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f); - printk("SMSC LPT Config: enabled=%s power=%s\n", + printk(KERN_INFO "SMSC LPT Config: enabled=%s power=%s\n", (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no"); - printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n", + printk(KERN_INFO "SMSC LPT Config: Port mode=%s, EPP version =%s\n", (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], (cr4 & 0x40) ? "1.7" : "1.9"); @@ -1132,7 +1290,7 @@ while((superios[i].io!= 0) && (i 3) printk("dma=none\n"); else printk("dma=%d\n",cr74 & 0x07); - printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", + printk(KERN_INFO "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", irqtypes[crf0>>7], (crf0>>3)&0x0f); - printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]); + printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]); if(cr30 & 0x01) { /* the settings can be interrogated later ... */ while((superios[i].io!= 0) && (i>3) & 0x07]); else printk(""); - printk ( " dma="); + printk (" dma="); if( (configb & 0x03 ) == 0x00) printk("\n"); else @@ -1756,17 +1914,19 @@ */ /* If EPP timeout bit clear then EPP available */ - if (!clear_epp_timeout(pb)) + if (!clear_epp_timeout(pb)) { return 0; /* No way to clear timeout */ + } /* Check for Intel bug. */ if (priv->ecr) { unsigned char i; for (i = 0x00; i < 0x80; i += 0x20) { outb (i, ECONTROL (pb)); - if (clear_epp_timeout (pb)) + if (clear_epp_timeout (pb)) { /* Phony EPP in ECP. */ return 0; + } } } @@ -1787,8 +1947,9 @@ int result; unsigned char oecr; - if (!priv->ecr) + if (!priv->ecr) { return 0; + } oecr = inb (ECONTROL (pb)); /* Search for SMC style EPP+ECP mode */ @@ -1930,10 +2091,11 @@ pb->irq = programmable_irq_support(pb); } - if (pb->modes & PARPORT_MODE_ECP) + if (pb->modes & PARPORT_MODE_ECP) { pb->irq = irq_probe_ECP(pb); + } - if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && + if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr && (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); @@ -1978,11 +2140,12 @@ const struct parport_pc_private *priv = p->private_data; if (priv->ecr) p->dma = programmable_dma_support(p); /* ask ECP chipset first */ - if (p->dma == PARPORT_DMA_NONE) + if (p->dma == PARPORT_DMA_NONE) { /* ask known Super-IO chips proper, although these claim ECP compatible, some don't report their DMA conforming to ECP standards */ p->dma = get_superio_dma(p); + } return p->dma; } @@ -2092,6 +2255,8 @@ p->ops->compat_write_data = parport_pc_compat_write_block_pio; #ifdef CONFIG_PARPORT_1284 p->ops->ecp_write_data = parport_pc_ecp_write_block_pio; + /* currently broken, but working on it.. (FB) */ + /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ #endif /* IEEE 1284 support */ if (p->dma != PARPORT_DMA_NONE) { printk(", dma %d", p->dma); @@ -2576,7 +2741,7 @@ } #else static struct pci_driver parport_pc_pci_driver; -static int __init parport_pc_init_superio(void) {return 0;} +static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} #endif /* CONFIG_PCI */ /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c --- v2.4.4/linux/drivers/parport/parport_sunbpp.c Sun Feb 18 19:49:54 2001 +++ linux/drivers/parport/parport_sunbpp.c Tue May 22 19:54:04 2001 @@ -74,7 +74,7 @@ struct bpp_regs *regs = (struct bpp_regs *)p->base; sbus_writeb(d, ®s->p_dr); - dprintk(("wrote 0x%x\n", d)); + dprintk((KERN_DEBUG "wrote 0x%x\n", d)); } static unsigned char parport_sunbpp_read_data(struct parport *p) @@ -123,8 +123,8 @@ if (!(value_tcr & P_TCR_BUSY)) bits |= PARPORT_STATUS_BUSY; - dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); - dprintk(("read status 0x%x\n", bits)); + dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); + dprintk((KERN_DEBUG "read status 0x%x\n", bits)); return bits; } @@ -144,8 +144,8 @@ if (value_or & P_OR_SLCT_IN) bits |= PARPORT_CONTROL_SELECT; - dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); - dprintk(("read control 0x%x\n", bits)); + dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + dprintk((KERN_DEBUG "read control 0x%x\n", bits)); return bits; } @@ -162,7 +162,7 @@ unsigned char value_tcr = sbus_readb(®s->p_tcr); unsigned char value_or = sbus_readb(®s->p_or); - dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); if (mask & PARPORT_CONTROL_STROBE) { if (val & PARPORT_CONTROL_STROBE) { value_tcr &= ~P_TCR_DS; @@ -194,7 +194,7 @@ sbus_writeb(value_or, ®s->p_or); sbus_writeb(value_tcr, ®s->p_tcr); - dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); return parport_sunbpp_read_control(p); } @@ -218,7 +218,7 @@ struct bpp_regs *regs = (struct bpp_regs *)p->base; unsigned char value_tcr = sbus_readb(®s->p_tcr); - dprintk(("forward\n")); + dprintk((KERN_DEBUG "forward\n")); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); } @@ -228,7 +228,7 @@ struct bpp_regs *regs = (struct bpp_regs *)p->base; u8 val = sbus_readb(®s->p_tcr); - dprintk(("reverse\n")); + dprintk((KERN_DEBUG "reverse\n")); val |= P_TCR_DIR; sbus_writeb(val, ®s->p_tcr); } @@ -311,7 +311,7 @@ struct bpp_regs *regs; unsigned char value_tcr; - dprintk(("init_one_port(%p): ranges, alloc_io, ", sdev)); + dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, @@ -328,7 +328,7 @@ memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); - dprintk(("register_port, ")); + dprintk(("register_port\n")); if (!(p = parport_register_port(base, irq, dma, ops))) { kfree(ops); sbus_iounmap(base, size); @@ -337,7 +337,7 @@ p->size = size; - dprintk(("init_one_port: request_irq(%08x:%p:%x:%s:%p) ", + dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ", p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); if ((err = request_irq(p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)) != 0) { @@ -352,7 +352,7 @@ } regs = (struct bpp_regs *)p->base; - dprintk(("forward\n")); + dprintk((KERN_DEBUG "forward\n")); value_tcr = sbus_readb(®s->p_tcr); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); diff -u --recursive --new-file v2.4.4/linux/drivers/parport/probe.c linux/drivers/parport/probe.c --- v2.4.4/linux/drivers/parport/probe.c Sat Feb 3 12:43:37 2001 +++ linux/drivers/parport/probe.c Tue May 22 19:54:04 2001 @@ -62,7 +62,7 @@ struct parport_device_info *info = &port->probe_info[device + 1]; if (!txt) { - printk("%s probe: memory squeeze\n", port->name); + printk(KERN_WARNING "%s probe: memory squeeze\n", port->name); return; } strcpy(txt, str); diff -u --recursive --new-file v2.4.4/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.4.4/linux/drivers/parport/share.c Mon Mar 26 15:41:19 2001 +++ linux/drivers/parport/share.c Tue May 22 19:54:04 2001 @@ -1103,7 +1103,7 @@ if (ep != str[i]) val[i] = r; else { - printk("parport: bad specifier `%s'\n", str[i]); + printk(KERN_ERR "parport: bad specifier `%s'\n", str[i]); return -1; } } diff -u --recursive --new-file v2.4.4/linux/drivers/pci/Makefile linux/drivers/pci/Makefile --- v2.4.4/linux/drivers/pci/Makefile Fri Apr 13 20:31:32 2001 +++ linux/drivers/pci/Makefile Sat May 19 17:49:14 2001 @@ -22,6 +22,7 @@ obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o +obj-$(CONFIG_ALL_PPC) += setup-bus.o ifndef CONFIG_X86 obj-y += syscall.o diff -u --recursive --new-file v2.4.4/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.4/linux/drivers/pci/pci.c Thu Apr 19 08:38:48 2001 +++ linux/drivers/pci/pci.c Sat May 19 17:43:06 2001 @@ -843,7 +843,7 @@ * Ugh. We don't know enough about this bridge. Just assume * that it's entirely transparent. */ - printk("Unknown bridge resource %d: assuming transparent\n", 0); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0); child->resource[0] = child->parent->resource[0]; } @@ -859,7 +859,7 @@ res->name = child->name; } else { /* See comment above. Same thing */ - printk("Unknown bridge resource %d: assuming transparent\n", 1); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1); child->resource[1] = child->parent->resource[1]; } @@ -886,7 +886,7 @@ res->name = child->name; } else { /* See comments above */ - printk("Unknown bridge resource %d: assuming transparent\n", 2); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2); child->resource[2] = child->parent->resource[2]; } } @@ -1484,7 +1484,7 @@ page->vaddr = pci_alloc_consistent (pool->dev, pool->allocation, &page->dma); if (page->vaddr) { - memset (page->bitmap, ~0, mapsize); // bit set == free + memset (page->bitmap, 0xff, mapsize); // bit set == free if (pool->flags & SLAB_POISON) memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); list_add (&page->page_list, &pool->page_list); @@ -1500,7 +1500,7 @@ is_page_busy (int blocks, unsigned long *bitmap) { while (blocks > 0) { - if (*bitmap++ != ~0) + if (*bitmap++ != ~0UL) return 1; blocks -= BITS_PER_LONG; } @@ -1589,9 +1589,8 @@ i += BITS_PER_LONG, map++) { if (page->bitmap [map] == 0) continue; - block = ffs (page->bitmap [map]); - if ((i + block) <= pool->blocks_per_page) { - block--; + block = ffz (~ page->bitmap [map]); + if ((i + block) < pool->blocks_per_page) { clear_bit (block, &page->bitmap [map]); offset = (BITS_PER_LONG * map) + block; offset *= pool->size; @@ -1687,7 +1686,7 @@ block %= BITS_PER_LONG; #ifdef CONFIG_PCIPOOL_DEBUG - if (page->bitmap [map] & (1 << block)) { + if (page->bitmap [map] & (1UL << block)) { printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", pool->dev ? pool->dev->slot_name : NULL, pool->name, dma); @@ -1701,8 +1700,11 @@ set_bit (block, &page->bitmap [map]); if (waitqueue_active (&pool->waitq)) wake_up (&pool->waitq); - else if (!is_page_busy (pool->blocks_per_page, page->bitmap)) - pool_free_page (pool, page); + /* + * Resist a temptation to do + * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page); + * it is not interrupt safe. Better have empty pages hang around. + */ spin_unlock_irqrestore (&pool->lock, flags); } diff -u --recursive --new-file v2.4.4/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.4/linux/drivers/pci/pci.ids Sun Mar 25 18:14:20 2001 +++ linux/drivers/pci/pci.ids Sat May 19 17:49:14 2001 @@ -1069,6 +1069,13 @@ 000e Hydra Mac I/O 0010 Heathrow Mac I/O 0017 Paddington Mac I/O + 0018 UniNorth FireWire + 0019 KeyLargo USB + 001e UniNorth PCI + 001f UniNorth PCI + 0020 UniNorth AGP + 0021 UniNorth GMAC + 0022 KeyLargo Mac I/O 106c Hyundai Electronics America 8801 Dual Pentium ISA/PCI Motherboard 8802 PowerPC ISA/PCI Motherboard diff -u --recursive --new-file v2.4.4/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.4.4/linux/drivers/pci/proc.c Fri Nov 17 16:51:47 2000 +++ linux/drivers/pci/proc.c Sat May 19 12:48:33 2001 @@ -191,10 +191,109 @@ return nbytes; } +struct pci_filp_private { + enum pci_mmap_state mmap_state; + int write_combine; +}; + +static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + const struct proc_dir_entry *dp = inode->u.generic_ip; + struct pci_dev *dev = dp->data; +#ifdef HAVE_PCI_MMAP + struct pci_filp_private *fpriv = file->private_data; +#endif /* HAVE_PCI_MMAP */ + int ret = 0; + + switch (cmd) { + case PCIIOC_CONTROLLER: + ret = pci_controller_num(dev); + break; + +#ifdef HAVE_PCI_MMAP + case PCIIOC_MMAP_IS_IO: + fpriv->mmap_state = pci_mmap_io; + break; + + case PCIIOC_MMAP_IS_MEM: + fpriv->mmap_state = pci_mmap_mem; + break; + + case PCIIOC_WRITE_COMBINE: + if (arg) + fpriv->write_combine = 1; + else + fpriv->write_combine = 0; + break; + +#endif /* HAVE_PCI_MMAP */ + + default: + ret = -EINVAL; + break; + }; + + return ret; +} + +#ifdef HAVE_PCI_MMAP +static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file->f_dentry->d_inode; + const struct proc_dir_entry *dp = inode->u.generic_ip; + struct pci_dev *dev = dp->data; + struct pci_filp_private *fpriv = file->private_data; + int ret; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + ret = pci_mmap_page_range(dev, vma, + fpriv->mmap_state, + fpriv->write_combine); + if (ret < 0) + return ret; + + return 0; +} + +static int proc_bus_pci_open(struct inode *inode, struct file *file) +{ + struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL); + + if (!fpriv) + return -ENOMEM; + + fpriv->mmap_state = pci_mmap_io; + fpriv->write_combine = 0; + + file->private_data = fpriv; + + return 0; +} + +static int proc_bus_pci_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + file->private_data = NULL; + + return 0; +} +#endif /* HAVE_PCI_MMAP */ + static struct file_operations proc_bus_pci_operations = { - llseek: proc_bus_pci_lseek, - read: proc_bus_pci_read, - write: proc_bus_pci_write, + llseek: proc_bus_pci_lseek, + read: proc_bus_pci_read, + write: proc_bus_pci_write, + ioctl: proc_bus_pci_ioctl, +#ifdef HAVE_PCI_MMAP + open: proc_bus_pci_open, + release: proc_bus_pci_release, + mmap: proc_bus_pci_mmap, +#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA + get_unmapped_area: get_pci_unmapped_area, +#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */ +#endif /* HAVE_PCI_MMAP */ }; #if BITS_PER_LONG == 32 diff -u --recursive --new-file v2.4.4/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.4.4/linux/drivers/pci/quirks.c Thu Apr 19 22:57:06 2001 +++ linux/drivers/pci/quirks.c Sat May 19 17:43:06 2001 @@ -12,6 +12,7 @@ * use the PowerTweak utility (see http://powertweak.sourceforge.net). */ +#include #include #include #include @@ -31,7 +32,7 @@ while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); + printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } @@ -88,23 +89,44 @@ * VIA Apollo KT133 needs PCI latency patch * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm + * Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for + * the info on which Mr Breese based his work. */ static void __init quirk_vialatency(struct pci_dev *dev) { u8 r70; - - printk(KERN_INFO "Applying VIA PCI latency patch.\n"); - /* - * In register 0x70, mask off bit 2 (PCI Master read caching) - * and 1 (Delay Transaction) - */ - pci_read_config_byte(dev, 0x70, &r70); - r70 &= 0xf9; - pci_write_config_byte(dev, 0x70, r70); - /* - * Turn off PCI Latency timeout (set to 0 clocks) + u8 rev; + struct pci_dev *vt82c686; + + + /* we want to look for a VT82C686 south bridge, and then apply the via latency + * patch if we find that it's a 686B (by revision) */ - pci_write_config_byte(dev, 0x75, 0x80); + vt82c686 = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); + if (vt82c686) + { + pci_read_config_byte(vt82c686, PCI_CLASS_REVISION, &rev); + /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ + if (rev >= 0x40 && rev <= 0x4f) + { + printk(KERN_INFO "Applying VIA PCI latency patch (found VT82C686B).\n"); + /* + * In register 0x70, mask off bit 2 (PCI Master read caching) + * and 1 (Delay Transaction) + */ + pci_read_config_byte(dev, 0x70, &r70); + r70 &= 0xf9; + pci_write_config_byte(dev, 0x70, r70); + /* + * Turn off PCI Latency timeout (set to 0 clocks) + */ + pci_write_config_byte(dev, 0x75, 0x80); + } + else + { + printk(KERN_INFO "Found VT82C686A, not applying VIA latency patch.\n"); + } + } /* if (vt82c686) ... */ } /* @@ -238,6 +260,30 @@ quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); } + +#ifdef CONFIG_X86_IO_APIC +extern int nr_ioapics; + +/* + * VIA 686A/B: If an IO-APIC is active, we need to route all on-chip + * devices to the external APIC. + */ +static void __init quirk_via_ioapic(struct pci_dev *dev) +{ + u8 tmp; + + if (nr_ioapics < 1) + tmp = 0; /* nothing routed to external APIC */ + else + tmp = 0x1f; /* all known bits (4-0) routed to external APIC */ + + /* Offset 0x58: External APIC IRQ output control */ + pci_write_config_byte (dev, 0x58, tmp); +} + +#endif /* CONFIG_X86_IO_APIC */ + + /* * PIIX3 USB: We have to disable USB interrupts that are * hardwired to PIRQD# and may be shared with an @@ -322,6 +368,11 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb }, { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy }, + +#ifdef CONFIG_X86_IO_APIC + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic }, +#endif + { 0 } }; @@ -333,7 +384,7 @@ (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); + printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); #endif f->hook(dev); } diff -u --recursive --new-file v2.4.4/linux/drivers/pci/setup-bus.c linux/drivers/pci/setup-bus.c --- v2.4.4/linux/drivers/pci/setup-bus.c Mon Dec 11 13:46:26 2000 +++ linux/drivers/pci/setup-bus.c Sat May 19 17:43:06 2001 @@ -136,9 +136,9 @@ ranges.mem_end = bus->resource[1]->end; pcibios_fixup_pbus_ranges(bus, &ranges); - DBGC(("PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); - DBGC((" IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end)); - DBGC((" MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end)); + DBGC((KERN_ERR "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); + DBGC((KERN_ERR " IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end)); + DBGC((KERN_ERR " MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end)); /* Set up the top and bottom of the PCI I/O segment for this bus. */ pci_read_config_dword(bridge, PCI_IO_BASE, &l); diff -u --recursive --new-file v2.4.4/linux/drivers/pci/setup-irq.c linux/drivers/pci/setup-irq.c --- v2.4.4/linux/drivers/pci/setup-irq.c Tue Jan 11 14:22:31 2000 +++ linux/drivers/pci/setup-irq.c Sat May 19 17:43:06 2001 @@ -53,7 +53,7 @@ irq = 0; dev->irq = irq; - DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq)); + DBGC((KERN_ERR "PCI fixup irq: (%s) got %d\n", dev->name, dev->irq)); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff -u --recursive --new-file v2.4.4/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c --- v2.4.4/linux/drivers/pci/setup-res.c Fri Apr 6 10:51:19 2001 +++ linux/drivers/pci/setup-res.c Sat May 19 17:43:06 2001 @@ -115,12 +115,13 @@ * window (it will just not perform as well). */ if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) { - printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name); + printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n", + i, res->start, res->end, dev->slot_name); return -EBUSY; } } - DBGC((" got res[%lx:%lx] for resource %d of %s\n", res->start, + DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start, res->end, i, dev->name)); return 0; @@ -164,7 +165,7 @@ if (r_size > size) { tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { - printk("pdev_sort_resources(): kmalloc() failed!\n"); + printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n"); continue; } tmp->next = ln; @@ -184,7 +185,7 @@ u16 cmd; int i; - DBGC(("PCI enable device: (%s)\n", dev->name)); + DBGC((KERN_ERR "PCI enable device: (%s)\n", dev->name)); pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -229,5 +230,5 @@ /* Enable the appropriate bits in the PCI command register. */ pci_write_config_word(dev, PCI_COMMAND, cmd); - DBGC((" cmd reg 0x%x\n", cmd)); + DBGC((KERN_ERR " cmd reg 0x%x\n", cmd)); } diff -u --recursive --new-file v2.4.4/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.4.4/linux/drivers/pcmcia/i82365.c Sat Mar 3 10:50:29 2001 +++ linux/drivers/pcmcia/i82365.c Tue May 1 16:05:00 2001 @@ -257,23 +257,31 @@ /*====================================================================*/ +static spinlock_t bus_lock = SPIN_LOCK_UNLOCKED; + static u_char i365_get(u_short sock, u_short reg) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val; reg = I365_REG(socket[sock].psock, reg); outb(reg, port); val = inb(port+1); + spin_unlock_irqrestore(&bus_lock,flags); return val; } } static void i365_set(u_short sock, u_short reg, u_char data) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); outb(val, port); outb(data, port+1); + spin_unlock_irqrestore(&bus_lock,flags); } } @@ -872,6 +880,13 @@ events = pending_events[i]; pending_events[i] = 0; spin_unlock_irq(&pending_event_lock); + /* + SS_DETECT events need a small delay here. The reason for this is that + the "is there a card" electronics need time to see the card after the + "we have a card coming in" electronics have seen it. + */ + if (events & SS_DETECT) + mdelay(2); if (socket[i].handler) socket[i].handler(socket[i].info, events); } @@ -881,6 +896,8 @@ routine: pcic_bh }; +static unsigned long last_detect_jiffies; + static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs) { @@ -906,6 +923,20 @@ continue; } events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; + + + /* Several sockets will send multiple "new card detected" + events in rapid succession. However, the rest of the pcmcia expects + only one such event. We just ignore these events by having a + timeout */ + + if (events) { + if ((jiffies - last_detect_jiffies)<(HZ/20)) + events = 0; + last_detect_jiffies = jiffies; + + } + if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; else { @@ -970,6 +1001,7 @@ status = i365_get(sock, I365_STATUS); *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; + if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; else { @@ -1247,7 +1279,7 @@ i = i365_get_pair(sock, base+I365_W_START); mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; - mem->sys_start += ((u_long)(i & 0x0fff) << 12); + mem->sys_start = ((u_long)(i & 0x0fff) << 12); i = i365_get_pair(sock, base+I365_W_STOP); mem->speed = (i & I365_MEM_WS0) ? 1 : 0; diff -u --recursive --new-file v2.4.4/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.4.4/linux/drivers/s390/block/dasd.c Wed Apr 11 19:02:28 2001 +++ linux/drivers/s390/block/dasd.c Tue May 15 01:29:34 2001 @@ -2892,7 +2892,7 @@ static ssize_t dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset) { - char *buffer = vmalloc (user_len); + char *buffer = vmalloc (user_len+1); int off = 0; char *temp; int irq; diff -u --recursive --new-file v2.4.4/linux/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c --- v2.4.4/linux/drivers/s390/char/hwc_tty.c Thu Apr 12 12:16:35 2001 +++ linux/drivers/s390/char/hwc_tty.c Tue May 22 10:23:16 2001 @@ -217,7 +217,7 @@ void hwc_tty_init (void) { -#ifdef CONFIG_3215 +#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE) if (MACHINE_IS_VM) return; #endif diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c --- v2.4.4/linux/drivers/sbus/char/aurora.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/sbus/char/aurora.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: aurora.c,v 1.11 2001/03/08 01:43:30 davem Exp $ +/* $Id: aurora.c,v 1.13 2001/05/10 01:45:38 davem Exp $ * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver * * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro) @@ -1632,33 +1632,55 @@ if (!tty || !port->xmit_buf || !tmp_buf) return 0; - if (from_user) - down(&tmp_buf_sem); - save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) - break; + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) + break; - if (from_user) { - copy_from_user(tmp_buf, buf, c); + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); - } else + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } memcpy(port->xmit_buf + port->xmit_head, buf, c); - port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - port->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } } - if (from_user) - up(&tmp_buf_sem); + + cli(); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->SRER & SRER_TXRDY)) { port->SRER |= SRER_TXRDY; diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.4.4/linux/drivers/sbus/char/pcikbd.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/sbus/char/pcikbd.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.53 2001/03/21 00:28:33 davem Exp $ +/* $Id: pcikbd.c,v 1.54 2001/05/11 07:46:28 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -28,6 +28,9 @@ #include #include +#if defined(CONFIG_USB) && defined(CONFIG_SPARC64) +#include +#endif #include #include #include @@ -451,6 +454,47 @@ } restore_flags(flags); } + +#if defined(CONFIG_USB) && defined(CONFIG_SPARC64) +static void isa_kd_nosound(unsigned long __unused) +{ + /* disable counter 2 */ + outb(inb(pcibeep_iobase + 0x61)&0xFC, pcibeep_iobase + 0x61); + return; +} + +static void isa_kd_mksound(unsigned int hz, unsigned int ticks) +{ + static struct timer_list sound_timer = { function: isa_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(inb(pcibeep_iobase + 0x61)|3, pcibeep_iobase + 0x61); + /* set command for counter 2, 2 byte write */ + outb(0xB6, pcibeep_iobase + 0x43); + /* select desired HZ */ + outb(count & 0xff, pcibeep_iobase + 0x42); + outb((count >> 8) & 0xff, pcibeep_iobase + 0x42); + + if (ticks) { + sound_timer.expires = jiffies+ticks; + add_timer(&sound_timer); + } + } else + isa_kd_nosound(0); + restore_flags(flags); + return; +} +#endif + #endif static void nop_kd_mksound(unsigned int hz, unsigned int ticks) @@ -550,6 +594,30 @@ } } } + +#ifdef CONFIG_SPARC64 + /* Maybe we have one inside the ALI southbridge? */ + { + struct isa_bridge *isa_br; + struct isa_device *isa_dev; + for_each_isa(isa_br) { + for_each_isadev(isa_dev, isa_br) { + /* This is a hack, the 'dma' device node has + * the base of the I/O port space for that PBM + * as it's resource, so we use that. -DaveM + */ + if (!strcmp(isa_dev->prom_name, "dma")) { + pcibeep_iobase = isa_dev->resource.start; + kd_mksound = isa_kd_mksound; + printk("isa(speaker): iobase[%016lx:%016lx]\n", + pcibeep_iobase + 0x42, + pcibeep_iobase + 0x61); + return; + } + } + } + } +#endif /* No beeper found, ok complain. */ #endif diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.4.4/linux/drivers/sbus/char/su.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/sbus/char/su.c Sat May 19 12:48:33 2001 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.47 2001/04/18 21:06:15 davem Exp $ +/* $Id: su.c,v 1.50 2001/05/16 08:37:03 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -75,6 +75,9 @@ #include #include #include +#ifdef CONFIG_SPARC64 +#include +#endif #include #include #include @@ -1411,6 +1414,41 @@ */ /* + * get_serial_info - handle TIOCGSERIAL ioctl() + * + * Purpose: Return standard serial struct information about + * a serial port handled by this driver. + * + * Added: 11-May-2001 Lars Kellogg-Stedman + */ +static int get_serial_info(struct su_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.xmit_fifo_size = info->xmit_fifo_size; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + tmp.hub6 = 0; + + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically @@ -1568,6 +1606,9 @@ case TIOCMSET: return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, (struct serial_struct *)arg); + case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -2220,7 +2261,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.47 $"; + char *revision = "$Revision: 1.50 $"; char *version, *p; version = strchr(revision, ' '); @@ -2243,6 +2284,10 @@ unsigned char status1, status2, scratch, scratch2; struct linux_ebus_device *dev = 0; struct linux_ebus *ebus; +#ifdef CONFIG_SPARC64 + struct isa_bridge *isa_br; + struct isa_device *isa_dev; +#endif #ifndef __sparc_v9__ struct linux_prom_registers reg0; #endif @@ -2263,6 +2308,18 @@ } } } + +#ifdef CONFIG_SPARC64 + for_each_isa(isa_br) { + for_each_isadev(isa_dev, isa_br) { + if (isa_dev->prom_node == info->port_node) { + info->port = isa_dev->resource.start; + info->irq = isa_dev->irq; + goto ebus_done; + } + } + } +#endif #ifdef __sparc_v9__ /* diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.4.4/linux/drivers/sbus/char/zs.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/sbus/char/zs.c Wed May 16 10:31:27 2001 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.63 2001/04/17 06:30:36 davem Exp $ +/* $Id: zs.c,v 1.65 2001/05/09 07:00:10 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1156,28 +1156,51 @@ return 0; save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - if (from_user) { - down(&tmp_buf_sem); - copy_from_user(tmp_buf, buf, c); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE - 1)); + info->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE - 1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } } cli(); @@ -1922,7 +1945,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.63 $"; + char *revision = "$Revision: 1.65 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ChangeLog.ips linux/drivers/scsi/ChangeLog.ips --- v2.4.4/linux/drivers/scsi/ChangeLog.ips Tue Sep 19 08:01:34 2000 +++ linux/drivers/scsi/ChangeLog.ips Sat May 19 17:43:06 2001 @@ -1,5 +1,25 @@ IBM ServeRAID driver Change Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size + + 4.71.00 - Change all memory allocations to not use GFP_DMA flag + Code Clean-Up for 2.4.x kernel + + 4.70.15 - Fix Breakup for very large ( non-SG ) requests + + 4.70.13 - Don't release HA Lock in ips_next() until SC taken off queue + - Unregister SCSI device in ips_release() + - Don't Send CDB's if we already know the device is not present + + 4.70.12 - Corrective actions for bad controller ( during initialization ) + + 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD + - Add IPSSEND Flash Support + - Set Sense Data for Unknown SCSI Command + - Use Slot Number from NVRAM Page 5 + - Restore caller's DCDB Structure + 4.20.14 - Update patch files for kernel 2.4.0-test5 4.20.13 - Fix some failure cases / reset code @@ -66,3 +86,4 @@ - Fixed read/write errors when the adapter is using an 8K stripe size. + \ No newline at end of file diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.4.4/linux/drivers/scsi/Makefile Mon Mar 26 15:36:30 2001 +++ linux/drivers/scsi/Makefile Fri May 4 15:16:28 2001 @@ -6,6 +6,12 @@ # # 20 Sep 2000, Torben Mathiasen # Changed link order to reflect new scsi initialization. +# +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! +# The link order must be, SCSI Core, SCSI HBA drivers, and +# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to +# satisfy certain initialization assumptions in the SCSI layer. +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! O_TARGET := scsidrv.o @@ -64,6 +70,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AIC7XXX),y) +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o +endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.4.4/linux/drivers/scsi/NCR53c406a.c Fri Mar 2 11:12:11 2001 +++ linux/drivers/scsi/NCR53c406a.c Tue May 22 10:23:16 2001 @@ -508,6 +508,7 @@ VDEB(printk("port_base=%x\n", port_base)); break; } + release_region(ports[i], 0x10); } } } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/README.ibmmca linux/drivers/scsi/README.ibmmca --- v2.4.4/linux/drivers/scsi/README.ibmmca Thu Jan 4 12:37:14 2001 +++ linux/drivers/scsi/README.ibmmca Tue May 22 10:23:16 2001 @@ -736,7 +736,7 @@ Feb 20, 1999 (v3.1e) 1) I took the warning from the Linux Kernel Hackers Guide serious and - checked the cmd->result return value to the done-function very carefuly. + checked the cmd->result return value to the done-function very carefully. It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if some error appeared, else it is undefined. Now, this is fixed. Before any SCB command gets queued, the tsb.dev_status is set to 0, so the @@ -1382,7 +1382,7 @@ 9 Disclaimer ------------ - Beside the GNU public license and the dependant disclaimers and disclaimers + Beside the GNU General Public License and the dependant disclaimers and disclaimers concerning the Linux-kernel in special, this SCSI-driver comes without any warranty. Its functionality is tested as good as possible on certain machines and combinations of computer hardware, which does not exclude, diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.4.4/linux/drivers/scsi/aha1542.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/scsi/aha1542.c Tue May 1 16:05:00 2001 @@ -254,7 +254,7 @@ /* Only used at boot time, so we do not need to worry about latency as much here */ -static int aha1542_in(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -276,7 +276,7 @@ /* Similar to aha1542_in, except that we wait a very short period of time. We use this if we know the board is alive and awake, but we are not sure if the board will respond to the command we are about to send or not */ -static int aha1542_in1(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -886,7 +886,7 @@ /* This function should only be called for 1542C boards - we can detect the special firmware settings and unlock the board */ -static int aha1542_mbenable(int base) +static int __init aha1542_mbenable(int base) { static unchar mbenable_cmd[3]; static unchar mbenable_result[2]; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/Config.in linux/drivers/scsi/aic7xxx/Config.in --- v2.4.4/linux/drivers/scsi/aic7xxx/Config.in Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/Config.in Fri May 4 15:16:28 2001 @@ -2,6 +2,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 - int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000 + int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000 + bool ' Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE fi fi diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/Makefile linux/drivers/scsi/aic7xxx/Makefile --- v2.4.4/linux/drivers/scsi/aic7xxx/Makefile Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/Makefile Fri May 4 15:16:28 2001 @@ -4,7 +4,7 @@ # Makefile for the Linux aic7xxx SCSI driver. # -O_TARGET = aic7xxx_drv.o +O_TARGET := aic7xxx_drv.o list-multi := aic7xxx_mod.o @@ -25,8 +25,13 @@ aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq +else +aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg + echo "Warning, generated aic7xxx firmware files may be out of date!\n" +endif aicasm/aicasm: aicasm/*.[chyl] $(MAKE) -C aicasm diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7770.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7770.c Fri May 4 15:16:28 2001 @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7770.c#6 $ + * $Id: //depot/src/aic7xxx/aic7770.c#11 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ */ @@ -95,8 +95,6 @@ u_int hostconf; u_int irq; u_int intdef; - u_int hcntrl; - int shared; ahc_init_probe_config(&probe_config); error = entry->setup(ahc->dev_softc, &probe_config); @@ -107,15 +105,15 @@ if (error != 0) return (error); - /* Pause the card preseving the IRQ type */ - hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS; - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; + probe_config.description = entry->name; + error = ahc_softc_init(ahc, &probe_config); + + error = ahc_reset(ahc); + if (error != 0) + return (error); /* Make sure we have a valid interrupt vector */ intdef = ahc_inb(ahc, INTDEF); - shared = (intdef & EDGE_TRIG) ? 0 : 1; irq = intdef & VECTOR; switch (irq) { case 9: @@ -130,16 +128,8 @@ return (ENXIO); } - probe_config.description = entry->name; - error = ahc_softc_init(ahc, &probe_config); - - error = aic7770_map_int(ahc, irq, shared); - if (error != 0) - return (error); - - error = ahc_reset(ahc); - if (error != 0) - return (error); + if ((intdef & EDGE_TRIG) != 0) + ahc->flags |= AHC_EDGE_INTERRUPT; switch (probe_config.chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: @@ -154,7 +144,7 @@ /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= 1; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; @@ -210,10 +200,19 @@ */ ahc_softc_insert(ahc); + error = aic7770_map_int(ahc, irq); + if (error != 0) + return (error); + /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); + + /* + * Allow interrupts. + */ + ahc_intr_enable(ahc, TRUE); return (0); } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7770_linux.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7770_linux.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $ */ #include "aic7xxx_osm.h" @@ -128,19 +128,18 @@ } int -aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared) +aic7770_map_int(struct ahc_softc *ahc, u_int irq) { int error; + int shared; - if (shared) + shared = 0; + if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) shared = SA_SHIRQ; ahc->platform_data->irq = irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|shared, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - shared, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + shared, "aic7xxx", ahc); return (-error); } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $ + * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ */ @@ -58,9 +58,17 @@ "aic7892", "aic7899" }; -const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); +static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); -struct hard_error_entry hard_error[] = { +/* + * Hardware error codes. + */ +struct ahc_hard_error_entry { + uint8_t errno; + char *errmesg; +}; + +static struct ahc_hard_error_entry ahc_hard_errors[] = { { ILLHADDR, "Illegal Host Access" }, { ILLSADDR, "Illegal Sequencer Address referrenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, @@ -70,9 +78,9 @@ { PCIERRSTAT, "PCI Error detected" }, { CIOPARERR, "CIOBUS Parity Error" }, }; -const u_int num_errors = NUM_ELEMENTS(hard_error); +static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); -struct phase_table_entry phase_table[] = +static struct ahc_phase_table_entry ahc_phase_table[] = { { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, @@ -90,14 +98,14 @@ * In most cases we only wish to itterate over real phases, so * exclude the last element from the count. */ -const u_int num_phases = NUM_ELEMENTS(phase_table) - 1; +static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; /* * Valid SCSIRATE values. (p. 3-17) * Provides a mapping of tranfer periods in ns to the proper value to * stick in the scsixfer reg. */ -struct ahc_syncrate ahc_syncrates[] = +static struct ahc_syncrate ahc_syncrates[] = { /* ultra2 fast/ultra period rate */ { 0x42, 0x000, 9, "80.0" }, @@ -121,7 +129,7 @@ #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ -static struct tmode_tstate* +static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); #ifdef AHC_TARGET_MODE @@ -134,12 +142,13 @@ u_int *period, u_int *ppr_options, role_t role); -static void ahc_update_pending_syncrates(struct ahc_softc *ahc); +static void ahc_update_pending_scbs(struct ahc_softc *ahc); static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); +static void ahc_assert_atn(struct ahc_softc *ahc); static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -174,6 +183,11 @@ struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); +#if AHC_TARGET_MODE +static void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +#endif static bus_dmamap_callback_t ahc_dmamap_cb; static void ahc_build_free_scb_list(struct ahc_softc *ahc); @@ -192,7 +206,6 @@ char channel, int lun, u_int tag, role_t role, uint32_t status); static void ahc_reset_current_bus(struct ahc_softc *ahc); -static void ahc_calc_residual(struct scb *scb); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); #endif @@ -204,7 +217,7 @@ u_int instrptr, uint8_t *dconsts); #ifdef AHC_TARGET_MODE static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct tmode_lstate *lstate, + struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg); @@ -218,10 +231,10 @@ * Restart the sequencer program from address zero */ void -restart_sequencer(struct ahc_softc *ahc) +ahc_restart(struct ahc_softc *ahc) { - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ @@ -259,7 +272,7 @@ ahc_outb(ahc, SEQCTL, FASTMODE); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); - unpause_sequencer(ahc); + ahc_unpause(ahc); } /************************* Input/Output Queues ********************************/ @@ -300,10 +313,7 @@ * Save off the residual * if there is one. */ - if (ahc_check_residual(scb) != 0) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + ahc_update_residual(scb); ahc_done(ahc, scb); } } @@ -340,14 +350,14 @@ * We upset the sequencer :-( * Lookup the error message */ - int i, error, num_errors; + int i; + int error; error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, + ahc_name(ahc), ahc_hard_errors[i].errmesg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); @@ -436,6 +446,12 @@ break; case SCSI_STATUS_CMD_TERMINATED: case SCSI_STATUS_CHECK_COND: + { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + struct ahc_transinfo *tinfo; #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -444,99 +460,94 @@ } #endif - if (ahc_perform_autosense(scb)) { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; - struct ahc_transinfo *tinfo; + if (ahc_perform_autosense(scb) == 0) + break; - targ_info = - ahc_fetch_transinfo(ahc, + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); - tinfo = &targ_info->current; - sg = scb->sg_list; - sc = (struct scsi_sense *) - (&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - if (ahc_check_residual(scb)) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + tinfo = &targ_info->curr; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + ahc_update_residual(scb); #ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("Sending Sense\n"); - } + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } #endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; - /* - * XXX Still true??? - * Would be nice to preserve DISCENB here, - * but due to the way we manage busy targets, - * we can't. - */ - hscb->control = 0; + /* + * We can't allow the target to disconnect. + * This will be an untagged transaction and + * having the target disconnect will make this + * transaction indestinguishable from outstanding + * tagged transactions. + */ + hscb->control = 0; - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_target_msg_request(ahc, - &devinfo, - targ_info, - /*force*/TRUE, - /*paused*/TRUE); - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_neg_request(ahc, &devinfo, + tstate, targ_info, + /*force*/TRUE); + } + if (tstate->auto_negotiate & devinfo.target_mask) { + hscb->control |= MK_MESSAGE; + scb->flags &= ~SCB_NEGOTIATE; + scb->flags |= SCB_AUTO_NEGOTIATE; + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); #ifdef __FreeBSD__ - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, 5 * hz); + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); #endif - } break; + } default: break; } @@ -577,7 +588,7 @@ ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); + ahc_assert_atn(ahc); break; } case SEND_REJECT: @@ -633,7 +644,7 @@ "Lastphase = 0x%x, Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); - restart_sequencer(ahc); + ahc_restart(ahc); return; } case HOST_MSG_LOOP: @@ -650,6 +661,8 @@ * loop. */ if (ahc->msg_type == MSG_TYPE_NONE) { + struct scb *scb; + u_int scb_index; u_int bus_phase; bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -663,17 +676,13 @@ * we got here. Just punt the message. */ ahc_clear_intstat(ahc); - restart_sequencer(ahc); + ahc_restart(ahc); return; } + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); if (devinfo.role == ROLE_INITIATOR) { - struct scb *scb; - u_int scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) panic("HOST_MSG_LOOP with " "invalid SCB %x\n", scb_index); @@ -695,7 +704,9 @@ } #if AHC_TARGET_MODE else - ahc_setup_target_msgin(ahc, &devinfo); + ahc_setup_target_msgin(ahc, + &devinfo, + scb); #endif } } @@ -718,17 +729,20 @@ */ if ((intstat & SCSIINT) == 0 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - u_int curphase; - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); + if ((ahc->features & AHC_DT) == 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + } ahc_inb(ahc, SCSIDATL); } break; @@ -749,13 +763,13 @@ scb = ahc_lookup_scb(ahc, scbindex); for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } ahc_print_path(ahc, scb); printf("data overrun detected %s." " Tag == 0x%x.\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, scb->hscb->tag); ahc_print_path(ahc, scb); printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", @@ -858,7 +872,7 @@ * a SEQINT, so we should restart it when * we're done. */ - unpause_sequencer(ahc); + ahc_unpause(ahc); } void @@ -897,7 +911,7 @@ if (status == 0) { printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); return; } } @@ -975,10 +989,10 @@ errorphase = lastphase; for (i = 0; i < num_phases; i++) { - if (errorphase == phase_table[i].phase) + if (errorphase == ahc_phase_table[i].phase) break; } - mesg_out = phase_table[i].mesg_out; + mesg_out = ahc_phase_table[i].mesg_out; if (scb != NULL) ahc_print_path(ahc, scb); else @@ -987,7 +1001,7 @@ scsirate = ahc_inb(ahc, SCSIRATE); printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), scsirate); @@ -1018,7 +1032,45 @@ ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessful + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { u_int lastphase; @@ -1113,7 +1165,7 @@ } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, FALSE)) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; /* * PPR Rejected. Try non-ppr negotiation @@ -1124,7 +1176,7 @@ devinfo.our_scsiid, devinfo.target, &tstate); - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; tinfo->goal.ppr_options = 0; ahc_qinfifo_requeue_tail(ahc, scb); @@ -1174,54 +1226,18 @@ printf("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", - phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - } else { - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); + ahc_restart(ahc); } else { printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); @@ -1290,7 +1306,7 @@ ahc_outb(ahc, HCNTRL, ahc->unpause); do { ahc_delay(200); - } while (!sequencer_paused(ahc)); + } while (!ahc_is_paused(ahc)); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1363,11 +1379,11 @@ * Allocate per target mode instance (ID we respond to as a target) * transfer negotiation data structures. */ -static struct tmode_tstate * +static struct ahc_tmode_tstate * ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) { - struct tmode_tstate *master_tstate; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *master_tstate; + struct ahc_tmode_tstate *tstate; int i; master_tstate = ahc->enabled_targets[ahc->our_id]; @@ -1394,8 +1410,8 @@ memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].current, 0, - sizeof(tstate->transinfo[i].current)); + memset(&tstate->transinfo[i].curr, 0, + sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, sizeof(tstate->transinfo[i].goal)); } @@ -1413,11 +1429,13 @@ static void ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; - /* Don't clean up the entry for our initiator role */ - if ((ahc->flags & AHC_INITIATORROLE) != 0 - && ((channel == 'B' && scsi_id == ahc->our_id_b) + /* + * Don't clean up our "master" tstate. + * It has our default user settings. + */ + if (((channel == 'B' && scsi_id == ahc->our_id_b) || (channel == 'A' && scsi_id == ahc->our_id)) && force == FALSE) return; @@ -1496,6 +1514,11 @@ if ((ahc->features & AHC_DT) == 0) *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + /* Skip all DT only entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && maxsync < AHC_SYNCRATE_ULTRA2) + maxsync = AHC_SYNCRATE_ULTRA2; for (syncrate = &ahc_syncrates[maxsync]; syncrate->rate != NULL; @@ -1509,11 +1532,6 @@ && (syncrate->sxfr_u2 == 0)) break; - /* Skip any DT entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && (syncrate->sxfr_u2 & DT_SXFR) != 0) - continue; - if (*period <= syncrate->period) { /* * When responding to a target that requests @@ -1647,44 +1665,31 @@ * means the next time we send the initial identify messages for * a new transaction. */ -void -ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused) -{ - u_int targ_msg_req_orig; - - targ_msg_req_orig = ahc->targ_msg_req; - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options +int +ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_tmode_tstate *tstate, + struct ahc_initiator_tinfo *tinfo, int force) +{ + u_int auto_negotiate_orig; + + auto_negotiate_orig = tstate->auto_negotiate; + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options || (force && (tinfo->goal.period != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT || tinfo->goal.ppr_options != 0))) - ahc->targ_msg_req |= devinfo->target_mask; + tstate->auto_negotiate |= devinfo->target_mask; else - ahc->targ_msg_req &= ~devinfo->target_mask; + tstate->auto_negotiate &= ~devinfo->target_mask; - if (ahc->targ_msg_req != targ_msg_req_orig) { - /* Update the message request bit for this target */ - if (!paused) - pause_sequencer(ahc); - - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - - if (!paused) - unpause_sequencer(ahc); - } + return (auto_negotiate_orig != tstate->auto_negotiate); } /* - * Update the user/goal/current tables of synchronous negotiation + * Update the user/goal/curr tables of synchronous negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1697,11 +1702,15 @@ u_int offset, u_int ppr_options, u_int type, int paused) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int old_period; u_int old_offset; u_int old_ppr; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; if (syncrate == NULL) { period = 0; @@ -1723,9 +1732,9 @@ tinfo->goal.ppr_options = ppr_options; } - old_period = tinfo->current.period; - old_offset = tinfo->current.offset; - old_ppr = tinfo->current.ppr_options; + old_period = tinfo->curr.period; + old_offset = tinfo->curr.offset; + old_ppr = tinfo->curr.ppr_options; if ((type & AHC_TRANS_CUR) != 0 && (old_period != period @@ -1733,6 +1742,7 @@ || old_ppr != ppr_options)) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1777,15 +1787,12 @@ } tinfo->scsirate = scsirate; - tinfo->current.period = period; - tinfo->current.offset = offset; - tinfo->current.ppr_options = ppr_options; - - /* Update the syncrates in any pending scbs */ - ahc_update_pending_syncrates(ahc); + tinfo->curr.period = period; + tinfo->curr.offset = offset; + tinfo->curr.ppr_options = ppr_options; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -1801,13 +1808,15 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, - paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + + if (update_needed) + ahc_update_pending_scbs(ahc); } /* - * Update the user/goal/current tables of wide negotiation + * Update the user/goal/curr tables of wide negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1818,11 +1827,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - u_int oldwidth; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int oldwidth; + int active; + int update_needed; + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); @@ -1832,10 +1844,11 @@ if ((type & AHC_TRANS_GOAL) != 0) tinfo->goal.width = width; - oldwidth = tinfo->current.width; + oldwidth = tinfo->curr.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) @@ -1846,10 +1859,10 @@ if (active) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->current.width = width; + tinfo->curr.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -1857,35 +1870,22 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + if (update_needed) + ahc_update_pending_scbs(ahc); } /* * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t orig_tagenable; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - orig_tagenable = tstate->tagenable; - if (enable) - tstate->tagenable |= devinfo->target_mask; - else - tstate->tagenable &= ~devinfo->target_mask; - - if (orig_tagenable != tstate->tagenable) { - ahc_platform_set_tags(ahc, devinfo, enable); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); - } - + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); } /* @@ -1894,11 +1894,12 @@ * be set correctly during future (re)selections. */ static void -ahc_update_pending_syncrates(struct ahc_softc *ahc) +ahc_update_pending_scbs(struct ahc_softc *ahc) { struct scb *pending_scb; int pending_scb_count; int i; + int paused; u_int saved_scbptr; /* @@ -1910,7 +1911,7 @@ struct ahc_devinfo devinfo; struct hardware_scb *pending_hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; ahc_scb_devinfo(ahc, &devinfo, pending_scb); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, @@ -1921,13 +1922,25 @@ if ((tstate->ultraenb & devinfo.target_mask) != 0) pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->current.offset; + pending_hscb->scsioffset = tinfo->curr.offset; + if ((tstate->auto_negotiate & devinfo.target_mask) == 0 + && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { + pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; + pending_hscb->control &= ~MK_MESSAGE; + } pending_scb_count++; } if (pending_scb_count == 0) return; + if (ahc_is_paused(ahc)) { + paused = 1; + } else { + paused = 0; + ahc_pause(ahc); + } + saved_scbptr = ahc_inb(ahc, SCBPTR); /* Ensure that the hscbs down on the card match the new information */ for (i = 0; i < ahc->scb_data->maxhscbs; i++) { @@ -1943,14 +1956,16 @@ pending_hscb = pending_scb->hscb; control = ahc_inb(ahc, SCB_CONTROL); - control &= ~ULTRAENB; - if ((pending_hscb->control & ULTRAENB) != 0) - control |= ULTRAENB; + control &= ~(ULTRAENB|MK_MESSAGE); + control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); ahc_outb(ahc, SCB_CONTROL, control); ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); } ahc_outb(ahc, SCBPTR, saved_scbptr); + + if (paused == 0) + ahc_unpause(ahc); } /**************************** Pathing Information *****************************/ @@ -1985,6 +2000,24 @@ role); } +struct ahc_phase_table_entry* +ahc_lookup_phase_entry(int phase) +{ + struct ahc_phase_table_entry *entry; + struct ahc_phase_table_entry *last_entry; + + /* + * num_phases doesn't include the default entry which + * will be returned if the phase doesn't match. + */ + last_entry = &ahc_phase_table[num_phases]; + for (entry = ahc_phase_table; entry < last_entry; entry++) { + if (phase == entry->phase) + break; + } + return (entry); +} + void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role) @@ -2017,6 +2050,17 @@ /************************ Message Phase Processing ****************************/ +static void +ahc_assert_atn(struct ahc_softc *ahc) +{ + u_int scsisigo; + + scsisigo = ATNO; + if ((ahc->features & AHC_DT) == 0) + scsisigo |= ahc_inb(ahc, SCSISIGI); + ahc_outb(ahc, SCSISIGO, scsisigo); +} + /* * When an initiator transaction with the MK_MESSAGE flag either reconnects * or enters the initial message out phase, we are interrupted. Fill our @@ -2083,8 +2127,7 @@ * away. */ ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 - || (scb->flags & SCB_NEGOTIATE) != 0) { + } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " @@ -2101,6 +2144,7 @@ * asked to send this message again. */ ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + scb->hscb->control &= ~MK_MESSAGE; ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; } @@ -2118,7 +2162,7 @@ * we want to renegotiate due to a check condition. */ struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *rate; int dowide; int dosync; @@ -2130,9 +2174,19 @@ tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); - dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + dowide = tinfo->curr.width != tinfo->goal.width; + dosync = tinfo->curr.period != period; + doppr = tinfo->curr.ppr_options != ppr_options; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; @@ -2145,7 +2199,7 @@ "but no negotiation needed\n"); } - use_ppr = (tinfo->current.transport_version >= 3) || doppr; + use_ppr = (tinfo->curr.transport_version >= 3) || doppr; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) use_ppr = 0; @@ -2160,16 +2214,10 @@ */ if (use_ppr || (dosync && !dowide)) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - if (use_ppr == 0) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); offset = tinfo->goal.offset; ahc_validate_offset(ahc, tinfo, rate, &offset, use_ppr ? tinfo->goal.width - : tinfo->current.width, + : tinfo->curr.width, devinfo->role); if (use_ppr) { ahc_construct_ppr(ahc, devinfo, period, offset, @@ -2258,7 +2306,7 @@ ahc->msgout_len = 0; ahc->msgin_index = 0; ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) { + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { /* * The target didn't care to respond to our * message request, so clear ATN. @@ -2327,7 +2375,7 @@ * 0, and try again. */ ahc->msgout_index = 0; - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); @@ -2382,8 +2430,7 @@ * message out phase. */ if (ahc->msgout_len != 0) - ahc_outb(ahc, SCSISIGO, - ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } else ahc->msgin_index++; @@ -2548,7 +2595,7 @@ found = TRUE; } index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { /* Skip tag type and tag id or residue param*/ @@ -2575,7 +2622,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int reject; int done; int response; @@ -2674,7 +2721,8 @@ /* * Send our own SDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahc_name(ahc), devinfo->channel, @@ -2744,7 +2792,8 @@ /* * Send our own WDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahc_name(ahc), devinfo->channel, @@ -2879,7 +2928,7 @@ "offset %x, options %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_width, + saved_width, ahc->msgin_buf[3], saved_offset, saved_ppr_options, bus_width, period, offset, ppr_options); } @@ -2906,7 +2955,7 @@ CAM_BDR_SENT, "Bus Device Reset Received", /*verbose_level*/0); - restart_sequencer(ahc); + ahc_restart(ahc); done = MSGLOOP_TERMINATED; break; case MSG_ABORT_TAG: @@ -2927,7 +2976,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[devinfo->lun]; if (lstate != NULL) { @@ -2979,7 +3028,7 @@ */ struct scb *scb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int scb_index; u_int last_msg; int response = 0; @@ -3004,7 +3053,7 @@ devinfo->target, devinfo->lun); } tinfo->goal.ppr_options = 0; - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; ahc->msgout_index = 0; ahc->msgout_len = 0; @@ -3046,24 +3095,39 @@ "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { - - printf("(%s:%c:%d:%d): refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, FALSE); + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; + + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } /* * Resend the identify for this CCB as the target * may believe that the selection is invalid otherwise. */ ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_Q_TAG); + /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); /* * This transaction is now at the head of @@ -3225,7 +3289,7 @@ cam_status status, char *message, int verbose_level) { #ifdef AHC_TARGET_MODE - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; #endif int found; @@ -3242,7 +3306,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -3265,7 +3329,7 @@ AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -3274,9 +3338,11 @@ } #ifdef AHC_TARGET_MODE -void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +static void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) { + /* * To facilitate adding multiple messages together, * each routine should increment the index and len @@ -3285,7 +3351,7 @@ ahc->msgout_index = 0; ahc->msgout_len = 0; - if ((ahc->targ_msg_req & devinfo->target_mask) != 0) + if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) ahc_build_transfer_msg(ahc, devinfo); else panic("ahc_intr: AWAITING target message with no message"); @@ -3319,6 +3385,7 @@ LIST_INIT(&ahc->pending_scbs); /* We don't know our unit number until the OSM sets it */ ahc->name = name; + ahc->unit = -1; for (i = 0; i < 16; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { @@ -3337,7 +3404,7 @@ ahc->bugs = config->bugs; ahc->flags = config->flags; ahc->channel = config->channel; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; + ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS); ahc->description = config->description; /* The IRQMS bit is only valid on VL and EISA chips */ if ((ahc->chip & AHC_PCI) != 0) @@ -3360,29 +3427,37 @@ { struct ahc_softc *list_ahc; -#ifdef AHC_SUPPORT_PCI +#if AHC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some - * settings from function 0. We assume that function 0 - * will always be found prior to function 1. + * settings from function 0. */ if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI - && ahc_get_pci_function(ahc->dev_softc) == 1) { + && (ahc->features & AHC_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { ahc_dev_softc_t list_pci; ahc_dev_softc_t pci; list_pci = list_ahc->dev_softc; pci = ahc->dev_softc; - if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci) - && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_function(list_pci) == 0) { - ahc->flags &= ~AHC_BIOS_ENABLED; - ahc->flags |= - list_ahc->flags & AHC_BIOS_ENABLED; - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - ahc->flags |= - list_ahc->flags & AHC_CHANNEL_B_PRIMARY; + if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + struct ahc_softc *master; + struct ahc_softc *slave; + + if (ahc_get_pci_function(list_pci) == 0) { + master = list_ahc; + slave = ahc; + } else { + master = ahc; + slave = list_ahc; + } + slave->flags &= ~AHC_BIOS_ENABLED; + slave->flags |= + master->flags & AHC_BIOS_ENABLED; + slave->flags &= ~AHC_PRIMARY_CHANNEL; + slave->flags |= + master->flags & AHC_PRIMARY_CHANNEL; break; } } @@ -3455,7 +3530,7 @@ #endif ahc_platform_free(ahc); for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; tstate = ahc->enabled_targets[i]; if (tstate != NULL) { @@ -3463,7 +3538,7 @@ int j; for (j = 0; j < AHC_NUM_LUNS; j++) { - struct tmode_lstate *lstate; + struct ahc_tmode_lstate *lstate; lstate = tstate->enabled_luns[j]; if (lstate != NULL) { @@ -3523,7 +3598,7 @@ * It contains settings that affect termination and we don't want * to disturb the integrity of the bus. */ - pause_sequencer(ahc); + ahc_pause(ahc); sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -3961,17 +4036,26 @@ len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " "B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, - ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A'); + (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); else { + const char *speed; const char *type; + speed = ""; + if ((ahc->features & AHC_ULTRA) != 0) { + speed = "Ultra "; + } else if ((ahc->features & AHC_DT) != 0) { + speed = "Ultra160 "; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + speed = "Ultra2 "; + } if ((ahc->features & AHC_WIDE) != 0) { type = "Wide"; } else { type = "Single"; } - len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ", - type, ahc->channel, ahc->our_id); + len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", + speed, type, ahc->channel, ahc->our_id); } buf += len; @@ -4124,16 +4208,16 @@ * data for any target mode initiator. */ if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } } @@ -4231,7 +4315,7 @@ for (i = 0; i <= max_targ; i++) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -4324,12 +4408,10 @@ tinfo->user.transport_version = 2; tinfo->goal.protocol_version = 2; tinfo->goal.transport_version = 2; - tinfo->current.protocol_version = 2; - tinfo->current.transport_version = 2; + tinfo->curr.protocol_version = 2; + tinfo->curr.transport_version = 2; } tstate->ultraenb = ultraenb; - tstate->discenable = discenable; - tstate->tagenable = 0; /* Wait until the XPT says its okay */ } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; @@ -4395,10 +4477,6 @@ ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0); - /* Don't have any special messages to send to targets */ - ahc_outb(ahc, TARGET_MSG_REQUEST, 0); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); - /* * Use the built in queue management registers * if they are available. @@ -4450,16 +4528,33 @@ * never settle, so don't complain if we * fail here. */ - pause_sequencer(ahc); + ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) ahc_delay(100); - unpause_sequencer(ahc); + ahc_unpause(ahc); } return (0); } +void +ahc_intr_enable(struct ahc_softc *ahc, int enable) +{ + u_int hcntrl; + + hcntrl = ahc_inb(ahc, HCNTRL); + hcntrl &= ~INTEN; + ahc->pause &= ~INTEN; + ahc->unpause &= ~INTEN; + if (enable) { + hcntrl |= INTEN; + ahc->pause |= INTEN; + ahc->unpause |= INTEN; + } + ahc_outb(ahc, HCNTRL, hcntrl); +} + /* * Ensure that the card is paused in a location * outside of all critical sections and that all @@ -4478,7 +4573,7 @@ intstat = 0; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) break; @@ -5409,7 +5504,7 @@ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, channel, ROLE_UNKNOWN); - pause_sequencer(ahc); + ahc_pause(ahc); /* Make sure the sequencer is in a safe location. */ ahc_clear_critical_section(ahc); @@ -5478,14 +5573,14 @@ * drivers affected by this action. */ for (target = 0; target <= max_scsiid; target++) { - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; tstate = ahc->enabled_targets[target]; if (tstate == NULL) continue; for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -5499,7 +5594,7 @@ #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); /* * Revert to async/narrow transfers until we renegotiate. @@ -5524,9 +5619,9 @@ } if (restart_needed) - restart_sequencer(ahc); + ahc_restart(ahc); else - unpause_sequencer(ahc); + ahc_unpause(ahc); return found; } @@ -5535,7 +5630,7 @@ /* * Calculate the residual for a just completed SCB. */ -static void +void ahc_calc_residual(struct scb *scb) { struct hardware_scb *hscb; @@ -5623,7 +5718,7 @@ * Add a target mode event to this lun's queue */ static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate, +ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg) { struct ahc_tmode_event *event; @@ -5674,7 +5769,7 @@ * for immediate notify resources. */ void -ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate) +ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) { struct ccb_hdr *ccbh; struct ccb_immed_notify *inot; @@ -5825,7 +5920,7 @@ memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - restart_sequencer(ahc); + ahc_restart(ahc); if (bootverbose) printf(" %d instructions downloaded\n", downloaded); @@ -6000,6 +6095,7 @@ int target; int maxtarget; int i; + uint8_t last_phase; uint8_t qinpos; uint8_t qintail; uint8_t qoutpos; @@ -6008,13 +6104,25 @@ saved_scbptr = ahc_inb(ahc, SCBPTR); - printf("%s: Dumping Card State at SEQADDR 0x%x\n", - ahc_name(ahc), + last_phase = ahc_inb(ahc, LASTPHASE); + printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", + ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - - printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n", - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL), - ahc_inb(ahc, SSTAT0)); + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); + printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", + ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); + printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", + last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); + printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", + ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); + if ((ahc->features & AHC_DT) != 0) + printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); printf("SCB count = %d\n", ahc->scb_data->numscbs); printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); @@ -6112,7 +6220,8 @@ #ifdef AHC_TARGET_MODE cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure) { @@ -6153,8 +6262,8 @@ void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; u_int target; @@ -6227,7 +6336,7 @@ ahc->flags |= AHC_TARGETROLE; if ((ahc->features & AHC_MULTIROLE) == 0) ahc->flags &= ~AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); ahc_unlock(ahc, &s); } @@ -6296,7 +6405,7 @@ SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); ahc_lock(ahc, &s); - pause_sequencer(ahc); + ahc_pause(ahc); if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = lstate; ahc->enabled_luns++; @@ -6360,7 +6469,7 @@ scsiseq |= ENSELI; ahc_outb(ahc, SCSISEQ, scsiseq); } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); @@ -6410,7 +6519,7 @@ xpt_free_path(lstate->path); free(lstate, M_DEVBUF); - pause_sequencer(ahc); + ahc_pause(ahc); /* Can we clean up the target too? */ if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = NULL; @@ -6463,11 +6572,11 @@ printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); } } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); } } @@ -6549,11 +6658,11 @@ ahc_outb(ahc, HS_MAILBOX, hs_mailbox); } else { if (!paused) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext & HOST_TQINPOS); if (!paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } } @@ -6562,8 +6671,8 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_accept_tio *atio; uint8_t *byte; int initiator; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.h Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $ + * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ */ @@ -209,9 +209,15 @@ AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, - AHC_AIC7855_FE = AHC_AIC7850_FE, - AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, + /* + * The real 7850 does not support Ultra modes, but there are + * several cards that use the generic 7850 PCI ID even though + * they are using an Ultra capable chip (7859/7860). We start + * out with the AHC_ULTRA feature set and then check the DEVSTATUS + * register to determine if the capability is really present. + */ + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, + AHC_AIC7860_FE = AHC_AIC7850_FE, AHC_AIC7870_FE = AHC_TARGETMODE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* @@ -286,56 +292,56 @@ * chip/controller's configuration. */ typedef enum { - AHC_FNONE = 0x000, - AHC_PAGESCBS = 0x001,/* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x002,/* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. + AHC_FNONE = 0x000, + AHC_PRIMARY_CHANNEL = 0x003,/* + * The channel that should + * be probed first. */ - AHC_USEDEFAULTS = 0x004,/* + AHC_USEDEFAULTS = 0x004,/* * For cards without an seeprom * or a BIOS to initialize the chip's * SRAM, we use the default target * settings. */ - AHC_SEQUENCER_DEBUG = 0x008, - AHC_SHARED_SRAM = 0x010, - AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ - AHC_RESET_BUS_A = 0x040, - AHC_RESET_BUS_B = 0x080, - AHC_EXTENDED_TRANS_A = 0x100, - AHC_EXTENDED_TRANS_B = 0x200, - AHC_TERM_ENB_A = 0x400, - AHC_TERM_ENB_B = 0x800, - AHC_INITIATORROLE = 0x1000,/* + AHC_SEQUENCER_DEBUG = 0x008, + AHC_SHARED_SRAM = 0x010, + AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ + AHC_RESET_BUS_A = 0x040, + AHC_RESET_BUS_B = 0x080, + AHC_EXTENDED_TRANS_A = 0x100, + AHC_EXTENDED_TRANS_B = 0x200, + AHC_TERM_ENB_A = 0x400, + AHC_TERM_ENB_B = 0x800, + AHC_INITIATORROLE = 0x1000,/* * Allow initiator operations on * this controller. */ - AHC_TARGETROLE = 0x2000,/* + AHC_TARGETROLE = 0x2000,/* * Allow target operations on this * controller. */ - AHC_NEWEEPROM_FMT = 0x4000, - AHC_RESOURCE_SHORTAGE = 0x8000, - AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ - AHC_INT50_SPEEDFLEX = 0x20000,/* + AHC_NEWEEPROM_FMT = 0x4000, + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ + AHC_INT50_SPEEDFLEX = 0x20000,/* * Internal 50pin connector * sits behind an aic3860 */ - AHC_SCB_BTT = 0x40000,/* + AHC_SCB_BTT = 0x40000,/* * The busy targets table is * stored in SCB space rather * than SRAM. */ - AHC_BIOS_ENABLED = 0x80000, - AHC_ALL_INTERRUPTS = 0x100000, - AHC_ULTRA_DISABLED = 0x200000/* + AHC_BIOS_ENABLED = 0x80000, + AHC_ALL_INTERRUPTS = 0x100000, + AHC_ULTRA_DISABLED = 0x200000, /* * The precision resistor for * ultra transmission speeds is * missing, so we must limit * ourselves to fast SCSI. */ + AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ + AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */ } ahc_flag; /* @@ -515,8 +521,9 @@ SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0040, - SCB_NEGOTIATE = 0x0080, + SCB_RECOVERY_SCB = 0x0020, + SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ + SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ SCB_ABORT = 0x1000, SCB_UNTAGGEDQ = 0x2000, SCB_ACTIVE = 0x4000, @@ -625,7 +632,7 @@ * data structures. */ #ifdef AHC_TARGET_MODE -struct tmode_lstate { +struct ahc_tmode_lstate { struct cam_path *path; struct ccb_hdr_slist accept_tios; struct ccb_hdr_slist immed_notifies; @@ -634,7 +641,7 @@ uint8_t event_w_idx; }; #else -struct tmode_lstate; +struct ahc_tmode_lstate; #endif /******************** Transfer Negotiation Datastructures *********************/ @@ -659,7 +666,7 @@ * Per-initiator current, goal and user transfer negotiation information. */ struct ahc_initiator_tinfo { uint8_t scsirate; /* Computed value for SCSIRATE reg */ - struct ahc_transinfo current; + struct ahc_transinfo curr; struct ahc_transinfo goal; struct ahc_transinfo user; }; @@ -671,16 +678,17 @@ * that we are the target and the targets are the initiators since the * negotiation is the same regardless of role. */ -struct tmode_tstate { - struct tmode_lstate* enabled_luns[AHC_NUM_LUNS]; +struct ahc_tmode_tstate { + struct ahc_tmode_lstate* enabled_luns[AHC_NUM_LUNS]; struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; /* * Per initiator state bitmasks. */ - uint16_t ultraenb; /* Using ultra sync rate */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ + uint16_t auto_negotiate;/* Auto Negotiation Required */ + uint16_t ultraenb; /* Using ultra sync rate */ + uint16_t discenable; /* Disconnection allowed */ + uint16_t tagenable; /* Tagged Queuing allowed */ }; /* @@ -711,32 +719,14 @@ /***************************** Lookup Tables **********************************/ /* - * Textual descriptions of the different chips indexed by chip type. - */ -extern char *ahc_chip_names[]; -extern const u_int num_chip_names; - -/* - * Hardware error codes. - */ -struct hard_error_entry { - uint8_t errno; - char *errmesg; -}; -extern struct hard_error_entry hard_error[]; -extern const u_int num_errors; - -/* * Phase -> name and message out response * to parity errors in each phase table. */ -struct phase_table_entry { +struct ahc_phase_table_entry { uint8_t phase; uint8_t mesg_out; /* Message response to parity errors */ char *phasemsg; }; -extern struct phase_table_entry phase_table[]; -extern const u_int num_phases; /************************** Serial EEPROM Format ******************************/ @@ -765,12 +755,19 @@ #define CFSUPREM 0x0001 /* support all removeable drives */ #define CFSUPREMB 0x0002 /* support removeable boot drives */ #define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ +#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ #define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ #define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ +#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ #define CFEXTEND 0x0080 /* extended translation enabled */ #define CFSCAMEN 0x0100 /* SCAM enable */ +#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ +#define CFMSG_VERBOSE 0x0000 +#define CFMSG_SILENT 0x0200 +#define CFMSG_DIAG 0x0400 +#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ /* UNUSED 0xff00 */ /* @@ -785,10 +782,11 @@ #define CFWSTERM 0x0008 /* SCSI high byte termination */ #define CFSPARITY 0x0010 /* SCSI parity */ #define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 #define CFRESETB 0x0040 /* reset SCSI bus at boot */ #define CFCLUSTERENB 0x0080 /* Cluster Enable */ -#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */ +#define CFBOOTCHAN 0x0300 /* probe this channel first */ +#define CFBOOTCHANSHIFT 8 #define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ #define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ #define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ @@ -812,6 +810,7 @@ uint16_t res_1[10]; /* words 20-29 */ uint16_t signature; /* Signature == 0x250 */ #define CFSIGNATURE 0x250 +#define CFSIGNATURE2 0x300 uint16_t checksum; /* word 31 */ }; @@ -857,6 +856,8 @@ uint8_t *btt; }; +typedef void (*ahc_bus_intr_t)(struct ahc_softc *); + struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; @@ -900,24 +901,29 @@ ahc_dev_softc_t dev_softc; /* + * Bus specific device information. + */ + ahc_bus_intr_t bus_intr; + + /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. * As an initiator, we keep one target entry for our initiator * ID to store our sync/wide transfer settings. */ - struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS]; + struct ahc_tmode_tstate *enabled_targets[AHC_NUM_TARGETS]; /* * The black hole device responsible for handling requests for * disabled luns on enabled targets. */ - struct tmode_lstate* black_hole; + struct ahc_tmode_lstate *black_hole; /* * Device instance currently on the bus awaiting a continue TIO * for a command that was not given the disconnect priveledge. */ - struct tmode_lstate* pending_device; + struct ahc_tmode_lstate *pending_device; /* * Card characteristics @@ -952,9 +958,6 @@ uint8_t our_id; uint8_t our_id_b; - /* Targets that need negotiation messages */ - uint16_t targ_msg_req; - /* * PCI error detection. */ @@ -1102,6 +1105,7 @@ struct ahc_probe_config*); void ahc_controller_info(struct ahc_softc *ahc, char *buf); int ahc_init(struct ahc_softc *ahc); +void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); @@ -1143,8 +1147,11 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); -void restart_sequencer(struct ahc_softc *ahc); +void ahc_restart(struct ahc_softc *ahc); +void ahc_calc_residual(struct scb *scb); /*************************** Utility Functions ********************************/ +struct ahc_phase_table_entry* + ahc_lookup_phase_entry(int phase); void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, @@ -1163,10 +1170,11 @@ struct ahc_initiator_tinfo *tinfo, u_int *bus_width, role_t role); -void ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *dinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused); +int ahc_update_neg_request(struct ahc_softc*, + struct ahc_devinfo*, + struct ahc_tmode_tstate*, + struct ahc_initiator_tinfo*, + int /*force*/); void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1176,22 +1184,27 @@ u_int period, u_int offset, u_int ppr_options, u_int type, int paused); +typedef enum { + AHC_QUEUE_NONE, + AHC_QUEUE_BASIC, + AHC_QUEUE_TAGGED +} ahc_queue_alg; + void ahc_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE void ahc_send_lstate_events(struct ahc_softc *, - struct tmode_lstate *); + struct ahc_tmode_lstate *); void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb); cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, - struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure); -void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); #ifndef AHC_TMODE_ENABLE #define AHC_TMODE_ENABLE 0 #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.reg Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ */ @@ -877,7 +877,8 @@ address 0x094 access_mode RO bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 + bit DFCACHETH 0x40 + bit FIFOQWDEMP 0x20 bit MREQPEND 0x10 bit HDONE 0x08 bit DFTHRESH 0x04 @@ -969,6 +970,7 @@ bit MSG_OUT_PHASE 0x04 bit DATA_IN_PHASE 0x02 bit DATA_OUT_PHASE 0x01 + mask DATA_PHASE_MASK 0x03 } /* @@ -1415,15 +1417,6 @@ */ LAST_MSG { size 1 - } - - /* - * Interrupt kernel for a message to this target on - * the next transaction. This is usually used for - * negotiation requests. - */ - TARGET_MSG_REQUEST { - size 2 } /* diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.seq Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ @@ -153,7 +153,9 @@ * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; + if ((ahc->features & AHC_DT) == 0) { + or SIMODE1, ENBUSFREE; + } /* * Guard against a bus free after (re)selection @@ -479,6 +481,9 @@ */ mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + test SCB_CONTROL, MK_MESSAGE jz target_ITloop; + mvi P_MESGIN|BSYO call change_phase; + jmp host_target_message_loop; target_ITloop: /* * Start honoring ATN signals now that @@ -494,12 +499,12 @@ * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } mov RETURN_1, ALLZEROS; call complete_target_cmd; cmp RETURN_1, CONT_MSG_LOOP jne .; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb; jmp target_synccmd; @@ -703,6 +708,11 @@ test CCSGCTL, CCSGEN jnz .; ret; idle_loop: + /* + * Do we need any more segments for this transfer? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + /* Did we just finish fetching segs? */ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; @@ -710,11 +720,6 @@ test CCSGCTL, CCSGEN jnz return; /* - * Do we need any more segments? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - - /* * Do we have any prefetch left??? */ cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; @@ -758,8 +763,8 @@ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; - /* Load the segment by writing DFCNTRL again */ - mov DFCNTRL, DMAPARAMS; + /* Load the segment */ + or DFCNTRL, PRELOADEN; } ret; } @@ -882,7 +887,11 @@ and DMAPARAMS, DIRECTION; mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - test SSTAT1,PHASEMIS jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz .; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz .; + } and SXFRCTL1, ~BITBUCKET; mvi DATA_OVERRUN call set_seqint; jmp ITloop; @@ -903,54 +912,48 @@ * completes or the target changes phase. */ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } + } else { + test DFCNTRL, SCSIEN jnz ultra2_dma_loop; } ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; - if ((ahc->features & AHC_DT) == 0) { - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - } -ultra2_dmafifoflush: + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { /* - * On Rev A of the aic7890, the autoflush - * features doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. + * On chips with broken auto-flush, start + * the flushing process now. We'll poke + * the chip from time to time to keep the + * flush process going as we complete the + * data phase. */ or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; -ultra2_dmafifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; -ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, HDMAEN jnz .; - /* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * * If, by chance, we stopped before being able * to fetch additional segments for this transfer, * yet the last S/G was completely exhausted, @@ -961,14 +964,14 @@ * If we happened to stop on the last segment, then * our residual information is still correct from * the idle loop and there is no need to perform - * any fixups. Just jump to data_phase_finish. + * any fixups. */ ultra2_ensure_sg: test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; /* Record if we've consumed all S/G entries */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; + test SSTAT2, SHVALID jnz residuals_correct; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; + jmp residuals_correct; ultra2_shvalid: test SSTAT2, SHVALID jnz sgptr_fixup; @@ -998,6 +1001,62 @@ test SG_CACHE_SHADOW, ODD_SEG jz . + 2; or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ +residuals_correct: + /* + * Go ahead and shut down the DMA engine now. + * In the future, we'll want to handle end of + * transfer messages prior to doing this, but this + * requires similar restructuring for pre-ULTRA2 + * controllers. + */ + test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; +ultra2_fifoflush: + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * feature doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } else { + /* + * We enable the auto-ack feature on DT capable + * controllers. This means that the controller may + * have already transferred some overrun bytes into + * the data FIFO and acked them on the bus. The only + * way to detect this situation is to wait for + * LAST_SEG_DONE to come true on a completed transfer + * and then test to see if the data FIFO is non-empty. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + /* Overrun */ + jmp data_phase_loop; + test DFSTATUS, FIFOEMP jz .; + } +ultra2_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_fifoempty; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, SCSIEN|HDMAEN jnz .; } else { /* If we are the last SG block, tell the hardware. */ if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 @@ -1156,7 +1215,11 @@ } if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz data_phase_loop; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; + } } data_phase_done: @@ -1296,13 +1359,17 @@ or DFCNTRL, FIFOFLUSH; } p_command_loop: - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz p_command_loop; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz p_command_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + } else { + test DFCNTRL, SCSIEN jnz p_command_loop; + } and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1346,23 +1413,16 @@ * reason. */ p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ + /* Turn on ATN for the retry */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; - mov FUNCTION1, SCB_SCSIID; - mov A, FUNCTION1; - mov SINDEX, TARGET_MSG_REQUEST[0]; - if ((ahc->features & AHC_TWIN) != 0) { - /* Second Channel uses high byte bits */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - mov SINDEX, TARGET_MSG_REQUEST[1]; - } else if ((ahc->features & AHC_WIDE) != 0) { - test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ - mov SINDEX, TARGET_MSG_REQUEST[1]; - } - test SINDEX, A jnz host_message_loop; p_mesgout_identify: or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; test SCB_CONTROL, DISCENB jnz . + 2; @@ -1555,10 +1615,17 @@ * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. + * Ack the message as soon as possible. For chips without S/G pipelining, + * we can only ack the message after SHADDR has been saved. On these + * chips, SHADDR increments with every bus transaction, even PIO. */ mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - + if ((ahc->features & AHC_ULTRA2) != 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + } else { + test SEQ_FLAGS, DPHASE jz mesgin_done; + } /* * The SCB_SGPTR becomes the next one we'll download, * and the SCB_DATAPTR becomes the current SHADDR. @@ -1567,13 +1634,17 @@ */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SCB_DATAPTR, SHADDR, 4; + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + } bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { mvi DINDEX, SCB_DATAPTR; mvi SHADDR call bcopy_4; + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ mvi SCB_RESIDUAL_DATACNT call bcopy_8; } - jmp mesgin_done; + jmp ITloop; /* * Restore pointers message? Data pointers are recopied from the @@ -1751,7 +1822,11 @@ jmp mesgin_done; mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } mov MSG_OUT,SINDEX ret; /* @@ -1924,7 +1999,9 @@ test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr; phase_lock_latch_phase: - and SCSISIGO, PHASE_MASK, SCSISIGI; + if ((ahc->features & AHC_DT) == 0) { + and SCSISIGO, PHASE_MASK, SCSISIGI; + } and LASTPHASE, PHASE_MASK, SCSISIGI ret; if ((ahc->features & AHC_CMD_CHAN) == 0) { @@ -2068,9 +2145,9 @@ * latch is full. */ clr A; - /* Wait for some data to arrive. */ + /* Wait for at least 8 bytes of data to arrive. */ dma_scb_hang_fifo: - test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; + test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; dma_scb_hang_wait: test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; @@ -2078,8 +2155,7 @@ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; /* * The PCI module no longer intends to perform - * a PCI transaction and HDONE has not come true. - * We are hung. Drain the fifo. + * a PCI transaction. Drain the fifo. */ dma_scb_hang_empty_fifo: /* @@ -2101,6 +2177,7 @@ */ not SINDEX; add A, 5, SINDEX; + cmp A, 4 je dma_finish_nowait; jmp dma_scb_hang_fifo; dma_scb_hang_dma_done: and DFCNTRL, ~HDMAEN; @@ -2146,6 +2223,7 @@ */ dma_finish: test DFSTATUS,HDONE jz dma_finish; +dma_finish_nowait: /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h linux/drivers/scsi/aic7xxx/aic7xxx_inline.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $ + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ */ @@ -37,10 +37,10 @@ #define _AIC7XXX_INLINE_H_ /************************* Sequencer Execution Control ************************/ -static __inline int sequencer_paused(struct ahc_softc *ahc); +static __inline int ahc_is_paused(struct ahc_softc *ahc); static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); -static __inline void pause_sequencer(struct ahc_softc *ahc); -static __inline void unpause_sequencer(struct ahc_softc *ahc); +static __inline void ahc_pause(struct ahc_softc *ahc); +static __inline void ahc_unpause(struct ahc_softc *ahc); /* * Work around any chip bugs related to halting sequencer execution. @@ -62,7 +62,7 @@ * Returns non-zero status if the sequencer is stopped. */ static __inline int -sequencer_paused(struct ahc_softc *ahc) +ahc_is_paused(struct ahc_softc *ahc) { return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); } @@ -75,7 +75,7 @@ * for critical sections. */ static __inline void -pause_sequencer(struct ahc_softc *ahc) +ahc_pause(struct ahc_softc *ahc) { ahc_outb(ahc, HCNTRL, ahc->pause); @@ -83,7 +83,7 @@ * Since the sequencer can disable pausing in a critical section, we * must loop until it actually stops. */ - while (sequencer_paused(ahc) == 0) + while (ahc_is_paused(ahc) == 0) ; ahc_pause_bug_fix(ahc); @@ -100,7 +100,7 @@ * condition. */ static __inline void -unpause_sequencer(struct ahc_softc *ahc) +ahc_unpause(struct ahc_softc *ahc) { if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) ahc_outb(ahc, HCNTRL, ahc->unpause); @@ -188,12 +188,12 @@ /*********************** Miscelaneous Support Functions ***********************/ -static __inline int ahc_check_residual(struct scb *scb); +static __inline void ahc_update_residual(struct scb *scb); static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, u_int remote_id, - struct tmode_tstate **tstate); + struct ahc_tmode_tstate **tstate); static __inline struct scb* ahc_get_scb(struct ahc_softc *ahc); static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); @@ -211,15 +211,16 @@ * Determine whether the sequencer reported a residual * for this SCB/transaction. */ -static __inline int -ahc_check_residual(struct scb *scb) +static __inline void +ahc_update_residual(struct scb *scb) { - struct status_pkt *sp; + uint32_t sgptr; - sp = &scb->hscb->shared_data.status; - if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) - return (1); - return (0); + sgptr = ahc_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_RESID_VALID) != 0) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); } /* @@ -228,7 +229,7 @@ */ static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, - u_int remote_id, struct tmode_tstate **tstate) + u_int remote_id, struct ahc_tmode_tstate **tstate) { /* * Transfer data structures are stored from the perspective @@ -345,10 +346,10 @@ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { if ((ahc->features & AHC_AUTOPAUSE) == 0) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); if ((ahc->features & AHC_AUTOPAUSE) == 0) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } @@ -412,19 +413,28 @@ * completion queues. This avoids a costly PCI bus read in * most cases. */ - intstat = 0; - if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) + if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 + && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) intstat = CMDCMPLT; - - if ((intstat & INT_PEND) == 0 - || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) { - + else { intstat = ahc_inb(ahc, INTSTAT); + /* + * We can't generate queuestat once above + * or we are exposed to a race when our + * interrupt is shared with another device. + * if instat showed a command complete interrupt, + * but our first generation of queue stat + * "just missed" the delivery of this transaction, + * we would clear the command complete interrupt + * below without ever servicing the completed + * command. + */ + queuestat = ahc_check_cmdcmpltqueues(ahc); #if AHC_PCI_CONFIG > 0 if (ahc->unsolicited_ints > 500 && (ahc->chip & AHC_PCI) != 0 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) - ahc_pci_intr(ahc); + ahc->bus_intr(ahc); #endif } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Sun May 20 12:11:39 2001 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#66 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -112,6 +112,7 @@ * 8: SMP friendliness has been improved * */ + #include /* @@ -158,8 +159,8 @@ * The scsi error recovery code performs its own bus settle * delay handling for error recovery actions. */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY +#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS #else #define AIC7XXX_RESET_DELAY 5000 #endif @@ -479,45 +480,48 @@ #endif -static void ahc_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, struct scb *); -static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static void ahc_sem_timeout(u_long arg); -static void ahc_release_sim_queue(u_long arg); -static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); -static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc); -static void aic7xxx_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -static void aic7xxx_device_queue_depth(struct ahc_softc *ahc, - Scsi_Device *device); -static struct ahc_linux_target* ahc_alloc_target(struct ahc_softc *, - u_int, u_int); -static void ahc_free_target(struct ahc_softc *ahc, - struct ahc_linux_target *targ); -static struct ahc_linux_device* ahc_alloc_device(struct ahc_softc *, - struct ahc_linux_target *, - u_int); -static void ahc_free_device(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_run_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_setup_tag_info(char *p, char *end); -static int ahc_next_unit(void); +static void ahc_linux_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, + struct scb *); +static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static void ahc_linux_sem_timeout(u_long arg); +static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc); +static void ahc_linux_release_sim_queue(u_long arg); +static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); +static void ahc_linux_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, + u_int, u_int); +static void ahc_linux_free_target(struct ahc_softc*, + struct ahc_linux_target*); +static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct ahc_linux_target*, + u_int); +static void ahc_linux_free_device(struct ahc_softc*, + 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 int ahc_linux_next_unit(void); +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); static __inline struct ahc_linux_device* - ahc_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int /*alloc*/); -static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); -static __inline void ahc_run_complete_queue(struct ahc_softc *ahc, - struct ahc_cmd *acmd); -static __inline void ahc_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb); + ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int alloc); +static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*); +static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline struct ahc_linux_device* -ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target, +ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) { struct ahc_linux_target *targ; @@ -530,7 +534,7 @@ targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { if (alloc != 0) { - targ = ahc_alloc_target(ahc, channel, target); + targ = ahc_linux_alloc_target(ahc, channel, target); if (targ == NULL) return (NULL); } else @@ -538,17 +542,17 @@ } dev = targ->devices[lun]; if (dev == NULL && alloc != 0) - dev = ahc_alloc_device(ahc, targ, lun); + dev = ahc_linux_alloc_device(ahc, targ, lun); return (dev); } static __inline void -ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Typically, the complete queue has very few entries * queued to it before the queue is emptied by - * ahc_run_complete_queue, so sorting the entries + * ahc_linux_run_complete_queue, so sorting the entries * by generation number should be inexpensive. * We perform the sort so that commands that complete * with an error are retuned in the order origionally @@ -584,7 +588,7 @@ } static __inline void -ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) { u_long done_flags; @@ -601,7 +605,8 @@ } static __inline void -ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev) { if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 && dev->active == 0) { @@ -613,11 +618,11 @@ || dev->openings == 0 || dev->qfrozen != 0) return; - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); } static __inline void -ahc_run_device_queues(struct ahc_softc *ahc) +ahc_linux_run_device_queues(struct ahc_softc *ahc) { struct ahc_linux_device *dev; @@ -626,25 +631,25 @@ && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) { LIST_REMOVE(dev, links); dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_check_device_queue(ahc, dev); + ahc_linux_check_device_queue(ahc, dev); } } static __inline void -ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Determine whether we care to filter * information out of this command. If so, - * pass it on to ahc_filter_command() for more + * pass it on to ahc_linux_filter_command() for more * heavy weight processing. */ if (cmd->cmnd[0] == INQUIRY) - ahc_filter_command(ahc, cmd); + ahc_linux_filter_command(ahc, cmd); } static __inline void -ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { Scsi_Cmnd *cmd; @@ -662,6 +667,24 @@ scsi_to_pci_dma_dir(cmd->sc_data_direction)); } +/************************ Shutdown/halt/reboot hook ***************************/ +#include +#include + +static struct notifier_block ahc_linux_notifier = { + ahc_linux_halt, NULL, 0 +}; + +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) +{ + struct ahc_softc *ahc; + + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + ahc_shutdown(ahc); + } + return (NOTIFY_OK); +} + /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->target << TID_SHIFT) & TID) \ @@ -820,6 +843,9 @@ /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { case AHC_PCI: + { + char primary_channel; + value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); if (value != 0) @@ -828,19 +854,18 @@ - ahc_get_pci_slot(rahc->dev_softc); if (value != 0) break; - value = ahc_get_pci_function(lahc->dev_softc) - - ahc_get_pci_function(rahc->dev_softc); /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. - * Function 0 is the only one that will have - * CHANNEL_B_PRIMARY set. + * Give whichever channel is the primary channel + * the lowest priority. */ - if (value < 0 - && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) - /* Swap the two */ - value = -value; + primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; + value = 1; + if (lahc->channel == primary_channel) + value = -1; break; + } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = lahc->platform_data->bios_address @@ -857,7 +882,7 @@ } static void -ahc_setup_tag_info(char *p, char *end) +ahc_linux_setup_tag_info(char *p, char *end) { char *base; char *tok; @@ -865,7 +890,7 @@ char *tok_end2; int i; int instance; - int device; + int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; @@ -873,7 +898,7 @@ return; instance = -1; - device = -1; + targ = -1; done = FALSE; base = p; /* Forward us just past the ':' */ @@ -886,13 +911,13 @@ case '{': if (instance == -1) instance = 0; - else if (device == -1) - device = 0; + else if (targ == -1) + targ = 0; tok++; break; case '}': - if (device != -1) - device = -1; + if (targ != -1) + targ = -1; else if (instance != -1) instance = -1; tok++; @@ -901,11 +926,11 @@ case '.': if (instance == -1) done = TRUE; - else if (device >= 0) - device++; + else if (targ >= 0) + targ++; else if (instance >= 0) instance++; - if ((device >= AHC_NUM_TARGETS) || + if ((targ >= AHC_NUM_TARGETS) || (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) done = TRUE; tok++; @@ -926,11 +951,12 @@ done = FALSE; } } - if ((instance >= 0) && (device >= 0) && - (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && - (device < AHC_NUM_TARGETS)) - aic7xxx_tag_info[instance].tag_commands[device] = + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = simple_strtoul(tok, NULL, 0) & 0xff; + } tok = tok_end; break; } @@ -980,7 +1006,7 @@ continue; if (strncmp(p, "tag_info", n) == 0) { - ahc_setup_tag_info(p + n, end); + ahc_linux_setup_tag_info(p + n, end); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); @@ -989,8 +1015,10 @@ } else { *(options[i].flag) = ~(*(options[i].flag)); } + break; } } + register_reboot_notifier(&ahc_linux_notifier); return 1; } @@ -1004,7 +1032,7 @@ * Try to detect an Adaptec 7XXX controller. */ int -aic7xxx_detect(Scsi_Host_Template *template) +ahc_linux_detect(Scsi_Host_Template *template) { struct ahc_softc *ahc; int found; @@ -1016,8 +1044,8 @@ */ if (offsetof(struct ahc_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { - printf("aic7xxx_detect: SCSI data structures changed.\n"); - printf("aic7xxx_detect: Unable to attach\n"); + printf("ahc_linux_detect: SCSI data structures changed.\n"); + printf("ahc_linux_detect: Unable to attach\n"); return (0); } #ifdef MODULE @@ -1054,7 +1082,7 @@ found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (aic7xxx_register_host(ahc, template) == 0) + if (ahc_linux_register_host(ahc, template) == 0) found++; } aic7xxx_detect_complete++; @@ -1062,7 +1090,7 @@ } int -aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) { char buf[80]; struct Scsi_Host *host; @@ -1081,12 +1109,13 @@ host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = aic7xxx_select_queue_depth; + host->select_queue_depths = ahc_linux_select_queue_depth; + /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - ahc_set_unit(ahc, ahc_next_unit()); + ahc_set_unit(ahc, ahc_linux_next_unit()); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1094,8 +1123,10 @@ ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, ahc->dev_softc); - aic7xxx_initialize_scsi_bus(ahc); +#endif + ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); return (0); } @@ -1107,7 +1138,7 @@ * scenario. */ static int -ahc_next_unit() +ahc_linux_next_unit() { struct ahc_softc *ahc; int unit; @@ -1129,7 +1160,7 @@ * target. */ void -aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc) +ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) { int i; int numtarg; @@ -1159,7 +1190,7 @@ for (; i < numtarg; i++) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -1175,20 +1206,27 @@ tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate); tinfo->goal = tinfo->user; + /* + * Don't try negotiations that require PPR messages + * until we successfully retrieve Inquiry data. + */ + tinfo->goal.ppr_options = 0; + if (tinfo->goal.transport_version > SCSI_REV_2) + tinfo->goal.transport_version = SCSI_REV_2; ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_target_msg_request(ahc, &devinfo, tinfo, - /*force*/FALSE, /*paused*/FALSE); + ahc_update_neg_request(ahc, &devinfo, tstate, + tinfo, /*force*/FALSE); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc->platform_data->qfrozen++; + ahc_linux_freeze_sim_queue(ahc); init_timer(&ahc->platform_data->reset_timer); ahc->platform_data->reset_timer.data = (u_long)ahc; ahc->platform_data->reset_timer.expires = jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; ahc->platform_data->reset_timer.function = - ahc_release_sim_queue; + ahc_linux_release_sim_queue; add_timer(&ahc->platform_data->reset_timer); } } @@ -1238,6 +1276,11 @@ 0x1000); #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* XXX Need an instance detach in the PCI code */ + if (ahc->dev_softc != NULL) + ahc->dev_softc->driver = NULL; +#endif free(ahc->platform_data, M_DEVBUF); } } @@ -1252,28 +1295,41 @@ } void -ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable) +ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { struct ahc_linux_device *dev; + int was_queuing; + int now_queuing; - dev = ahc_get_device(ahc, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + now_queuing = alg != AHC_QUEUE_NONE; if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - if (enable) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm take - * care of the rest. - */ - dev->maxtags = AHC_MAX_QUEUE; - dev->openings = dev->maxtags - dev->active; + dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + if (now_queuing) { + + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = AHC_MAX_QUEUE; + dev->openings = dev->maxtags - dev->active; + } + if (alg == AHC_QUEUE_TAGGED) + dev->flags |= AHC_DEV_Q_TAGGED; + else + dev->flags |= AHC_DEV_Q_BASIC; } else { /* We can only have one opening */ dev->maxtags = 0; @@ -1326,9 +1382,9 @@ struct ahc_busyq *busyq; struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, chan, targ, - clun, /*alloc*/FALSE); - + dev = ahc_linux_get_device(ahc, chan, + targ, clun, + /*alloc*/FALSE); if (dev == NULL) continue; @@ -1341,7 +1397,7 @@ acmd_links.tqe); count++; cmd->result = status << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } } } @@ -1355,8 +1411,8 @@ * off the input host adapter. */ static void -aic7xxx_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) +ahc_linux_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) { Scsi_Device *device; struct ahc_softc *ahc; @@ -1368,7 +1424,7 @@ scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { - aic7xxx_device_queue_depth(ahc, device); + ahc_linux_device_queue_depth(ahc, device); scbnum += device->queue_depth; } } @@ -1379,11 +1435,11 @@ * Determines the queue depth for a given device. */ static void -aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint8_t tags; ahc_compile_devinfo(&devinfo, @@ -1397,7 +1453,7 @@ tags = 0; if (device->tagged_supported != 0 - && (tstate->discenable & devinfo.target_mask) != 0) { + && (ahc->user_discenable & devinfo.target_mask) != 0) { if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { printf("aic7xxx: WARNING, insufficient " @@ -1418,7 +1474,7 @@ } if (tags != 0) { device->queue_depth = tags; - ahc_set_tags(ahc, &devinfo, TRUE); + ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n", ahc->platform_data->host->host_no, device->channel, device->id, device->lun, tags); @@ -1437,7 +1493,7 @@ * Queue an SCB to the controller. */ int -aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -1451,29 +1507,29 @@ cmd->scsi_done = scsi_done; ahc_lock(ahc, &flags); - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/TRUE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); if (dev == NULL) { ahc_unlock(ahc, &flags); - printf("aic7xxx_queue: Unable to allocate device!\n"); + printf("aic7xxx_linux_queue: Unable to allocate device!\n"); return (-ENOMEM); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); ahc_unlock(ahc, &flags); return (0); } static void -ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint16_t mask; while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -1524,19 +1580,26 @@ SCB_GET_OUR_ID(scb), SCB_GET_TARGET(ahc, scb), &tstate); hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->current.offset; + hscb->scsioffset = tinfo->curr.offset; if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB; - if ((tstate->discenable & mask) != 0) + if ((ahc->user_discenable & mask) != 0) hscb->control |= DISCENB; - if ((tstate->tagenable & mask) != 0) { - /* XXX What about devices that dislike ordered tags? */ - if ((dev->num_commands % 256) == 0) - hscb->control |= MSG_ORDERED_Q_TAG; - else - hscb->control |= MSG_SIMPLE_Q_TAG; + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } } hscb->cdb_len = cmd->cmd_len; @@ -1632,7 +1695,8 @@ LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); dev->openings--; dev->active++; - dev->num_commands++; + dev->commands_issued++; + dev->commands_since_idle_or_otag++; /* * We only allow one untagged transaction @@ -1661,7 +1725,7 @@ * SCSI controller interrupt handler. */ void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -1676,12 +1740,12 @@ * dynamically register one, we'll have to postpone * that until we get integrated into the kernel. */ - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &flags); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } void @@ -1692,11 +1756,11 @@ acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } static struct ahc_linux_target* -ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) { struct ahc_linux_target *targ; u_int target_offset; @@ -1715,7 +1779,7 @@ } static void -ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) { u_int target_offset; @@ -1727,7 +1791,7 @@ } static struct ahc_linux_device* -ahc_alloc_device(struct ahc_softc *ahc, +ahc_linux_alloc_device(struct ahc_softc *ahc, struct ahc_linux_target *targ, u_int lun) { struct ahc_linux_device *dev; @@ -1760,7 +1824,7 @@ } static void -ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; @@ -1769,14 +1833,14 @@ free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0) - ahc_free_target(ahc, targ); + ahc_linux_free_target(ahc, targ); } /* * Return a string describing the driver. */ const char * -aic7xxx_info(struct Scsi_Host *host) +ahc_linux_info(struct Scsi_Host *host) { static char buffer[512]; char ahc_info[256]; @@ -1802,7 +1866,7 @@ void ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code) + u_int target, u_int lun, ac_code code, void *arg) { switch (code) { case AC_TRANSFER_NEG: @@ -1811,7 +1875,7 @@ struct ahc_linux_target *targ; struct info_str info; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int target_offset; info.buffer = buf; @@ -1827,10 +1891,10 @@ * Don't bother reporting results while * negotiations are still pending. */ - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options) + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options) if (bootverbose == 0) break; @@ -1843,24 +1907,24 @@ target_offset += 8; targ = ahc->platform_data->targets[target_offset]; if (targ != NULL - && tinfo->current.period == targ->last_tinfo.period - && tinfo->current.width == targ->last_tinfo.width - && tinfo->current.offset == targ->last_tinfo.offset - && tinfo->current.ppr_options == targ->last_tinfo.ppr_options) + && tinfo->curr.period == targ->last_tinfo.period + && tinfo->curr.width == targ->last_tinfo.width + && tinfo->curr.offset == targ->last_tinfo.offset + && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) if (bootverbose == 0) break; - targ->last_tinfo.period = tinfo->current.period; - targ->last_tinfo.width = tinfo->current.width; - targ->last_tinfo.offset = tinfo->current.offset; - targ->last_tinfo.ppr_options = tinfo->current.ppr_options; + targ->last_tinfo.period = tinfo->curr.period; + targ->last_tinfo.width = tinfo->curr.width; + targ->last_tinfo.offset = tinfo->curr.offset; + targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; printf("(%s:%c:", ahc_name(ahc), channel); if (target == CAM_TARGET_WILDCARD) printf("*): "); else printf("%d): ", target); - ahc_format_transinfo(&info, &tinfo->current); + ahc_format_transinfo(&info, &tinfo->curr); if (info.pos < info.length) *info.buffer = '\0'; else @@ -1909,7 +1973,7 @@ dev = scb->platform_data->dev; dev->active--; dev->openings++; - ahc_unmap_scb(ahc, scb); + ahc_linux_unmap_scb(ahc, scb); if (scb->flags & SCB_SENSE) { memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), MIN(sizeof(struct scsi_sense_data), @@ -1928,10 +1992,19 @@ ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); } else { ahc_set_transaction_status(scb, CAM_REQ_CMP); - ahc_sniff_command(ahc, cmd); + ahc_linux_sniff_command(ahc, cmd); } } else if (ahc_get_transaction_status(scb) == DID_OK) { - ahc_handle_scsi_status(ahc, dev, scb); + ahc_linux_handle_scsi_status(ahc, dev, scb); + } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { + /* + * Should a selection timeout kill the device? + * That depends on whether the selection timeout + * is persistent. Since we have no guarantee that + * the mid-layer will issue an inquiry for this device + * again, we can't just kill it off. + dev->flags |= AHC_DEV_UNCONFIGURED; + */ } if (dev->openings == 1 @@ -1950,10 +2023,14 @@ dev->openings++; } - if (dev->active == 0 - && (dev->flags & AHC_DEV_UNCONFIGURED) != 0) - ahc_free_device(ahc, dev); - else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; + + if (TAILQ_EMPTY(&dev->busyq)) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) + ahc_linux_free_device(ahc, dev); + } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; } @@ -1964,12 +2041,12 @@ } ahc_free_scb(ahc, scb); - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } static void -ahc_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) +ahc_linux_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) { /* * We don't currently trust the mid-layer to @@ -2050,7 +2127,7 @@ } static void -ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { switch (cmd->cmnd[0]) { case INQUIRY: @@ -2058,8 +2135,9 @@ struct ahc_devinfo devinfo; struct scsi_inquiry_data *sid; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *syncrate; + struct ahc_linux_device *dev; u_int scsiid; u_int maxsync; int minlen; @@ -2078,15 +2156,20 @@ /* * Determine if this lun actually exists. If so, * hold on to its corresponding device structure. - */ + * If not, make sure we release the device and + * don't bother processing the rest of this inquiry + * command. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); if (cmd->request_bufflen >= 1 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - struct ahc_linux_device *dev; - dev = ahc_get_device(ahc, cmd->channel, - cmd->target, cmd->lun, - /*alloc*/FALSE); dev->flags &= ~AHC_DEV_UNCONFIGURED; + } else { + dev->flags |= AHC_DEV_UNCONFIGURED; + break; } /* @@ -2108,17 +2191,17 @@ ppr_options = targ_info->user.ppr_options; minlen = offsetof(struct scsi_inquiry_data, version) + 1; if (cmd->request_bufflen >= minlen) { - targ_info->current.protocol_version = SID_ANSI_REV(sid); + targ_info->curr.protocol_version = SID_ANSI_REV(sid); /* * Only attempt SPI3 once we've verified that * the device claims to support SPI3 features. */ - if (targ_info->current.protocol_version < SCSI_REV_2) - targ_info->current.transport_version = + if (targ_info->curr.protocol_version < SCSI_REV_2) + targ_info->curr.transport_version = SID_ANSI_REV(sid); else - targ_info->current.transport_version = + targ_info->curr.transport_version = SCSI_REV_2; } @@ -2137,18 +2220,26 @@ break; } minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; - if (cmd->request_bufflen >= minlen - && (sid->additional_length + 4) >= minlen) { - if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) + /* + * This is a kludge to deal with inquiry requests that + * are not large enough for us to pull the spi3 bits. + * In this case, we assume that a device that tells us + * they can provide inquiry data that spans the SPI3 + * bits can handle a PPR request. If the inquiry + * request has sufficient buffer space to cover these + * bits, we check them to see if any ppr options are + * available. + */ + if ((sid->additional_length + 4) >= minlen) { + if (cmd->request_bufflen >= minlen + && (sid->spi3data & SID_SPI_CLOCK_DT) == 0) ppr_options = 0; - if ((sid->spi3data & SID_SPI_MASK) != 0 - && targ_info->current.protocol_version > SCSI_REV_2) - targ_info->current.transport_version = 3; + if (targ_info->curr.protocol_version > SCSI_REV_2) + targ_info->curr.transport_version = 3; } else { ppr_options = 0; } - ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN); if ((ahc->features & AHC_ULTRA2) != 0) @@ -2162,6 +2253,11 @@ &ppr_options, maxsync); ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, &offset, width, ROLE_UNKNOWN); + if (offset == 0 || period == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } /* Apply our filtered user settings. */ ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE); @@ -2171,14 +2267,14 @@ break; } default: - panic("ahc_filter_command: Unexpected Command type %x\n", + panic("ahc_linux_filter_command: Unexpected Command type %x\n", cmd->cmnd[0]); break; } } static void -ahc_sem_timeout(u_long arg) +ahc_linux_sem_timeout(u_long arg) { struct semaphore *sem; @@ -2187,22 +2283,42 @@ } static void -ahc_release_sim_queue(u_long arg) +ahc_linux_freeze_sim_queue(struct ahc_softc *ahc) +{ + ahc->platform_data->qfrozen++; + if (ahc->platform_data->qfrozen == 1) + scsi_block_requests(ahc->platform_data->host); +} + +static void +ahc_linux_release_sim_queue(u_long arg) { struct ahc_softc *ahc; u_long s; + int unblock_reqs; ahc = (struct ahc_softc *)arg; + unblock_reqs = 0; ahc_lock(ahc, &s); if (ahc->platform_data->qfrozen > 0) ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - ahc_run_device_queues(ahc); + if (ahc->platform_data->qfrozen == 0) { + unblock_reqs = 1; + ahc_linux_run_device_queues(ahc); + } ahc_unlock(ahc, &s); + /* + * There is still a race here. The mid-layer + * should keep its own freeze count and use + * a bottom half handler to run the queues + * so we can unblock with our own lock held. + */ + if (unblock_reqs) + scsi_unblock_requests(ahc->platform_data->host); } static int -aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2242,8 +2358,8 @@ * at all, and the system wanted us to just abort the * command return success. */ - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); if (dev == NULL) { /* @@ -2267,7 +2383,7 @@ if (flag == SCB_ABORT) { TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); retval = SUCCESS; goto done; } @@ -2315,7 +2431,7 @@ ahc->flags |= AHC_ALL_INTERRUPTS; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); ahc->flags &= ~AHC_ALL_INTERRUPTS; @@ -2455,7 +2571,7 @@ retval = SUCCESS; done: if (paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); if (wait) { struct timer_list timer; int ret; @@ -2464,7 +2580,7 @@ init_timer(&timer); timer.data = (u_long)&ahc->platform_data->eh_sem; timer.expires = jiffies + (5 * HZ); - timer.function = ahc_sem_timeout; + timer.function = ahc_linux_sem_timeout; add_timer(&timer); printf("Recovery code sleeping\n"); down(&ahc->platform_data->eh_sem); @@ -2476,12 +2592,12 @@ } ahc_lock(ahc, &s); } - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &s); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return (retval); } @@ -2490,11 +2606,11 @@ * Abort the current SCSI command(s). */ int -aic7xxx_abort(Scsi_Cmnd *cmd) +ahc_linux_abort(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns %d\n", error); return (error); @@ -2504,11 +2620,11 @@ * Attempt to send a target reset message to the device that timed out. */ int -aic7xxx_dev_reset(Scsi_Cmnd *cmd) +ahc_linux_dev_reset(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns %d\n", error); return (error); @@ -2518,7 +2634,7 @@ * Reset the SCSI bus. */ int -aic7xxx_bus_reset(Scsi_Cmnd *cmd) +ahc_linux_bus_reset(Scsi_Cmnd *cmd) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2543,7 +2659,7 @@ "%d SCBs aborted.\n", ahc_name(ahc), found); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return SUCCESS; @@ -2553,7 +2669,7 @@ * Return the disk geometry for the given SCSI device. */ int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) { int heads; int sectors; @@ -2597,14 +2713,23 @@ * module. */ int -aic7xxx_release(struct Scsi_Host * host) +ahc_linux_release(struct Scsi_Host * host) { struct ahc_softc *ahc; if (host != NULL) { + ahc = *(struct ahc_softc **)host->hostdata; ahc_free(ahc); } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } return (0); } @@ -2626,8 +2751,8 @@ for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); if (dev == NULL) continue; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Fri May 4 15:16:28 2001 @@ -28,24 +28,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#3 $ */ #ifndef _AIC7XXX_LINUX_HOST_H_ #define _AIC7XXX_LINUX_HOST_H_ -int aic7xxx_proc_info(char *, char **, off_t, int, int, int); -int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -int aic7xxx_detect(Scsi_Host_Template *); -int aic7xxx_release(struct Scsi_Host *); -const char *aic7xxx_info(struct Scsi_Host *); -int aic7xxx_biosparam(Disk *, kdev_t, int[]); -int aic7xxx_bus_reset(Scsi_Cmnd *); -int aic7xxx_dev_reset(Scsi_Cmnd *); -int aic7xxx_abort(Scsi_Cmnd *); +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int ahc_linux_detect(Scsi_Host_Template *); +int ahc_linux_release(struct Scsi_Host *); +const char *ahc_linux_info(struct Scsi_Host *); +int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_bus_reset(Scsi_Cmnd *); +int ahc_linux_dev_reset(Scsi_Cmnd *); +int ahc_linux_abort(Scsi_Cmnd *); #if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +# define AIC7XXX_BIOSPARAM ahc_linux_biosparam #else # define AIC7XXX_BIOSPARAM NULL #endif @@ -58,23 +58,23 @@ next: NULL, \ module: NULL, \ proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ + proc_info: ahc_linux_proc_info, \ name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ + detect: ahc_linux_detect, \ + release: ahc_linux_release, \ + info: ahc_linux_info, \ command: NULL, \ - queuecommand: aic7xxx_queue, \ + queuecommand: ahc_linux_queue, \ eh_strategy_handler: NULL, \ - eh_abort_handler: aic7xxx_abort, \ - eh_device_reset_handler: aic7xxx_dev_reset, \ - eh_bus_reset_handler: aic7xxx_bus_reset, \ + eh_abort_handler: ahc_linux_abort, \ + eh_device_reset_handler: ahc_linux_dev_reset, \ + eh_bus_reset_handler: ahc_linux_bus_reset, \ eh_host_reset_handler: NULL, \ abort: NULL, \ reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 254, /* max simultaneous cmds */\ + can_queue: 253, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ cmd_per_lun: 2, /* cmds per lun */\ diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Tue Mar 6 22:44:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#17 $ */ #include "aic7xxx_osm.h" @@ -57,7 +57,7 @@ { 0 } }; -static struct pci_driver aic7xxx_pci_driver = { +struct pci_driver aic7xxx_pci_driver = { name: "aic7xxx", probe: ahc_linux_pci_dev_probe, remove: ahc_linux_pci_dev_remove, @@ -133,7 +133,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdev->driver_data = ahc; if (aic7xxx_detect_complete) - aic7xxx_register_host(ahc, aic7xxx_driver_template); + ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif return (0); } @@ -191,11 +191,9 @@ { uint32_t command; u_long base; -#ifdef MMAPIO u_long start; u_long base_page; u_long base_offset; -#endif uint8_t *maddr; command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); @@ -306,11 +304,47 @@ int error; ahc->platform_data->irq = ahc->dev_softc->irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_SHIRQ, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + SA_SHIRQ, "aic7xxx", ahc); return (-error); +} + +void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(ahc->dev_softc, new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Thu Apr 12 12:16:35 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Fri May 4 15:16:28 2001 @@ -18,7 +18,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * * Copyright (c) 2000, 2001 Adaptec Inc. * All rights reserved. @@ -47,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -62,6 +62,10 @@ #include #include +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include #endif @@ -79,14 +83,6 @@ #include "queue.h" #include "scsi_message.h" -/* - * We never have to reference the current task, and the driver core - * makes ample use of this "name". - */ -#ifdef current -#undef current -#endif - /************************* Forward Declarations *******************************/ struct ahc_softc; typedef struct pci_dev *ahc_dev_softc_t; @@ -114,7 +110,7 @@ /***************************** Bus Space/DMA **********************************/ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) typedef dma_addr_t bus_addr_t; #else typedef uint32_t bus_addr_t; @@ -353,11 +349,7 @@ #include #endif -#define AIC7XXX_DRIVER_VERSION "6.1.5" - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif +#define AIC7XXX_DRIVER_VERSION "6.1.13" /**************************** Front End Queues ********************************/ /* @@ -401,7 +393,9 @@ AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08 /* Queued to be run later */ + AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ + AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ + AHC_DEV_Q_TAGGED = 0x20 /* Allow full SCSI2 command queueing */ } ahc_dev_flags; struct ahc_linux_target; @@ -434,7 +428,7 @@ /* * Cumulative command counter. */ - u_int num_commands; + u_long commands_issued; /* * The number of tagged transactions when @@ -465,8 +459,16 @@ * on devices with a fixed number of tags. */ u_int last_queuefull_same_count; - #define AHC_LOCK_TAGS_COUNT 50 + + /* + * How many transactions have been queued + * without the device going idle. We use + * this statistic to + */ + u_int commands_since_idle_or_otag; +#define AHC_OTAG_THRESH 250 + int lun; struct ahc_linux_target *target; }; @@ -570,9 +572,6 @@ #endif #define mb() \ __asm__ __volatile__("mb": : :"memory") -#elif defined(__sparc__) -#define MMAPIO -/* The default mb() define does what this driver wants. -DaveM */ #endif static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); @@ -644,8 +643,8 @@ } /**************************** Initialization **********************************/ -int aic7xxx_register_host(struct ahc_softc *ahc, - Scsi_Host_Template *template); +int ahc_linux_register_host(struct ahc_softc *, + Scsi_Host_Template *); /*************************** Pretty Printing **********************************/ struct info_str { @@ -784,11 +783,24 @@ #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +extern struct pci_driver aic7xxx_pci_driver; +#endif + +typedef enum +{ + AHC_POWER_STATE_D0, + AHC_POWER_STATE_D1, + AHC_POWER_STATE_D2, + AHC_POWER_STATE_D3 +} ahc_power_state; + +void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ int aic7770_linux_probe(Scsi_Host_Template *); int aic7770_map_registers(struct ahc_softc *ahc); -int aic7770_map_int(struct ahc_softc *ahc, - u_int irq, int shared); +int aic7770_map_int(struct ahc_softc *ahc, u_int irq); /******************************* PCI Routines *********************************/ /* @@ -1047,16 +1059,16 @@ } void ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -void aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs); +void ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code); + u_int target, u_int lun, ac_code, void *); void ahc_print_path(struct ahc_softc *, struct scb *); void ahc_platform_dump_card_state(struct ahc_softc *ahc); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Fri May 4 15:16:28 2001 @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $ + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ */ @@ -263,7 +263,7 @@ { ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec 2930C SCSI adapter (VAR)", + "Adaptec 2930C Ultra SCSI adapter (VAR)", ahc_aic7860_setup }, /* aic7870 based controllers */ @@ -452,7 +452,7 @@ { ID_AIC7892_ARO, ID_ALL_MASK, - "Adaptec aic7892 Ultra2 SCSI adapter (ARO)", + "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", ahc_aic7892_setup }, /* aic7895 based controllers */ @@ -546,13 +546,13 @@ { ID_AIC7859 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7859 Ultra SCSI adapter", + "Adaptec aic7859 SCSI adapter", ahc_aic7860_setup }, { ID_AIC7860 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7860 SCSI adapter", + "Adaptec aic7860 Ultra SCSI adapter", ahc_aic7860_setup }, { @@ -644,16 +644,6 @@ #define CACHESIZE 0x0000003ful /* only 5 bits */ #define LATTIME 0x0000ff00ul -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -static void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); static int ahc_ext_scbram_present(struct ahc_softc *ahc); static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large); @@ -761,9 +751,11 @@ if (error != 0) return (error); + ahc->bus_intr = ahc_pci_intr; + /* Remeber how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { - pause_sequencer(ahc); + ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else @@ -786,7 +778,8 @@ /* Perform ALT-Mode Setup */ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS); + ahc_outb(ahc, OPTIONMODE, + OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); ahc_outb(ahc, SFUNCT, sfunct); /* Normal mode setup */ @@ -794,9 +787,6 @@ |TARGCRCENDEN); } - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -825,6 +815,19 @@ /*bytes*/1) & CACHESIZE; ahc->pci_cachesize *= 4; + /* + * We cannot perform ULTRA speeds without the presense + * of the external precision resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->features &= ~AHC_ULTRA; + } + /* See if we have a SEEPROM and perform auto-term */ check_extport(ahc, &sxfrctl1); @@ -879,20 +882,6 @@ if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; - /* - * We cannot perform ULTRA speeds without - * the presense of the external precision - * resistor. - */ - if ((ahc->features & AHC_ULTRA) != 0) { - uint32_t devconfig; - - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - if ((devconfig & REXTVALID) == 0) - ahc->flags |= AHC_ULTRA_DISABLED; - } - /* Core initialization */ error = ahc_init(ahc); if (error != 0) @@ -903,42 +892,16 @@ */ ahc_softc_insert(ahc); - return (0); -} - -static void -ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) -{ - uint32_t cap; - u_int cap_offset; - /* - * Traverse the capability list looking for - * the power management capability. + * Allow interrupts now that we are completely setup. */ - cap = 0; - cap_offset = ahc_pci_read_config(ahc->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahc_pci_read_config(ahc->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahc_pci_read_config(ahc->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahc_pci_write_config(ahc->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + + ahc_intr_enable(ahc, TRUE); + + return (0); } /* @@ -1190,32 +1153,37 @@ } sd.sd_chip = C56_66; } + release_seeprom(&sd); } -#if 0 if (!have_seeprom) { /* * Pull scratch ram settings and treat them as * if they are the contents of an seeprom if * the 'ADPT' signature is found in SCB2. + * We manually compose the data as 16bit values + * to avoid endian issues. */ ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint8_t *sc_bytes; + uint16_t *sc_data; int i; - sc_bytes = (uint8_t *)≻ - for (i = 0; i < 64; i++) - sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i); - /* Byte 0x1c is stored in byte 4 of SCB2 */ - sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4); + sc_data = (uint16_t *)≻ + for (i = 0; i < 32; i++) { + uint16_t val; + int j; + + j = i * 2; + val = ahc_inb(ahc, SRAM_BASE + j) + | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; + } have_seeprom = verify_cksum(&sc); } } -#endif if (!have_seeprom) { if (bootverbose) @@ -1301,9 +1269,8 @@ if (sc.adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; - if ((sc.adapter_control & CFCHNLBPRIMARY) != 0 - && (ahc->features & AHC_MULTI_FUNC) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= + (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; if (sc.bios_control & CFEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; @@ -1318,7 +1285,8 @@ ultraenb = 0; } - if (sc.signature == CFSIGNATURE) { + if (sc.signature == CFSIGNATURE + || sc.signature == CFSIGNATURE2) { uint32_t devconfig; /* Honor the STPWLEVEL settings */ @@ -1362,10 +1330,11 @@ have_autoterm = FALSE; } - if (have_autoterm) + if (have_autoterm) { + acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - - release_seeprom(&sd); + release_seeprom(&sd); + } } static void @@ -1806,7 +1775,7 @@ ahc_outb(ahc, CLRINT, CLRPARERR); } - unpause_sequencer(ahc); + ahc_unpause(ahc); } static int diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Fri May 4 15:16:28 2001 @@ -29,7 +29,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#11 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -174,7 +174,7 @@ { struct ahc_linux_target *targ; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int lun; tinfo = ahc_fetch_transinfo(ahc, channel, our_id, @@ -190,7 +190,7 @@ copy_info(info, "\tGoal: "); ahc_format_transinfo(info, &tinfo->goal); copy_info(info, "\tCurr: "); - ahc_format_transinfo(info, &tinfo->current); + ahc_format_transinfo(info, &tinfo->curr); for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_linux_device *dev; @@ -210,7 +210,7 @@ copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); - copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands); + copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); copy_info(info, "\t\tCommand Openings %d\n", dev->openings); copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); @@ -221,7 +221,7 @@ * Return information to handle /proc support for the driver. */ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, +ahc_linux_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct ahc_softc *ahc; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Tue Mar 6 19:18:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Fri May 4 15:16:28 2001 @@ -86,8 +86,8 @@ #define SELDO 0x40 #define SELDI 0x20 #define SELINGO 0x10 -#define IOERR 0x08 #define SWRAP 0x08 +#define IOERR 0x08 #define SDONE 0x04 #define SPIORDY 0x02 #define DMADONE 0x01 @@ -191,8 +191,8 @@ #define BRDDAT5 0x20 #define BRDDAT4 0x10 #define BRDSTB 0x10 -#define BRDCS 0x08 #define BRDDAT3 0x08 +#define BRDCS 0x08 #define BRDDAT2 0x04 #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 @@ -242,8 +242,8 @@ #define PRELOADEN 0x80 #define WIDEODD 0x40 #define SCSIEN 0x20 -#define SDMAENACK 0x10 #define SDMAEN 0x10 +#define SDMAENACK 0x10 #define HDMAEN 0x08 #define HDMAENACK 0x08 #define DIRECTION 0x04 @@ -271,8 +271,8 @@ #define P_MESGOUT 0xa0 #define P_COMMAND 0x80 #define CDI 0x80 -#define IOI 0x40 #define P_DATAIN 0x40 +#define IOI 0x40 #define MSGI 0x20 #define P_BUSFREE 0x01 #define P_DATAOUT 0x00 @@ -314,9 +314,7 @@ #define LAST_MSG 0x53 -#define TARGET_MSG_REQUEST 0x54 - -#define SCSISEQ_TEMPLATE 0x56 +#define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 #define ENSELI 0x20 #define ENRSELI 0x10 @@ -324,11 +322,11 @@ #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x57 +#define DATA_COUNT_ODD 0x55 -#define INITIATOR_TAG 0x58 +#define INITIATOR_TAG 0x56 -#define SEQ_FLAGS2 0x59 +#define SEQ_FLAGS2 0x57 #define SCB_DMA 0x01 #define SCSICONF 0x5a @@ -345,8 +343,8 @@ #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 @@ -483,7 +481,8 @@ #define DFSTATUS 0x94 #define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 +#define DFCACHETH 0x40 +#define FIFOQWDEMP 0x20 #define MREQPEND 0x10 #define HDONE 0x08 #define DFTHRESH 0x04 @@ -521,18 +520,19 @@ #define COMMAND_PHASE 0x10 #define MSG_IN_PHASE 0x08 #define MSG_OUT_PHASE 0x04 +#define DATA_PHASE_MASK 0x03 #define DATA_IN_PHASE 0x02 #define DATA_OUT_PHASE 0x01 #define SFUNCT 0x9f #define ALT_MODE 0x80 +#define SCB_BASE 0xa0 + #define SCB_CDB_PTR 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 #define SCB_CDB_STORE 0xa0 #define SCB_TARGET_INFO 0xa0 -#define SCB_RESIDUAL_DATACNT 0xa0 - -#define SCB_BASE 0xa0 #define SCB_RESIDUAL_SGPTR 0xa4 @@ -579,13 +579,13 @@ #define SCB_NEXT 0xbf +#define SCB_64_SPARE 0xc0 + #define SEECTL_2840 0xc0 #define CS_2840 0x04 #define CK_2840 0x02 #define DO_2840 0x01 -#define SCB_64_SPARE 0xc0 - #define STATUS_2840 0xc1 #define EEPROM_TF 0x80 #define BIOS_SEL 0x60 @@ -648,8 +648,8 @@ #define WR_DFTHRSH_63 0x30 #define WR_DFTHRSH_50 0x20 #define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH_90 0x06 #define RD_DFTHRSH_85 0x05 #define RD_DFTHRSH_75 0x04 @@ -668,39 +668,39 @@ #define SG_CACHE_PRE 0xfc -#define CMD_GROUP_CODE_SHIFT 0x05 +#define SCB_INITIATOR_TAG 0x03 +#define SCB_TARGET_DATA_DIR 0x01 +#define SCB_TARGET_PHASES 0x00 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 #define BUS_8_BIT 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define TARGET_DATA_IN 0x01 +#define TARGET_CMD_CMPLT 0xfe #define STATUS_QUEUE_FULL 0x28 #define STATUS_BUSY 0x08 #define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 #define TID_SHIFT 0x04 #define SCB_DOWNLOAD_SIZE_64 0x30 -#define SCB_UPLOAD_SIZE 0x20 #define HOST_MAILBOX_SHIFT 0x04 -#define SCB_INITIATOR_TAG 0x03 #define SCB_TARGET_STATUS 0x02 -#define SCB_TARGET_DATA_DIR 0x01 -#define SCB_TARGET_PHASES 0x00 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define TARGET_CMD_CMPLT 0xfe +#define CMD_GROUP_CODE_SHIFT 0x05 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define SCB_DOWNLOAD_SIZE 0x20 #define SEQ_MAILBOX_SHIFT 0x00 +#define TARGET_DATA_IN 0x01 #define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 +#define BUS_16_BIT 0x01 +#define SCB_UPLOAD_SIZE 0x20 /* Downloaded Constant Definitions */ +#define INVERTED_CACHESIZE_MASK 0x03 #define SG_PREFETCH_ADDR_MASK 0x06 #define SG_PREFETCH_ALIGN_MASK 0x05 #define QOUTFIFO_OFFSET 0x00 #define SG_PREFETCH_CNT 0x04 -#define INVERTED_CACHESIZE_MASK 0x03 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h linux/drivers/scsi/aic7xxx/aic7xxx_seq.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Tue Mar 6 19:18:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Fri May 4 15:16:28 2001 @@ -4,7 +4,7 @@ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xde, 0x59, + 0x00, 0x65, 0xe4, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -17,21 +17,21 @@ 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x01, 0x51, 0x20, 0x31, - 0x01, 0x59, 0xb2, 0x00, + 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x5d, + 0x00, 0x51, 0xec, 0x5d, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xde, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0x96, 0x5e, + 0xc1, 0x6a, 0xaa, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, 0x01, 0xf6, 0xd4, 0x30, 0x01, 0x4d, 0x9a, 0x18, - 0xfe, 0x59, 0xb2, 0x08, + 0xfe, 0x57, 0xae, 0x08, 0x01, 0x40, 0x20, 0x31, 0x00, 0x65, 0xe2, 0x58, 0x60, 0x0b, 0x40, 0x78, @@ -48,10 +48,10 @@ 0x08, 0x3c, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -62,7 +62,7 @@ 0x80, 0x3d, 0x7a, 0x00, 0x01, 0x3d, 0xd8, 0x31, 0x01, 0x3d, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x80, 0x66, 0xa8, 0x78, 0x01, 0x66, 0xd8, 0x31, @@ -77,33 +77,33 @@ 0x00, 0x65, 0xb0, 0x48, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x01, 0x66, 0xb0, 0x30, + 0x01, 0x66, 0xac, 0x30, 0x40, 0x3c, 0x78, 0x00, 0x10, 0x03, 0xa6, 0x78, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xb0, 0x40, - 0x61, 0x6a, 0x96, 0x5e, - 0x08, 0x51, 0x2e, 0x71, + 0x61, 0x6a, 0xaa, 0x5e, + 0x08, 0x51, 0x34, 0x71, 0x02, 0x0b, 0xac, 0x78, 0x00, 0x65, 0xa8, 0x40, 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0xc2, 0x60, - 0xc4, 0x6a, 0x32, 0x5d, + 0xc4, 0x6a, 0x44, 0x5d, 0x40, 0x3c, 0xbe, 0x78, - 0x28, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x08, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, + 0x28, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x08, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, 0xff, 0x6a, 0xd8, 0x01, 0xff, 0x6a, 0x32, 0x01, 0x90, 0x3c, 0x78, 0x00, - 0x10, 0x03, 0x4a, 0x69, - 0x00, 0x65, 0x2e, 0x41, + 0x10, 0x03, 0x50, 0x69, + 0x00, 0x65, 0x34, 0x41, 0x1a, 0x01, 0x02, 0x00, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x0f, 0xc8, 0x08, @@ -112,8 +112,8 @@ 0x08, 0x1f, 0xda, 0x78, 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xe8, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -125,11 +125,11 @@ 0x01, 0xb9, 0x1e, 0x30, 0x7f, 0xb9, 0x0a, 0x08, 0x01, 0xb9, 0x0a, 0x30, - 0x01, 0x56, 0xca, 0x30, + 0x01, 0x54, 0xca, 0x30, 0x80, 0xb8, 0xfc, 0x78, 0x80, 0x65, 0xca, 0x00, 0x01, 0x65, 0x00, 0x34, - 0x01, 0x56, 0x00, 0x34, + 0x01, 0x54, 0x00, 0x34, 0x1a, 0x01, 0x02, 0x00, 0x08, 0xb8, 0x06, 0x79, 0x20, 0x01, 0x02, 0x00, @@ -146,40 +146,43 @@ 0x01, 0xb9, 0x7a, 0x30, 0x01, 0xba, 0x7c, 0x30, 0x00, 0x65, 0x00, 0x59, - 0x80, 0x0b, 0xba, 0x79, - 0xe4, 0x6a, 0x32, 0x5d, - 0x80, 0xba, 0x48, 0x5d, + 0x80, 0x0b, 0xc0, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x80, 0xba, 0x5a, 0x5d, 0x20, 0xb8, 0x2c, 0x79, - 0x20, 0x6a, 0x48, 0x5d, - 0x00, 0xa3, 0x48, 0x5d, + 0x20, 0x6a, 0x5a, 0x5d, + 0x00, 0xa3, 0x5a, 0x5d, 0x01, 0xa0, 0x78, 0x30, - 0x10, 0x03, 0x46, 0x69, - 0x08, 0x3c, 0x62, 0x69, - 0x04, 0x3c, 0x88, 0x69, - 0x02, 0x3c, 0x8e, 0x69, - 0x01, 0x3c, 0x4c, 0x79, - 0x00, 0x6a, 0x7e, 0x5e, + 0x10, 0xb8, 0x34, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x00, 0x65, 0xa8, 0x40, + 0x10, 0x03, 0x4c, 0x69, + 0x08, 0x3c, 0x68, 0x69, + 0x04, 0x3c, 0x8e, 0x69, + 0x02, 0x3c, 0x94, 0x69, + 0x01, 0x3c, 0x52, 0x79, 0x01, 0x6a, 0xa2, 0x30, - 0x00, 0x65, 0x9a, 0x59, - 0x04, 0x51, 0x3e, 0x61, + 0x00, 0x65, 0xa0, 0x59, + 0x04, 0x51, 0x42, 0x61, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, + 0x00, 0xbb, 0xec, 0x5d, 0x00, 0x65, 0x2c, 0x41, 0xa4, 0x6a, 0x06, 0x00, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xa8, 0x40, - 0xe4, 0x6a, 0x32, 0x5d, - 0x20, 0x3c, 0x52, 0x79, - 0x02, 0x6a, 0x48, 0x5d, - 0x04, 0x6a, 0x48, 0x5d, - 0x01, 0x03, 0x54, 0x69, + 0xe4, 0x6a, 0x44, 0x5d, + 0x20, 0x3c, 0x58, 0x79, + 0x02, 0x6a, 0x5a, 0x5d, + 0x04, 0x6a, 0x5a, 0x5d, + 0x01, 0x03, 0x5a, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, 0xff, 0x6a, 0x06, 0x08, 0x01, 0x6a, 0x7e, 0x00, - 0x00, 0x65, 0x9a, 0x59, + 0x00, 0x65, 0xa0, 0x59, 0x00, 0x65, 0x04, 0x40, - 0x84, 0x6a, 0x32, 0x5d, + 0x84, 0x6a, 0x44, 0x5d, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -187,60 +190,60 @@ 0x5b, 0x64, 0xc8, 0x28, 0x30, 0x64, 0xca, 0x18, 0x01, 0x6c, 0xc8, 0x30, - 0xff, 0x64, 0x84, 0x79, + 0xff, 0x64, 0x8a, 0x79, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x76, 0x79, - 0x01, 0x64, 0x7c, 0x61, + 0x02, 0x0b, 0x7c, 0x79, + 0x01, 0x64, 0x82, 0x61, 0xf7, 0x01, 0x02, 0x08, 0x01, 0x06, 0xd8, 0x31, 0x01, 0x06, 0x32, 0x31, 0xff, 0x64, 0xc8, 0x18, - 0xff, 0x64, 0x76, 0x69, + 0xff, 0x64, 0x7c, 0x69, 0xf7, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x2e, 0x41, + 0x00, 0x65, 0x34, 0x41, 0x40, 0xa1, 0x7e, 0x10, - 0x04, 0xa1, 0x32, 0x5d, - 0x00, 0x65, 0x62, 0x42, - 0xc4, 0x6a, 0x32, 0x5d, + 0x04, 0xa1, 0x44, 0x5d, + 0x00, 0x65, 0x68, 0x42, + 0xc4, 0x6a, 0x44, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa2, 0x48, 0x5d, + 0x00, 0xa2, 0x5a, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x10, 0x3c, 0x9e, 0x69, - 0x00, 0xbb, 0x64, 0x44, + 0x00, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x10, 0x3c, 0xa4, 0x69, + 0x00, 0xbb, 0x6c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xa6, 0x79, + 0x80, 0xee, 0xac, 0x79, 0xff, 0x6a, 0xdc, 0x09, 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xa8, 0x5d, + 0x1c, 0x6a, 0xba, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x80, 0x6a, 0x74, 0x00, 0x80, 0x3c, 0x78, 0x00, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x62, 0x7a, - 0x80, 0x64, 0x82, 0x73, - 0xa0, 0x64, 0xd8, 0x73, - 0xc0, 0x64, 0xd0, 0x73, - 0xe0, 0x64, 0x18, 0x74, - 0x01, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0xbf, 0x64, 0x68, 0x7a, + 0x80, 0x64, 0x96, 0x73, + 0xa0, 0x64, 0xf0, 0x73, + 0xc0, 0x64, 0xe6, 0x73, + 0xe0, 0x64, 0x20, 0x74, + 0x01, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xd8, 0x79, + 0x09, 0x0c, 0xde, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0x96, 0x5e, + 0xb1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -253,47 +256,47 @@ 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0x9a, 0x7e, - 0x80, 0xeb, 0xf8, 0x79, + 0x08, 0xeb, 0xae, 0x7e, + 0x80, 0xeb, 0xfe, 0x79, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0xfc, 0x69, + 0x08, 0xeb, 0x02, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0xeb, 0x12, 0x72, - 0x08, 0xeb, 0x9a, 0x6e, - 0x80, 0xa3, 0x9a, 0x6e, - 0x04, 0xea, 0x16, 0xe2, - 0x08, 0xee, 0x9a, 0x6e, + 0x80, 0xa3, 0xae, 0x6e, + 0x88, 0xeb, 0x18, 0x72, + 0x08, 0xeb, 0xae, 0x6e, + 0x04, 0xea, 0x1c, 0xe2, + 0x08, 0xee, 0xae, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x00, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0x9a, 0x7e, + 0x80, 0x94, 0xae, 0x7e, 0x04, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, - 0x01, 0x65, 0x20, 0x7a, - 0x01, 0x57, 0xae, 0x10, + 0x01, 0x65, 0x26, 0x7a, + 0x01, 0x55, 0xaa, 0x10, 0x01, 0x65, 0x18, 0x31, 0x02, 0xe9, 0x1a, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xf2, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x57, 0x2e, 0x7a, + 0x01, 0x55, 0x34, 0x7a, 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x32, 0x7a, + 0x80, 0xa3, 0x38, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, - 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x93, 0x26, 0x01, 0xff, 0x6a, 0xd4, 0x0c, 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0x9a, 0x7e, - 0xff, 0x8d, 0x48, 0x6a, - 0xff, 0x8e, 0x48, 0x6a, + 0xff, 0x64, 0xae, 0x7e, + 0xff, 0x8d, 0x4e, 0x6a, + 0xff, 0x8e, 0x4e, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0x9a, 0x56, + 0x00, 0x65, 0xae, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, @@ -304,139 +307,146 @@ 0x03, 0xa0, 0x18, 0x31, 0x03, 0xa0, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbe, 0x5d, - 0x01, 0xa0, 0xae, 0x08, - 0x00, 0x65, 0x88, 0x42, + 0xa0, 0x6a, 0xd0, 0x5d, + 0x01, 0xa0, 0xaa, 0x08, + 0x00, 0x65, 0x8e, 0x42, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x70, 0x6a, 0x04, 0x3b, 0x76, 0x00, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0x64, 0x5d, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x54, 0x6a, + 0x20, 0x3c, 0x5a, 0x6a, 0x20, 0x3c, 0x78, 0x00, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xb6, 0x5d, + 0xac, 0x6a, 0xc8, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xba, 0x5d, - 0x00, 0x65, 0x38, 0x5a, + 0xb3, 0x6a, 0xcc, 0x5d, + 0x00, 0x65, 0x3e, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xae, 0x08, + 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0xa4, 0x98, 0x7a, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0xa4, 0xa0, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x90, 0x7a, + 0x10, 0x0c, 0x96, 0x7a, + 0x03, 0x9e, 0x98, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0x91, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9e, 0x7a, + 0x80, 0xa3, 0xa6, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x57, 0xa2, 0x7a, + 0x01, 0x55, 0xaa, 0x7a, 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0xfc, 0xae, 0x6a, - 0x80, 0x0b, 0xa6, 0x6a, - 0x10, 0x0c, 0xa6, 0x7a, - 0x04, 0x93, 0xc0, 0x6a, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0xfc, 0xb8, 0x6a, + 0x80, 0x0b, 0xae, 0x6a, + 0x10, 0x0c, 0xae, 0x7a, + 0x20, 0x93, 0xae, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x10, 0x94, 0xc0, 0x6a, - 0xd7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc4, 0x6a, - 0x02, 0xfc, 0xce, 0x7a, - 0x01, 0xfc, 0x4e, 0x7b, + 0x02, 0xfc, 0xc2, 0x7a, + 0x40, 0x0d, 0xdc, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x40, 0x0d, 0xd4, 0x6a, - 0x00, 0x65, 0x00, 0x5a, - 0x00, 0x65, 0xc6, 0x42, - 0x80, 0xfc, 0xde, 0x7a, - 0x80, 0xa4, 0xde, 0x6a, + 0x00, 0x65, 0xdc, 0x42, + 0x40, 0x0d, 0xc8, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x65, 0xba, 0x42, + 0x80, 0xfc, 0xd2, 0x7a, + 0x80, 0xa4, 0xd2, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xae, 0x08, - 0x04, 0xfc, 0xe6, 0x7a, - 0x01, 0x57, 0xae, 0x00, + 0xff, 0x6a, 0xaa, 0x08, + 0x04, 0xfc, 0xda, 0x7a, + 0x01, 0x55, 0xaa, 0x00, 0xff, 0x6a, 0x46, 0x09, - 0xff, 0x38, 0xf2, 0x6a, - 0x80, 0xa3, 0xf2, 0x7a, - 0x80, 0x0b, 0xf0, 0x7a, - 0x04, 0x3b, 0xf2, 0x7a, + 0x04, 0x3b, 0xf4, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0xa4, 0xf2, 0x7a, + 0x01, 0xfc, 0xec, 0x7a, + 0x01, 0x94, 0xf4, 0x6a, + 0x00, 0x65, 0x8e, 0x42, + 0x01, 0x94, 0xf2, 0x7a, + 0x10, 0x94, 0xf4, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xf8, 0x6a, + 0xff, 0x38, 0x04, 0x6b, + 0x80, 0xa3, 0x04, 0x7b, + 0x80, 0x0b, 0x02, 0x7b, + 0x04, 0x3b, 0x04, 0x7b, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0x0b, 0x00, 0x6b, - 0x10, 0x0c, 0xf4, 0x7a, - 0x04, 0x93, 0xfe, 0x6a, - 0x01, 0x94, 0xfc, 0x7a, - 0x10, 0x94, 0xfe, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0x0b, 0x12, 0x6b, + 0x10, 0x0c, 0x06, 0x7b, + 0x04, 0x93, 0x10, 0x6b, + 0x01, 0x94, 0x0e, 0x7b, + 0x10, 0x94, 0x10, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x02, 0x6b, - 0xff, 0x08, 0x4e, 0x6b, - 0xff, 0x09, 0x4e, 0x6b, - 0xff, 0x0a, 0x4e, 0x6b, - 0xff, 0x38, 0x1e, 0x7b, + 0x38, 0x93, 0x14, 0x6b, + 0xff, 0x08, 0x60, 0x6b, + 0xff, 0x09, 0x60, 0x6b, + 0xff, 0x0a, 0x60, 0x6b, + 0xff, 0x38, 0x30, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0x00, 0x38, 0xa8, 0x5d, + 0x14, 0x6a, 0xce, 0x5d, + 0x00, 0x38, 0xba, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x44, 0x43, - 0x80, 0xa3, 0x24, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x36, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x08, 0xeb, 0x2a, 0x7b, - 0x00, 0x65, 0x00, 0x5a, - 0x08, 0xeb, 0x26, 0x6b, + 0x00, 0x65, 0x60, 0x43, + 0x08, 0xeb, 0x3c, 0x7b, + 0x00, 0x65, 0x06, 0x5a, + 0x08, 0xeb, 0x38, 0x6b, 0x07, 0xe9, 0x10, 0x31, - 0x80, 0xe9, 0x30, 0x7b, + 0x80, 0xe9, 0x42, 0x7b, 0x80, 0xa3, 0x46, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xbc, 0x5d, - 0x08, 0x6a, 0xa8, 0x5d, + 0xa4, 0x6a, 0xce, 0x5d, + 0x08, 0x6a, 0xba, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x4e, 0x5e, + 0x00, 0x65, 0x62, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0x65, 0x38, 0x5a, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0x3e, 0x5a, + 0x00, 0x65, 0xf2, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0x8c, 0x4c, 0x7b, - 0x01, 0x57, 0xae, 0x10, - 0x80, 0x0b, 0x88, 0x6a, - 0x80, 0x0b, 0x54, 0x6b, - 0x01, 0x0c, 0x50, 0x7b, - 0x10, 0x0c, 0x88, 0x7a, - 0x00, 0x65, 0xf6, 0x59, - 0xff, 0x38, 0x66, 0x7b, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0x8c, 0x5e, 0x7b, + 0x01, 0x55, 0xaa, 0x10, + 0x80, 0x0b, 0x8e, 0x6a, + 0x80, 0x0b, 0x68, 0x6b, + 0x01, 0x0c, 0x62, 0x7b, + 0x10, 0x0c, 0x8e, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, + 0x00, 0x65, 0xfc, 0x59, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x68, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -445,13 +455,13 @@ 0xfd, 0xb4, 0x68, 0x09, 0x12, 0x01, 0x02, 0x00, 0x12, 0x01, 0x02, 0x00, - 0x04, 0x3c, 0xbe, 0x79, + 0x04, 0x3c, 0xc4, 0x79, 0xfb, 0x3c, 0x78, 0x08, - 0x04, 0x93, 0x2e, 0x79, - 0x01, 0x0c, 0x7c, 0x6b, - 0x00, 0x65, 0x2e, 0x41, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x04, 0x93, 0x34, 0x79, + 0x01, 0x0c, 0x90, 0x6b, + 0x00, 0x65, 0x34, 0x41, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -461,16 +471,16 @@ 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xaa, 0x53, + 0xa0, 0x6a, 0xbe, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbc, 0x5d, - 0x00, 0xbc, 0xa8, 0x5d, + 0xa0, 0x6a, 0xce, 0x5d, + 0x00, 0xbc, 0xba, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xc2, 0x43, + 0x00, 0x65, 0xd6, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -480,114 +490,112 @@ 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x60, 0x5e, - 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x65, 0x74, 0x5e, 0x02, 0x93, 0x26, 0x01, - 0x04, 0x0b, 0xc6, 0x6b, - 0x10, 0x0c, 0xc2, 0x7b, - 0x01, 0x03, 0xc6, 0x6b, + 0x04, 0x0b, 0xda, 0x6b, + 0x10, 0x0c, 0xd6, 0x7b, + 0x01, 0x03, 0xda, 0x6b, + 0x20, 0x93, 0xd6, 0x6b, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xca, 0x6b, + 0x38, 0x93, 0xe0, 0x6b, 0x10, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0x06, 0x50, 0x31, - 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0xc4, 0x41, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x04, 0x64, - 0x10, 0xb8, 0x28, 0x6c, - 0x01, 0xb9, 0xdc, 0x30, - 0x01, 0x6e, 0xc8, 0x30, - 0x01, 0x54, 0xca, 0x30, - 0x80, 0xb9, 0xe8, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x80, 0xb9, 0xec, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x00, 0x65, 0x28, 0x6c, + 0x80, 0x65, 0x0c, 0x64, + 0x10, 0xb8, 0x30, 0x6c, 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0xf4, 0x6b, + 0x40, 0xb8, 0xfc, 0x6b, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x08, 0x7c, + 0x20, 0xb8, 0x10, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, - 0x00, 0xbb, 0x08, 0x44, - 0xff, 0x65, 0x08, 0x64, - 0x00, 0x65, 0x28, 0x44, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, + 0x00, 0xbb, 0x10, 0x44, + 0xff, 0x65, 0x10, 0x64, + 0x00, 0x65, 0x30, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0xd6, 0x73, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0xec, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x64, 0x6a, 0x2c, 0x5d, - 0x80, 0x64, 0x9e, 0x6c, - 0x04, 0x64, 0x74, 0x74, - 0x02, 0x64, 0x82, 0x74, - 0x00, 0x6a, 0x44, 0x74, - 0x03, 0x64, 0x90, 0x74, - 0x23, 0x64, 0x30, 0x74, - 0x08, 0x64, 0x40, 0x74, - 0x61, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xa0, 0x5d, - 0x08, 0x51, 0xc0, 0x71, - 0x00, 0x65, 0x28, 0x44, - 0x80, 0x04, 0x3e, 0x7c, - 0x51, 0x6a, 0x22, 0x5d, - 0x01, 0x51, 0x3e, 0x64, - 0x01, 0xa4, 0x3a, 0x7c, - 0x01, 0x57, 0x40, 0x7c, - 0x41, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, - 0x07, 0x6a, 0x1a, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x64, 0x6a, 0x3e, 0x5d, + 0x80, 0x64, 0xae, 0x6c, + 0x04, 0x64, 0x7c, 0x74, + 0x02, 0x64, 0x8a, 0x74, + 0x00, 0x6a, 0x4c, 0x74, + 0x03, 0x64, 0xa0, 0x74, + 0x23, 0x64, 0x38, 0x74, + 0x08, 0x64, 0x48, 0x74, + 0x61, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xb2, 0x5d, + 0x08, 0x51, 0xc6, 0x71, + 0x00, 0x65, 0x30, 0x44, + 0x80, 0x04, 0x46, 0x7c, + 0x51, 0x6a, 0x34, 0x5d, + 0x01, 0x51, 0x46, 0x64, + 0x01, 0xa4, 0x42, 0x7c, + 0x01, 0x55, 0x48, 0x7c, + 0x41, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, + 0x07, 0x6a, 0x2a, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xbe, 0x41, - 0x10, 0xb8, 0x48, 0x7c, - 0xa1, 0x6a, 0x96, 0x5e, - 0x01, 0xb4, 0x4e, 0x6c, - 0x02, 0xb4, 0x50, 0x6c, - 0x01, 0xa4, 0x50, 0x7c, - 0xff, 0xa8, 0x60, 0x7c, + 0x00, 0x65, 0xc4, 0x41, + 0x10, 0xb8, 0x50, 0x7c, + 0xa1, 0x6a, 0xaa, 0x5e, + 0x01, 0xb4, 0x56, 0x6c, + 0x02, 0xb4, 0x58, 0x6c, + 0x01, 0xa4, 0x58, 0x7c, + 0xff, 0xa8, 0x68, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, - 0xff, 0xa8, 0x60, 0x7c, - 0x71, 0x6a, 0x96, 0x5e, - 0x40, 0x51, 0x60, 0x64, - 0x00, 0x65, 0x76, 0x5e, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0xbb, 0x64, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0xbb, 0xec, 0x5d, + 0xff, 0xa8, 0x68, 0x7c, + 0x71, 0x6a, 0xaa, 0x5e, + 0x40, 0x51, 0x68, 0x64, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0xbb, 0x6c, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0x7e, 0xdd, - 0x00, 0x51, 0x90, 0x5d, + 0x00, 0x6a, 0x90, 0xdd, + 0x00, 0x51, 0xa2, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0x92, 0x5e, - 0x20, 0xb8, 0xd0, 0x69, + 0x00, 0x65, 0xa6, 0x5e, + 0x20, 0xb8, 0xd6, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0x94, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x20, 0x3c, 0x40, 0x7c, + 0x00, 0xb9, 0xa4, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x01, 0x06, 0xd4, 0x30, + 0x20, 0x3c, 0xc4, 0x79, + 0x20, 0x3c, 0x48, 0x7c, 0x04, 0x14, 0x58, 0x31, + 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0xa0, 0x6a, 0xb4, 0x5d, - 0x00, 0x65, 0x40, 0x44, + 0x14, 0x6a, 0xce, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0xa0, 0x6a, 0xc6, 0x5d, + 0x00, 0x65, 0xc4, 0x41, 0xdf, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0x48, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -598,103 +606,104 @@ 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xac, 0x4c, + 0x00, 0x65, 0xbc, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xb4, 0x54, + 0x00, 0x65, 0xc4, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xbe, 0x4c, + 0x00, 0x65, 0xce, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xc6, 0x54, + 0x00, 0x65, 0xd6, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0xd8, 0x74, - 0x00, 0x51, 0x56, 0x5d, + 0xff, 0x51, 0xe8, 0x74, + 0x00, 0x51, 0x68, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0xfa, 0x44, + 0x00, 0x65, 0x0a, 0x45, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0xfa, 0x74, - 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x3e, 0x0a, 0x75, + 0x00, 0x65, 0x88, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x16, 0x65, + 0xe0, 0x3f, 0x26, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x16, 0x65, - 0x51, 0x6a, 0x22, 0x5d, - 0x00, 0x51, 0x56, 0x5d, - 0x51, 0x6a, 0x22, 0x5d, + 0x20, 0x12, 0x26, 0x65, + 0x51, 0x6a, 0x34, 0x5d, + 0x00, 0x51, 0x68, 0x5d, + 0x51, 0x6a, 0x34, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x14, 0x65, + 0x00, 0x3d, 0x24, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x14, 0x65, + 0x00, 0x3e, 0x24, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x14, 0x7d, + 0x04, 0xb8, 0x24, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x0a, 0x6d, + 0x20, 0xb8, 0x1a, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0x94, 0x5c, + 0x00, 0x3d, 0xa4, 0x5c, 0x01, 0x64, 0x20, 0x31, 0x80, 0x6a, 0x78, 0x00, 0x00, 0x65, 0x02, 0x59, - 0x10, 0xb8, 0x40, 0x7c, - 0xff, 0x6a, 0x1a, 0x5d, - 0x00, 0x65, 0x40, 0x44, - 0x00, 0x65, 0x74, 0x5e, - 0x31, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, + 0x10, 0xb8, 0x48, 0x7c, + 0xff, 0x6a, 0x2a, 0x5d, + 0x00, 0x65, 0x48, 0x44, + 0x00, 0x65, 0x88, 0x5e, + 0x31, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x24, 0x45, + 0x81, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x36, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x24, 0x7d, - 0x04, 0x0c, 0x1e, 0x6d, + 0x01, 0x0c, 0x36, 0x7d, + 0x04, 0x0c, 0x30, 0x6d, 0xe0, 0x03, 0x7e, 0x08, - 0xe0, 0x3f, 0xbe, 0x61, + 0xe0, 0x3f, 0xc4, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x32, 0x6d, + 0x01, 0x03, 0x44, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x40, 0x75, - 0x40, 0x65, 0x40, 0x7d, - 0x00, 0x65, 0x40, 0x5d, + 0x00, 0x66, 0x52, 0x75, + 0x40, 0x65, 0x52, 0x7d, + 0x00, 0x65, 0x52, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x4a, 0x7d, + 0x02, 0x0b, 0x5c, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x4e, 0x7d, + 0x02, 0x0b, 0x60, 0x7d, 0xf7, 0x01, 0x02, 0x0c, - 0x80, 0x3c, 0x9a, 0x6e, - 0x21, 0x6a, 0x96, 0x46, + 0x80, 0x3c, 0xae, 0x6e, + 0x21, 0x6a, 0xaa, 0x46, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0x76, 0x75, + 0xff, 0x41, 0x88, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x66, 0x45, - 0xff, 0xbf, 0x76, 0x75, + 0x00, 0x65, 0x78, 0x45, + 0xff, 0xbf, 0x88, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x60, 0x65, - 0xff, 0x52, 0x74, 0x75, + 0x00, 0xbb, 0x72, 0x65, + 0xff, 0x52, 0x86, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -702,28 +711,28 @@ 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x45, + 0x00, 0x51, 0xec, 0x45, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, - 0x01, 0x6a, 0xa8, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, + 0x01, 0x6a, 0xba, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x94, 0x7d, + 0x80, 0xee, 0xa6, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, - 0x81, 0x6a, 0x96, 0x5e, - 0x01, 0x0c, 0xa0, 0x7d, - 0x04, 0x0c, 0x9e, 0x6d, + 0x00, 0x65, 0x80, 0x46, + 0x81, 0x6a, 0xaa, 0x5e, + 0x01, 0x0c, 0xb2, 0x7d, + 0x04, 0x0c, 0xb0, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -742,7 +751,7 @@ 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0xce, 0x45, + 0x00, 0x65, 0xe0, 0x45, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -753,61 +762,62 @@ 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0xee, 0x7d, + 0x04, 0x3b, 0x00, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xea, 0x65, - 0x00, 0x65, 0x06, 0x46, + 0xdc, 0xee, 0xfc, 0x65, + 0x00, 0x65, 0x18, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xf6, 0x7d, + 0x80, 0xee, 0x08, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0xfa, 0x65, + 0x50, 0xee, 0x0c, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x00, 0x66, + 0x88, 0xee, 0x12, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x04, 0x66, + 0xd8, 0xee, 0x16, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x08, 0x6e, + 0x18, 0xee, 0x1a, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, - 0x20, 0x6a, 0xa8, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, + 0x20, 0x6a, 0xba, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x22, 0x6e, + 0x04, 0x3b, 0x34, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x5c, 0x5e, - 0x00, 0x65, 0x1a, 0x66, + 0x00, 0x65, 0x70, 0x5e, + 0x00, 0x65, 0x2c, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, + 0x00, 0x65, 0x80, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x01, 0x94, 0x26, 0x6e, - 0x10, 0x94, 0x28, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, + 0x20, 0x94, 0x38, 0x6e, + 0x10, 0x94, 0x3a, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, 0x07, 0x8c, 0xca, 0x18, 0x3d, 0x65, 0xca, 0x28, 0x00, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x42, 0x5e, + 0x00, 0x65, 0x56, 0x5e, 0xff, 0x65, 0xca, 0x10, 0x05, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x26, 0x46, + 0x04, 0x64, 0x82, 0x76, + 0x00, 0x65, 0x38, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x40, 0x6e, + 0x08, 0x93, 0x54, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0x6c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -824,23 +834,23 @@ 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0x6c, 0x7e, + 0x08, 0x94, 0x80, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x70, 0x6e, + 0x08, 0x93, 0x84, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0x92, 0x6e, + 0x04, 0xb8, 0xa6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, 0xff, 0x6a, 0x76, 0x05, - 0xff, 0x42, 0x8e, 0x66, - 0xff, 0x41, 0x86, 0x66, - 0xd1, 0x6a, 0x96, 0x5e, + 0xff, 0x42, 0xa2, 0x66, + 0xff, 0x41, 0x9a, 0x66, + 0xd1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x45, + 0x00, 0xbb, 0xec, 0x45, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -919,7 +929,7 @@ static int ahc_patch14_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_DT) == 0); + return ((ahc->features & AHC_ULTRA2) == 0); } static int ahc_patch13_func(struct ahc_softc *ahc); @@ -927,7 +937,7 @@ static int ahc_patch13_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA2) == 0); + return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); } static int ahc_patch12_func(struct ahc_softc *ahc); @@ -935,7 +945,7 @@ static int ahc_patch12_func(struct ahc_softc *ahc) { - return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); + return ((ahc->features & AHC_ULTRA) != 0); } static int ahc_patch11_func(struct ahc_softc *ahc); @@ -943,7 +953,7 @@ static int ahc_patch11_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA) != 0); + return ((ahc->features & AHC_HS_MAILBOX) != 0); } static int ahc_patch10_func(struct ahc_softc *ahc); @@ -951,7 +961,7 @@ static int ahc_patch10_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_HS_MAILBOX) != 0); + return ((ahc->features & AHC_MULTI_TID) != 0); } static int ahc_patch9_func(struct ahc_softc *ahc); @@ -959,7 +969,7 @@ static int ahc_patch9_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_MULTI_TID) != 0); + return ((ahc->features & AHC_CMD_CHAN) != 0); } static int ahc_patch8_func(struct ahc_softc *ahc); @@ -967,7 +977,7 @@ static int ahc_patch8_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_CMD_CHAN) != 0); + return ((ahc->flags & AHC_INITIATORROLE) != 0); } static int ahc_patch7_func(struct ahc_softc *ahc); @@ -975,7 +985,7 @@ static int ahc_patch7_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_INITIATORROLE) != 0); + return ((ahc->flags & AHC_TARGETROLE) != 0); } static int ahc_patch6_func(struct ahc_softc *ahc); @@ -983,7 +993,7 @@ static int ahc_patch6_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TARGETROLE) != 0); + return ((ahc->features & AHC_DT) == 0); } static int ahc_patch5_func(struct ahc_softc *ahc); @@ -1051,28 +1061,29 @@ { ahc_patch5_func, 22, 2, 1 }, { ahc_patch3_func, 27, 1, 2 }, { ahc_patch0_func, 28, 1, 1 }, - { ahc_patch6_func, 37, 65, 21 }, - { ahc_patch7_func, 37, 1, 1 }, - { ahc_patch8_func, 45, 3, 2 }, + { ahc_patch6_func, 34, 1, 1 }, + { ahc_patch7_func, 37, 65, 21 }, + { ahc_patch8_func, 37, 1, 1 }, + { ahc_patch9_func, 45, 3, 2 }, { ahc_patch0_func, 48, 3, 1 }, - { ahc_patch9_func, 52, 1, 2 }, + { ahc_patch10_func, 52, 1, 2 }, { ahc_patch0_func, 53, 2, 3 }, { ahc_patch1_func, 53, 1, 2 }, { ahc_patch0_func, 54, 1, 1 }, { ahc_patch2_func, 56, 2, 1 }, - { ahc_patch8_func, 58, 1, 2 }, + { ahc_patch9_func, 58, 1, 2 }, { ahc_patch0_func, 59, 1, 1 }, - { ahc_patch8_func, 63, 1, 2 }, + { ahc_patch9_func, 63, 1, 2 }, { ahc_patch0_func, 64, 1, 1 }, - { ahc_patch8_func, 73, 1, 2 }, + { ahc_patch9_func, 73, 1, 2 }, { ahc_patch0_func, 74, 1, 1 }, - { ahc_patch8_func, 77, 1, 2 }, + { ahc_patch9_func, 77, 1, 2 }, { ahc_patch0_func, 78, 1, 1 }, - { ahc_patch10_func, 88, 1, 2 }, + { ahc_patch11_func, 88, 1, 2 }, { ahc_patch0_func, 89, 1, 1 }, - { ahc_patch8_func, 97, 1, 2 }, + { ahc_patch9_func, 97, 1, 2 }, { ahc_patch0_func, 98, 1, 1 }, - { ahc_patch7_func, 102, 9, 4 }, + { ahc_patch8_func, 102, 9, 4 }, { ahc_patch1_func, 104, 1, 2 }, { ahc_patch0_func, 105, 1, 1 }, { ahc_patch2_func, 107, 2, 1 }, @@ -1081,147 +1092,162 @@ { ahc_patch0_func, 121, 2, 3 }, { ahc_patch2_func, 121, 1, 2 }, { ahc_patch0_func, 122, 1, 1 }, - { ahc_patch6_func, 123, 4, 2 }, + { ahc_patch7_func, 123, 4, 2 }, { ahc_patch0_func, 127, 1, 1 }, - { ahc_patch11_func, 129, 2, 1 }, + { ahc_patch12_func, 129, 2, 1 }, { ahc_patch1_func, 131, 1, 2 }, { ahc_patch0_func, 132, 1, 1 }, - { ahc_patch6_func, 133, 4, 1 }, - { ahc_patch6_func, 144, 77, 9 }, - { ahc_patch4_func, 156, 1, 1 }, - { ahc_patch1_func, 172, 1, 1 }, - { ahc_patch8_func, 180, 1, 2 }, - { ahc_patch0_func, 181, 1, 1 }, - { ahc_patch8_func, 190, 1, 2 }, - { ahc_patch0_func, 191, 1, 1 }, - { ahc_patch8_func, 207, 6, 2 }, - { ahc_patch0_func, 213, 6, 1 }, - { ahc_patch7_func, 221, 18, 2 }, - { ahc_patch1_func, 234, 1, 1 }, - { ahc_patch1_func, 241, 1, 2 }, - { ahc_patch0_func, 242, 2, 2 }, - { ahc_patch11_func, 243, 1, 1 }, - { ahc_patch8_func, 251, 33, 2 }, - { ahc_patch1_func, 267, 16, 1 }, - { ahc_patch12_func, 284, 14, 1 }, - { ahc_patch1_func, 298, 2, 2 }, - { ahc_patch0_func, 300, 3, 3 }, - { ahc_patch8_func, 300, 1, 2 }, - { ahc_patch0_func, 301, 2, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch8_func, 310, 1, 1 }, - { ahc_patch8_func, 313, 2, 2 }, - { ahc_patch0_func, 315, 4, 1 }, - { ahc_patch12_func, 319, 1, 1 }, - { ahc_patch13_func, 322, 2, 3 }, - { ahc_patch8_func, 322, 1, 2 }, - { ahc_patch0_func, 323, 1, 1 }, - { ahc_patch1_func, 332, 40, 6 }, - { ahc_patch6_func, 341, 1, 1 }, - { ahc_patch7_func, 342, 1, 1 }, - { ahc_patch14_func, 344, 2, 1 }, - { ahc_patch15_func, 346, 5, 1 }, - { ahc_patch0_func, 372, 51, 15 }, - { ahc_patch12_func, 372, 1, 1 }, - { ahc_patch6_func, 374, 2, 2 }, - { ahc_patch16_func, 375, 1, 1 }, - { ahc_patch8_func, 378, 1, 1 }, - { ahc_patch17_func, 385, 1, 1 }, - { ahc_patch12_func, 390, 9, 3 }, - { ahc_patch8_func, 391, 3, 2 }, - { ahc_patch0_func, 394, 3, 1 }, - { ahc_patch8_func, 402, 6, 2 }, - { ahc_patch0_func, 408, 8, 1 }, - { ahc_patch12_func, 416, 1, 1 }, - { ahc_patch8_func, 418, 1, 2 }, - { ahc_patch0_func, 419, 1, 1 }, - { ahc_patch6_func, 422, 1, 1 }, - { ahc_patch6_func, 423, 1, 1 }, - { ahc_patch7_func, 424, 2, 1 }, - { ahc_patch8_func, 426, 1, 1 }, - { ahc_patch12_func, 427, 9, 4 }, - { ahc_patch8_func, 427, 1, 1 }, - { ahc_patch8_func, 434, 2, 1 }, - { ahc_patch0_func, 436, 4, 3 }, - { ahc_patch8_func, 436, 1, 2 }, - { ahc_patch0_func, 437, 3, 1 }, - { ahc_patch1_func, 441, 2, 1 }, - { ahc_patch6_func, 443, 5, 2 }, - { ahc_patch0_func, 448, 1, 1 }, - { ahc_patch7_func, 449, 113, 22 }, - { ahc_patch1_func, 450, 3, 2 }, - { ahc_patch0_func, 453, 5, 3 }, - { ahc_patch8_func, 453, 2, 2 }, - { ahc_patch0_func, 455, 3, 1 }, - { ahc_patch1_func, 460, 2, 2 }, - { ahc_patch0_func, 462, 6, 3 }, - { ahc_patch8_func, 462, 2, 2 }, - { ahc_patch0_func, 464, 3, 1 }, + { ahc_patch7_func, 133, 4, 1 }, + { ahc_patch7_func, 144, 80, 9 }, + { ahc_patch4_func, 162, 1, 1 }, + { ahc_patch1_func, 175, 1, 1 }, + { ahc_patch9_func, 183, 1, 2 }, + { ahc_patch0_func, 184, 1, 1 }, + { ahc_patch9_func, 193, 1, 2 }, + { ahc_patch0_func, 194, 1, 1 }, + { ahc_patch9_func, 210, 6, 2 }, + { ahc_patch0_func, 216, 6, 1 }, + { ahc_patch8_func, 224, 18, 2 }, + { ahc_patch1_func, 237, 1, 1 }, + { ahc_patch1_func, 244, 1, 2 }, + { ahc_patch0_func, 245, 2, 2 }, + { ahc_patch12_func, 246, 1, 1 }, + { ahc_patch9_func, 254, 33, 2 }, + { ahc_patch1_func, 270, 16, 1 }, + { ahc_patch13_func, 287, 14, 1 }, + { ahc_patch1_func, 301, 2, 2 }, + { ahc_patch0_func, 303, 3, 3 }, + { ahc_patch9_func, 303, 1, 2 }, + { ahc_patch0_func, 304, 2, 1 }, + { ahc_patch1_func, 308, 1, 2 }, + { ahc_patch0_func, 309, 1, 1 }, + { ahc_patch9_func, 313, 1, 1 }, + { ahc_patch9_func, 316, 2, 2 }, + { ahc_patch0_func, 318, 4, 1 }, + { ahc_patch13_func, 322, 1, 1 }, + { ahc_patch14_func, 325, 2, 3 }, + { ahc_patch9_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch6_func, 331, 1, 2 }, + { ahc_patch0_func, 332, 1, 1 }, + { ahc_patch1_func, 336, 45, 10 }, + { ahc_patch6_func, 345, 2, 4 }, + { ahc_patch7_func, 345, 1, 1 }, + { ahc_patch8_func, 346, 1, 1 }, + { ahc_patch0_func, 347, 1, 1 }, + { ahc_patch15_func, 348, 1, 1 }, + { ahc_patch6_func, 367, 6, 3 }, + { ahc_patch15_func, 367, 5, 1 }, + { ahc_patch0_func, 373, 5, 1 }, + { ahc_patch0_func, 381, 51, 15 }, + { ahc_patch13_func, 381, 1, 1 }, + { ahc_patch7_func, 383, 2, 2 }, + { ahc_patch16_func, 384, 1, 1 }, + { ahc_patch9_func, 387, 1, 1 }, + { ahc_patch17_func, 394, 1, 1 }, + { ahc_patch13_func, 399, 9, 3 }, + { ahc_patch9_func, 400, 3, 2 }, + { ahc_patch0_func, 403, 3, 1 }, + { ahc_patch9_func, 411, 6, 2 }, + { ahc_patch0_func, 417, 8, 1 }, + { ahc_patch13_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, + { ahc_patch7_func, 431, 1, 1 }, + { ahc_patch7_func, 432, 1, 1 }, + { ahc_patch8_func, 433, 3, 3 }, + { ahc_patch6_func, 434, 1, 2 }, + { ahc_patch0_func, 435, 1, 1 }, + { ahc_patch9_func, 436, 1, 1 }, + { ahc_patch13_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 5, 2 }, + { ahc_patch0_func, 458, 1, 1 }, + { ahc_patch8_func, 459, 107, 23 }, + { ahc_patch1_func, 460, 3, 2 }, + { ahc_patch0_func, 463, 5, 3 }, + { ahc_patch9_func, 463, 2, 2 }, + { ahc_patch0_func, 465, 3, 1 }, { ahc_patch1_func, 470, 2, 2 }, - { ahc_patch0_func, 472, 9, 7 }, - { ahc_patch8_func, 472, 5, 6 }, - { ahc_patch18_func, 472, 1, 2 }, - { ahc_patch0_func, 473, 1, 1 }, - { ahc_patch18_func, 475, 1, 2 }, - { ahc_patch0_func, 476, 1, 1 }, - { ahc_patch0_func, 477, 4, 1 }, - { ahc_patch1_func, 486, 1, 1 }, - { ahc_patch2_func, 498, 2, 2 }, - { ahc_patch0_func, 500, 2, 2 }, - { ahc_patch19_func, 500, 2, 1 }, - { ahc_patch19_func, 536, 7, 1 }, - { ahc_patch3_func, 564, 1, 2 }, - { ahc_patch0_func, 565, 1, 1 }, - { ahc_patch20_func, 568, 1, 1 }, - { ahc_patch7_func, 570, 95, 26 }, - { ahc_patch4_func, 571, 1, 1 }, - { ahc_patch8_func, 578, 2, 2 }, - { ahc_patch0_func, 580, 3, 1 }, - { ahc_patch18_func, 587, 2, 2 }, - { ahc_patch0_func, 589, 1, 1 }, - { ahc_patch18_func, 593, 10, 3 }, - { ahc_patch5_func, 595, 8, 1 }, - { ahc_patch0_func, 603, 9, 2 }, - { ahc_patch5_func, 604, 8, 1 }, - { ahc_patch4_func, 614, 1, 2 }, - { ahc_patch0_func, 615, 1, 1 }, - { ahc_patch18_func, 616, 1, 2 }, - { ahc_patch0_func, 617, 3, 2 }, - { ahc_patch4_func, 619, 1, 1 }, - { ahc_patch5_func, 620, 1, 1 }, - { ahc_patch5_func, 623, 1, 1 }, - { ahc_patch5_func, 625, 1, 1 }, - { ahc_patch4_func, 627, 2, 2 }, - { ahc_patch0_func, 629, 2, 1 }, + { ahc_patch0_func, 472, 6, 3 }, + { ahc_patch9_func, 472, 2, 2 }, + { ahc_patch0_func, 474, 3, 1 }, + { ahc_patch1_func, 480, 2, 2 }, + { ahc_patch0_func, 482, 9, 7 }, + { ahc_patch9_func, 482, 5, 6 }, + { ahc_patch18_func, 482, 1, 2 }, + { ahc_patch0_func, 483, 1, 1 }, + { ahc_patch18_func, 485, 1, 2 }, + { ahc_patch0_func, 486, 1, 1 }, + { ahc_patch0_func, 487, 4, 1 }, + { ahc_patch6_func, 491, 3, 2 }, + { ahc_patch0_func, 494, 1, 1 }, + { ahc_patch1_func, 497, 1, 1 }, + { ahc_patch6_func, 502, 1, 2 }, + { ahc_patch0_func, 503, 1, 1 }, + { ahc_patch19_func, 540, 7, 1 }, + { ahc_patch3_func, 568, 1, 2 }, + { ahc_patch0_func, 569, 1, 1 }, + { ahc_patch20_func, 572, 1, 1 }, + { ahc_patch8_func, 574, 100, 31 }, + { ahc_patch4_func, 575, 1, 1 }, + { ahc_patch1_func, 581, 2, 2 }, + { ahc_patch0_func, 583, 1, 1 }, + { ahc_patch9_func, 584, 3, 3 }, + { ahc_patch14_func, 585, 1, 1 }, + { ahc_patch0_func, 587, 4, 1 }, + { ahc_patch18_func, 595, 2, 2 }, + { ahc_patch0_func, 597, 1, 1 }, + { ahc_patch18_func, 601, 10, 3 }, + { ahc_patch5_func, 603, 8, 1 }, + { ahc_patch0_func, 611, 9, 2 }, + { ahc_patch5_func, 612, 8, 1 }, + { ahc_patch4_func, 622, 1, 2 }, + { ahc_patch0_func, 623, 1, 1 }, + { ahc_patch18_func, 624, 1, 2 }, + { ahc_patch0_func, 625, 3, 2 }, + { ahc_patch4_func, 627, 1, 1 }, + { ahc_patch5_func, 628, 1, 1 }, { ahc_patch5_func, 631, 1, 1 }, - { ahc_patch5_func, 634, 1, 1 }, - { ahc_patch5_func, 637, 1, 1 }, - { ahc_patch18_func, 641, 1, 1 }, - { ahc_patch18_func, 644, 1, 1 }, - { ahc_patch4_func, 650, 1, 1 }, - { ahc_patch6_func, 665, 16, 1 }, - { ahc_patch4_func, 683, 20, 1 }, - { ahc_patch8_func, 704, 4, 2 }, - { ahc_patch0_func, 708, 4, 1 }, - { ahc_patch8_func, 712, 4, 2 }, - { ahc_patch0_func, 716, 3, 1 }, - { ahc_patch21_func, 724, 14, 1 }, - { ahc_patch6_func, 738, 3, 1 }, - { ahc_patch8_func, 750, 24, 8 }, - { ahc_patch18_func, 754, 1, 2 }, - { ahc_patch0_func, 755, 1, 1 }, - { ahc_patch13_func, 760, 4, 2 }, - { ahc_patch0_func, 764, 7, 3 }, - { ahc_patch22_func, 764, 5, 2 }, - { ahc_patch0_func, 769, 2, 1 }, - { ahc_patch0_func, 774, 40, 3 }, - { ahc_patch17_func, 786, 16, 2 }, - { ahc_patch0_func, 802, 1, 1 }, - { ahc_patch4_func, 826, 1, 1 }, - { ahc_patch4_func, 827, 3, 2 }, - { ahc_patch0_func, 830, 1, 1 }, - { ahc_patch4_func, 831, 12, 1 } + { ahc_patch5_func, 633, 1, 1 }, + { ahc_patch4_func, 635, 2, 2 }, + { ahc_patch0_func, 637, 2, 1 }, + { ahc_patch5_func, 639, 1, 1 }, + { ahc_patch5_func, 642, 1, 1 }, + { ahc_patch5_func, 645, 1, 1 }, + { ahc_patch18_func, 649, 1, 1 }, + { ahc_patch18_func, 652, 1, 1 }, + { ahc_patch4_func, 658, 1, 1 }, + { ahc_patch6_func, 661, 1, 2 }, + { ahc_patch0_func, 662, 1, 1 }, + { ahc_patch7_func, 674, 16, 1 }, + { ahc_patch4_func, 692, 20, 1 }, + { ahc_patch9_func, 713, 4, 2 }, + { ahc_patch0_func, 717, 4, 1 }, + { ahc_patch9_func, 721, 4, 2 }, + { ahc_patch0_func, 725, 3, 1 }, + { ahc_patch6_func, 731, 1, 1 }, + { ahc_patch21_func, 733, 14, 1 }, + { ahc_patch7_func, 747, 3, 1 }, + { ahc_patch9_func, 759, 24, 8 }, + { ahc_patch18_func, 763, 1, 2 }, + { ahc_patch0_func, 764, 1, 1 }, + { ahc_patch14_func, 769, 4, 2 }, + { ahc_patch0_func, 773, 7, 3 }, + { ahc_patch22_func, 773, 5, 2 }, + { ahc_patch0_func, 778, 2, 1 }, + { ahc_patch0_func, 783, 41, 3 }, + { ahc_patch17_func, 795, 17, 2 }, + { ahc_patch0_func, 812, 1, 1 }, + { ahc_patch4_func, 836, 1, 1 }, + { ahc_patch4_func, 837, 3, 2 }, + { ahc_patch0_func, 840, 1, 1 }, + { ahc_patch4_func, 841, 12, 1 } }; struct cs { u_int16_t begin; @@ -1229,11 +1255,11 @@ } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 683, 699 }, - { 827, 830 }, - { 831, 837 }, - { 839, 841 }, - { 841, 843 } + { 692, 708 }, + { 837, 840 }, + { 841, 847 }, + { 849, 851 }, + { 851, 853 } }; const int num_critical_sections = sizeof(critical_sections) / sizeof(*critical_sections); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/Makefile linux/drivers/scsi/aic7xxx/aicasm/Makefile --- v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/Makefile Tue Mar 6 22:44:16 2001 +++ linux/drivers/scsi/aic7xxx/aicasm/Makefile Fri May 4 15:16:28 2001 @@ -2,17 +2,23 @@ CSRCS= aicasm.c aicasm_symbol.c GENSRCS= aicasm_gram.c aicasm_scan.c - -GENHDRS= y.tab.h +DEPHDRS= aicdb.h +GENHDRS= y.tab.h aicdb.h SRCS= ${GENSRCS} ${CSRCS} CLEANFILES= ${GENSRCS} ${GENHDRS} y.output # Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -ldb1 +AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d NOMAN= noman +ifneq ($(HOSTCC),) +AICASM_CC= $(HOSTCC) +else +AICASM_CC= $(CC) +endif + ifdef DEBUG CFLAGS+= -DDEBUG -g YFLAGS+= -t -v @@ -21,8 +27,21 @@ .SUFFIXES= .l .y .c -$(PROG): $(SRCS) - $(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) +$(PROG): $(SRCS) $(DEPHDRS) + $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +aicdb.h: + @if [ -e "/usr/include/db3/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db2/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + else \ + echo "*** Install db development libraries"; \ + fi clean: rm -f $(CLEANFILES) $(PROG) diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $ + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#5 $ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -36,7 +36,7 @@ #include #ifdef __linux__ -#include +#include "aicdb.h" #else #include #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.4.4/linux/drivers/scsi/eata.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/scsi/eata.c Sat May 19 17:43:06 2001 @@ -1,6 +1,10 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 1 May 2001 Rev. 6.05 for linux 2.4.4 + * + Clean up all pci related routines. + * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) + * * 30 Jan 2001 Rev. 6.04 for linux 2.4.1 * + Call pci_resource_start after pci_enable_device. * @@ -828,77 +832,38 @@ return FALSE; } -static inline void tune_pci_port(unsigned long port_base) { - -#if defined(CONFIG_PCI) - - unsigned int addr, k; - struct pci_dev *dev = NULL; - - if (!pci_present()) return; - - for (k = 0; k < MAX_PCI; k++) { - - if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break; - - if (pci_enable_device (dev)) continue; - - addr = pci_resource_start (dev, 0); - -#if defined(DEBUG_PCI_DETECT) - printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, dev->bus->number, dev->devfn, addr); -#endif - - if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) { - pci_set_master(dev); - return; - } - - } - -#endif /* end CONFIG_PCI */ - - return; -} - -static inline int - get_pci_irq(unsigned long port_base, unsigned char *apic_irq) { +static inline struct pci_dev *get_pci_dev(unsigned long port_base) { #if defined(CONFIG_PCI) unsigned int addr; struct pci_dev *dev = NULL; - if (!pci_present()) return FALSE; + if (!pci_present()) return NULL; while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { - - if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue; + addr = pci_resource_start (dev, 0); #if defined(DEBUG_PCI_DETECT) - printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n", - driver_name, dev->bus->number, dev->devfn, addr, dev->irq); + printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", + driver_name, dev->bus->number, dev->devfn, addr); #endif - if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) { - *apic_irq = dev->irq; - return TRUE; - } - + if (addr + PCI_BASE_ADDRESS_0 == port_base) return dev; } #endif /* end CONFIG_PCI */ - return FALSE; + return NULL; } static inline int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) { unsigned char irq, dma_channel, subversion, i; - unsigned char protocol_rev, apic_irq; + unsigned char protocol_rev; struct eata_info info; char *bus_type, dma_name[16], tag_type; + struct pci_dev *pdev; /* Allowed DMA channels for ISA (0 indicates reserved) */ unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; @@ -1002,9 +967,11 @@ printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", name, irq); - if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) { - printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq); - irq = apic_irq; + pdev = get_pci_dev(port_base); + + if (pdev && (irq != pdev->irq)) { + printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq); + irq = pdev->irq; } /* Board detected, allocate its IRQ */ @@ -1064,10 +1031,6 @@ sh[j]->can_queue = (ushort) ntohs(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; sh[j]->select_queue_depths = select_queue_depths; - - /* Register the I/O space that we use */ - request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name); - memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->subversion = subversion; HD(j)->protocol_rev = protocol_rev; @@ -1185,7 +1148,8 @@ info.pci, info.eisa, info.raidnum); #endif - tune_pci_port(sh[j]->io_port); + if (pdev) pci_set_master(pdev); + return TRUE; } @@ -1254,19 +1218,26 @@ if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break; - if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue; + if (pci_enable_device (dev)) { + +#if defined(DEBUG_PCI_DETECT) + printk("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", + driver_name, dev->bus->number, dev->devfn); +#endif + + continue; + } + + addr = pci_resource_start (dev, 0); #if defined(DEBUG_PCI_DETECT) printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", driver_name, k, dev->bus->number, dev->devfn, addr); #endif - if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) - continue; - /* Order addresses according to rev_scan value */ io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = - (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0; + addr + PCI_BASE_ADDRESS_0; } #endif /* end CONFIG_PCI */ @@ -1327,7 +1298,7 @@ static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b + 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d }; static const unsigned char data_none_cmds[] = { diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h --- v2.4.4/linux/drivers/scsi/eata.h Fri Feb 16 16:02:36 2001 +++ linux/drivers/scsi/eata.h Sat May 19 17:43:06 2001 @@ -13,7 +13,7 @@ int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "6.04.00" +#define EATA_VERSION "6.05.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.4.4/linux/drivers/scsi/fdomain.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/fdomain.c Fri May 4 15:11:42 2001 @@ -587,9 +587,7 @@ static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ { - do { - udelay(10*1000); - } while (--amount); + mdelay(10*amount); } inline static void fdomain_make_bus_idle( void ) @@ -971,7 +969,7 @@ return 0; shpnt->irq = interrupt_level; shpnt->io_port = port_base; - scsi_set_pci_device(shpnt->pci_dev, pdev); + scsi_set_pci_device(shpnt, pdev); shpnt->n_io_port = 0x10; print_banner( shpnt ); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.4.4/linux/drivers/scsi/gdth.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/gdth.c Sat May 19 17:43:06 2001 @@ -2,7 +2,7 @@ * GDT ISA/EISA/PCI Disk Array Controller driver for Linux * * * * gdth.c * - * Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner * + * Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner * * * * * * * @@ -20,9 +20,92 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Tested with Linux 1.2.13, ..., 2.2.4 * + * Tested with Linux 1.2.13, ..., 2.2.18, ..., 2.4.2 * * * * $Log: gdth.c,v $ + * Revision 1.49 2001/03/15 15:07:17 achim + * New __setup interface for boot command line options added + * + * Revision 1.48 2001/02/06 12:36:28 achim + * Bugfix Cluster protocol + * + * Revision 1.47 2001/01/10 14:42:06 achim + * New switch shared_access added + * + * Revision 1.46 2001/01/09 08:11:35 achim + * gdth_command() removed + * meaning of Scsi_Pointer members changed + * + * Revision 1.45 2000/11/16 12:02:24 achim + * Changes for kernel 2.4 + * + * Revision 1.44 2000/10/11 08:44:10 achim + * Clustering changes: New flag media_changed added + * + * Revision 1.43 2000/09/20 12:59:01 achim + * DPMEM remap functions for all PCI controller types implemented + * Small changes for ia64 platform + * + * Revision 1.42 2000/07/20 09:04:50 achim + * Small changes for kernel 2.4 + * + * Revision 1.41 2000/07/04 14:11:11 achim + * gdth_analyse_hdrive() added to rescan drives after online expansion + * + * Revision 1.40 2000/06/27 11:24:16 achim + * Changes Clustering, Screenservice + * + * Revision 1.39 2000/06/15 13:09:04 achim + * Changes for gdth_do_cmd() + * + * Revision 1.38 2000/06/15 12:08:43 achim + * Bugfix gdth_sync_event(), service SCREENSERVICE + * Data direction for command 0xc2 changed to DOU + * + * Revision 1.37 2000/05/25 13:50:10 achim + * New driver parameter virt_ctr added + * + * Revision 1.36 2000/05/04 08:50:46 achim + * Event buffer now in gdth_ha_str + * + * Revision 1.35 2000/03/03 10:44:08 achim + * New event_string only valid for the RP controller family + * + * Revision 1.34 2000/03/02 14:55:29 achim + * New mechanism for async. event handling implemented + * + * Revision 1.33 2000/02/21 15:37:37 achim + * Bugfix Alpha platform + DPMEM above 4GB + * + * Revision 1.32 2000/02/14 16:17:37 achim + * Bugfix sense_buffer[] + raw devices + * + * Revision 1.31 2000/02/10 10:29:00 achim + * Delete sense_buffer[0], if command OK + * + * Revision 1.30 1999/11/02 13:42:39 achim + * ARRAY_DRV_LIST2 implemented + * Now 255 log. and 100 host drives supported + * + * Revision 1.29 1999/10/05 13:28:47 achim + * GDT_CLUST_RESET added + * + * Revision 1.28 1999/08/12 13:44:54 achim + * MOUNTALL removed + * Cluster drives -> removeable drives + * + * Revision 1.27 1999/06/22 07:22:38 achim + * Small changes + * + * Revision 1.26 1999/06/10 16:09:12 achim + * Cluster Host Drive support: Bugfixes + * + * Revision 1.25 1999/06/01 16:03:56 achim + * gdth_init_pci(): Manipulate config. space to start RP controller + * + * Revision 1.24 1999/05/26 11:53:06 achim + * Cluster Host Drive support added + * * Revision 1.23 1999/03/26 09:12:31 achim * Default value for hdr_channel set to 0 * @@ -120,7 +203,7 @@ * Initial revision * ************************************************************************/ -#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" +#ident "$Id: gdth.c,v 1.49 2001/03/15 15:07:17 achim Exp $" /* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the @@ -147,10 +230,17 @@ * max_ids:x x - target ID count per channel (1..MAXID) * rescan:Y rescan all channels/IDs * rescan:N use all devices found until now + * virt_ctr:Y map every channel to a virtual controller + * virt_ctr:N use multi channel support * hdr_channel:x x - number of virtual bus for host drives + * shared_access:Y disable driver reserve/release protocol to + * access a shared resource from several nodes, + * appropiate controller firmware required + * shared_access:N enable driver reserve/release protocol * - * The default value is: "gdth=disable:N,reserve_mode:1,reverse_scan:N, - * max_ids:127,rescan:N,hdr_channel:0". + * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, + * max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0, + * shared_access:N". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". * * When loading the gdth driver as a module, the same options are available. @@ -160,10 +250,22 @@ * '1' in place of 'Y' and '0' in place of 'N'. * * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 - * max_ids=127 rescan=0 hdr_channel=0" + * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". */ +/* The meaning of the Scsi_Pointer members in this driver is as follows: + * ptr: Chaining + * this_residual: Command priority + * buffer: Unused + * buffers_residual: Timeout value + * Status: Command status (gdth_do_cmd()) + * Message: Additional info (gdth_do_cmd()) + * have_data_in: Flag for gdth_wait_completion() + * sent_command: Opcode special command + * phase: Service/parameter/return code special command + */ + #ifdef MODULE #include #endif @@ -181,13 +283,32 @@ #include #include #include +#ifdef GDTH_RTC +#include +#endif +#if LINUX_VERSION_CODE >= 0x020100 #include +#else +#include +#endif +#if LINUX_VERSION_CODE >= 0x020126 +#include +#endif #include #include #include +#if LINUX_VERSION_CODE >= 0x020322 #include +#elif LINUX_VERSION_CODE >= 0x02015F +#include +#endif + +#if LINUX_VERSION_CODE >= 0x010300 #include +#else +#include "../block/blk.h" +#endif #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -196,9 +317,13 @@ static void gdth_delay(int milliseconds); static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs); +#if LINUX_VERSION_CODE >= 0x010346 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs); +#else +static void gdth_interrupt(int irq,struct pt_regs *regs); +#endif static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp); -static int gdth_async_event(int hanum,int service); +static int gdth_async_event(int hanum); static void gdth_log_event(gdth_evt_data *dvr, char *buffer); static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority); @@ -233,19 +358,25 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, ulong32 p2,ulong32 p3); static int gdth_search_drives(int hanum); +static int gdth_analyse_hdrive(int hanum, ushort hdrive); static void *gdth_mmap(ulong paddr, ulong size); static void gdth_munmap(void *addr); static const char *gdth_ctr_name(int hanum); +#if LINUX_VERSION_CODE >= 0x010300 static void gdth_flush(int hanum); +#if LINUX_VERSION_CODE >= 0x020100 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); +#else +static int halt_called = FALSE; +void gdth_halt(void); +#endif +#endif #ifdef DEBUG_GDTH static unchar DebugState = DEBUG_GDTH; -extern long sys_syslog(int,char*,int); -#define LOGEN sys_syslog(7,NULL,0) #ifdef __SERIAL__ #define MAX_SERBUF 160 @@ -314,9 +445,9 @@ #define TRACE3(a) {if (DebugState!=0) {ser_printk a;}} #else /* !__SERIAL__ */ -#define TRACE(a) {if (DebugState==1) {LOGEN;printk a;}} -#define TRACE2(a) {if (DebugState==1 || DebugState==2) {LOGEN;printk a;}} -#define TRACE3(a) {if (DebugState!=0) {LOGEN;printk a;}} +#define TRACE(a) {if (DebugState==1) {printk a;}} +#define TRACE2(a) {if (DebugState==1 || DebugState==2) {printk a;}} +#define TRACE3(a) {if (DebugState!=0) {printk a;}} #endif #else /* !DEBUG */ @@ -341,6 +472,64 @@ #define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) +#if LINUX_VERSION_CODE < 0x010300 +static void *gdth_mmap(ulong paddr, ulong size) +{ + if (paddr >= high_memory) + return NULL; + else + return (void *)paddr; +} +static void gdth_munmap(void *addr) +{ +} +inline ulong32 virt_to_phys(volatile void *addr) +{ + return (ulong32)addr; +} +inline void *phys_to_virt(ulong32 addr) +{ + return (void *)addr; +} +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt +#define gdth_readb(addr) (*(volatile unchar *)(addr)) +#define gdth_readw(addr) (*(volatile ushort *)(addr)) +#define gdth_readl(addr) (*(volatile ulong32 *)(addr)) +#define gdth_writeb(b,addr) (*(volatile unchar *)(addr) = (b)) +#define gdth_writew(b,addr) (*(volatile ushort *)(addr) = (b)) +#define gdth_writel(b,addr) (*(volatile ulong32 *)(addr) = (b)) +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) + +#define PCI_SLOT(devfn) ((devfn >> 3) & 0x1f) + +#elif LINUX_VERSION_CODE < 0x020100 +static int remapped = FALSE; +static void *gdth_mmap(ulong paddr, ulong size) +{ + if ( paddr >= high_memory) { + remapped = TRUE; + return vremap(paddr, size); + } else { + return (void *)paddr; + } +} +static void gdth_munmap(void *addr) +{ + if (remapped) + vfree(addr); + remapped = FALSE; +} +#define gdth_readb(addr) readb((ulong)(addr)) +#define gdth_readw(addr) readw((ulong)(addr)) +#define gdth_readl(addr) (ulong32)readl((ulong)(addr)) +#define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) +#define gdth_writew(b,addr) writew((b),(ulong)(addr)) +#define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) + +#else static void *gdth_mmap(ulong paddr, ulong size) { return ioremap(paddr, size); @@ -354,7 +543,9 @@ #define gdth_readl(addr) (ulong32)readl((ulong)(addr)) #define gdth_writeb(b,addr) writeb((b),(ulong)(addr)) #define gdth_writew(b,addr) writew((b),(ulong)(addr)) -#define gdth_writel(b,addr) writel((b),(ulong)(addr)) +#define gdth_writel(b,addr) writel((ulong32)(b),(ulong)(addr)) +#endif + static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ @@ -388,15 +579,24 @@ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU, DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN }; /* __initfunc, __initdata macros */ -#include +#if LINUX_VERSION_CODE >= 0x020322 +#define GDTH_INITFUNC(type, func) type __init func +#elif LINUX_VERSION_CODE >= 0x020126 +#define GDTH_INITFUNC(type, func) __initfunc(type func) +#else +#define GDTH_INITFUNC(type, func) type func +#define __initdata +#define __init +#endif +#if LINUX_VERSION_CODE >= 0x02015F #define GDTH_INIT_LOCK_HA(ha) spin_lock_init(&(ha)->smp_lock) #define GDTH_LOCK_HA(ha,flags) spin_lock_irqsave(&(ha)->smp_lock,flags) #define GDTH_UNLOCK_HA(ha,flags) spin_unlock_irqrestore(&(ha)->smp_lock,flags) @@ -405,6 +605,16 @@ #define GDTH_UNLOCK_SCSI_DONE(flags) spin_unlock_irqrestore(&io_request_lock,flags) #define GDTH_LOCK_SCSI_DOCMD() spin_lock_irq(&io_request_lock) #define GDTH_UNLOCK_SCSI_DOCMD() spin_unlock_irq(&io_request_lock) +#else +#define GDTH_INIT_LOCK_HA(ha) do {} while (0) +#define GDTH_LOCK_HA(ha,flags) do {save_flags(flags); cli();} while (0) +#define GDTH_UNLOCK_HA(ha,flags) do {restore_flags(flags);} while (0) + +#define GDTH_LOCK_SCSI_DONE(flags) do {} while (0) +#define GDTH_UNLOCK_SCSI_DONE(flags) do {} while (0) +#define GDTH_LOCK_SCSI_DOCMD() do {} while (0) +#define GDTH_UNLOCK_SCSI_DOCMD() do {} while (0) +#endif /* LILO and modprobe/insmod parameters */ /* IRQ list for GDT3000/3020 EISA controllers */ @@ -428,8 +638,13 @@ static int max_ids = MAXID; /* rescan all IDs */ static int rescan = 0; +/* map channels to virtual controllers */ +static int virt_ctr = 0; +/* shared access */ +static int shared_access = 0; #ifdef MODULE +#if LINUX_VERSION_CODE >= 0x02011A /* parameters for modprobe/insmod */ MODULE_PARM(irq, "i"); MODULE_PARM(disable, "i"); @@ -439,25 +654,45 @@ MODULE_PARM(hdr_channel, "i"); MODULE_PARM(max_ids, "i"); MODULE_PARM(rescan, "i"); +MODULE_PARM(virt_ctr, "i"); +MODULE_PARM(shared_access, "i"); MODULE_AUTHOR("Achim Leubner"); #endif +#endif /* /proc support */ +#if LINUX_VERSION_CODE >= 0x010300 #include +#if LINUX_VERSION_CODE < 0x020322 +struct proc_dir_entry proc_scsi_gdth = { + PROC_SCSI_GDTH, 4, "gdth", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif #include "gdth_proc.h" #include "gdth_proc.c" +#endif +#if LINUX_VERSION_CODE >= 0x020100 /* notifier block to get a notify on system shutdown/halt/reboot */ static struct notifier_block gdth_notifier = { gdth_halt, NULL, 0 }; +#endif + static void gdth_delay(int milliseconds) { if (milliseconds == 0) { udelay(1); } else { +#if LINUX_VERSION_CODE >= 0x020168 mdelay(milliseconds); +#else + int i; + for (i = 0; i < milliseconds; ++i) + udelay(1000); +#endif } } @@ -465,24 +700,24 @@ { *cyls = size /HEADS/SECS; if (*cyls <= MAXCYLS) { - *heads = HEADS; - *secs = SECS; - } else { /* too high for 64*32 */ - *cyls = size /MEDHEADS/MEDSECS; - if (*cyls <= MAXCYLS) { - *heads = MEDHEADS; - *secs = MEDSECS; - } else { /* too high for 127*63 */ - *cyls = size /BIGHEADS/BIGSECS; - *heads = BIGHEADS; - *secs = BIGSECS; - } + *heads = HEADS; + *secs = SECS; + } else { /* too high for 64*32 */ + *cyls = size /MEDHEADS/MEDSECS; + if (*cyls <= MAXCYLS) { + *heads = MEDHEADS; + *secs = MEDSECS; + } else { /* too high for 127*63 */ + *cyls = size /BIGHEADS/BIGSECS; + *heads = BIGHEADS; + *secs = BIGSECS; + } } } /* controller search and initialization functions */ -static int __init gdth_search_eisa(ushort eisa_adr) +GDTH_INITFUNC(static int, gdth_search_eisa(ushort eisa_adr)) { ulong32 id; @@ -500,7 +735,7 @@ } -static int __init gdth_search_isa(ulong32 bios_adr) +GDTH_INITFUNC(static int, gdth_search_isa(ulong32 bios_adr)) { void *addr; ulong32 id; @@ -516,11 +751,16 @@ } -static int __init gdth_search_pci(gdth_pci_str *pcistr) +GDTH_INITFUNC(static int, gdth_search_pci(gdth_pci_str *pcistr)) { - ulong32 base0, base1, base2; + ulong base0, base1, base2; ushort device_id, cnt; +#if LINUX_VERSION_CODE >= 0x2015C struct pci_dev *pdev; +#else + int error; + ushort idx; +#endif TRACE(("gdth_search_pci()\n")); @@ -530,11 +770,46 @@ if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 && device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP) continue; +#if LINUX_VERSION_CODE >= 0x20363 + pdev = NULL; + while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) + != NULL) { + if (pci_enable_device(pdev)) + continue; + if (cnt >= MAXHA) + return cnt; + /* GDT PCI controller found, resources are already in pdev */ + pcistr[cnt].pdev = pdev; + pcistr[cnt].device_id = device_id; + pcistr[cnt].bus = pdev->bus->number; + pcistr[cnt].device_fn = pdev->devfn; + pcistr[cnt].irq = pdev->irq; + base0 = pci_resource_flags(pdev, 0); + base1 = pci_resource_flags(pdev, 1); + base2 = pci_resource_flags(pdev, 2); + if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ + device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ + if (!(base0 & IORESOURCE_MEM)) + continue; + pcistr[cnt].dpmem = pci_resource_start(pdev, 0); + } else { /* GDT6110, GDT6120, .. */ + if (!(base0 & IORESOURCE_MEM) || + !(base2 & IORESOURCE_MEM) || + !(base1 & IORESOURCE_IO)) + continue; + pcistr[cnt].dpmem = pci_resource_start(pdev, 2); + pcistr[cnt].io_mm = pci_resource_start(pdev, 0); + pcistr[cnt].io = pci_resource_start(pdev, 1); + } + TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", + pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), + pcistr[cnt].irq, pcistr[cnt].dpmem)); + cnt++; + } +#elif LINUX_VERSION_CODE >= 0x2015C pdev = NULL; while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) != NULL) { - if (pci_enable_device(pdev)) - continue; if (cnt >= MAXHA) return cnt; /* GDT PCI controller found, resources are already in pdev */ @@ -543,16 +818,16 @@ pcistr[cnt].bus = pdev->bus->number; pcistr[cnt].device_fn = pdev->devfn; pcistr[cnt].irq = pdev->irq; - base0 = pdev->resource[0].flags; - base1 = pdev->resource[1].flags; - base2 = pdev->resource[2].flags; + base0 = pdev->base_address[0]; + base1 = pdev->base_address[1]; + base2 = pdev->base_address[2]; if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ if ((base0 & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) continue; - pcistr[cnt].dpmem = pdev->resource[0].start; - } else { /* GDT6110, GDT6120, .. */ + pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK; + } else { /* GDT6110, GDT6120, .. */ if ((base0 & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY || (base2 & PCI_BASE_ADDRESS_SPACE) != @@ -560,21 +835,77 @@ (base1 & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; - pcistr[cnt].dpmem = pdev->resource[2].start; - pcistr[cnt].io_mm = pdev->resource[0].start; - pcistr[cnt].io = pdev->resource[1].start; + pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK; + pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK; + pcistr[cnt].io = base1 & PCI_BASE_ADDRESS_IO_MASK; } - TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n", + TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), pcistr[cnt].irq, pcistr[cnt].dpmem)); cnt++; } +#else + idx = 0; + while (!pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,idx++, + &pcistr[cnt].bus,&pcistr[cnt].device_fn)) { + if (cnt >= MAXHA) + return cnt; + /* GDT PCI ctr. found, now read resources from config space */ +#if LINUX_VERSION_CODE >= 0x010300 +#define GDTH_BASEP (int *) +#else +#define GDTH_BASEP +#endif + if ((error = pcibios_read_config_dword(pcistr[cnt].bus, + pcistr[cnt].device_fn, + PCI_BASE_ADDRESS_0, + GDTH_BASEP&base0)) || + (error = pcibios_read_config_dword(pcistr[cnt].bus, + pcistr[cnt].device_fn, + PCI_BASE_ADDRESS_1, + GDTH_BASEP&base1)) || + (error = pcibios_read_config_dword(pcistr[cnt].bus, + pcistr[cnt].device_fn, + PCI_BASE_ADDRESS_2, + GDTH_BASEP&base2)) || + (error = pcibios_read_config_byte(pcistr[cnt].bus, + pcistr[cnt].device_fn, + PCI_INTERRUPT_LINE, + &pcistr[cnt].irq))) { + printk("GDT-PCI: error %d reading configuration space", error); + continue; + } + pcistr[cnt].device_id = device_id; + if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ + device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ + if ((base0 & PCI_BASE_ADDRESS_SPACE) != + PCI_BASE_ADDRESS_SPACE_MEMORY) + continue; + pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK; + } else { /* GDT6110, GDT6120, .. */ + if ((base0 & PCI_BASE_ADDRESS_SPACE) != + PCI_BASE_ADDRESS_SPACE_MEMORY || + (base2 & PCI_BASE_ADDRESS_SPACE) != + PCI_BASE_ADDRESS_SPACE_MEMORY || + (base1 & PCI_BASE_ADDRESS_SPACE) != + PCI_BASE_ADDRESS_SPACE_IO) + continue; + pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK; + pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK; + pcistr[cnt].io = base1 & PCI_BASE_ADDRESS_IO_MASK; + } + TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", + pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), + pcistr[cnt].irq, pcistr[cnt].dpmem)); + cnt++; + } +#endif } return cnt; } -static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt) +GDTH_INITFUNC(static void, gdth_sort_pci(gdth_pci_str *pcistr, int cnt)) { gdth_pci_str temp; int i, changed; @@ -612,7 +943,7 @@ } -static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) +GDTH_INITFUNC(static int, gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)) { ulong32 retries,id; unchar prot_ver,eisacf,i,irq_found; @@ -701,7 +1032,7 @@ } -static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) +GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)) { register gdt2_dpram_str *dp2_ptr; int i; @@ -798,14 +1129,18 @@ } -static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) +GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) { register gdt6_dpram_str *dp6_ptr; register gdt6c_dpram_str *dp6c_ptr; register gdt6m_dpram_str *dp6m_ptr; ulong32 retries; unchar prot_ver; + ushort command; int i, found = FALSE; +#if LINUX_VERSION_CODE < 0x2015C + int rom_addr; +#endif TRACE(("gdth_init_pci()\n")); @@ -820,8 +1155,51 @@ printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } + /* check and reset interface area */ dp6_ptr = (gdt6_dpram_str *)ha->brd; - /* reset interface area */ + gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); + if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) { + printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", + pcistr->dpmem); + found = FALSE; + for (i = 0xC8000; i < 0xE8000; i += 0x4000) { + gdth_munmap(ha->brd); + ha->brd = gdth_mmap(i, sizeof(ushort)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + if (gdth_readw(ha->brd) != 0xffff) { + TRACE2(("init_pci_old() address 0x%x busy\n", i)); + continue; + } + gdth_munmap(ha->brd); +#if LINUX_VERSION_CODE >= 0x2015C + pci_write_config_dword(pcistr->pdev, + PCI_BASE_ADDRESS_0, i); +#else + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_BASE_ADDRESS_0, i); +#endif + ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + dp6_ptr = (gdt6_dpram_str *)ha->brd; + gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); + if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) { + printk("GDT-PCI: Use free address at 0x%x\n", i); + found = TRUE; + break; + } + } + if (!found) { + printk("GDT-PCI: No free address found!\n"); + gdth_munmap(ha->brd); + return 0; + } + } memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u)); if (gdth_readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); @@ -890,8 +1268,51 @@ gdth_munmap(ha->brd); return 0; } + /* check and reset interface area */ dp6c_ptr = (gdt6c_dpram_str *)ha->brd; - /* reset interface area */ + gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) { + printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", + pcistr->dpmem); + found = FALSE; + for (i = 0xC8000; i < 0xE8000; i += 0x4000) { + gdth_munmap(ha->brd); + ha->brd = gdth_mmap(i, sizeof(ushort)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + if (gdth_readw(ha->brd) != 0xffff) { + TRACE2(("init_pci_plx() address 0x%x busy\n", i)); + continue; + } + gdth_munmap(ha->brd); +#if LINUX_VERSION_CODE >= 0x2015C + pci_write_config_dword(pcistr->pdev, + PCI_BASE_ADDRESS_2, i); +#else + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_BASE_ADDRESS_2, i); +#endif + ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) { + printk("GDT-PCI: Use free address at 0x%x\n", i); + found = TRUE; + break; + } + } + if (!found) { + printk("GDT-PCI: No free address found!\n"); + gdth_munmap(ha->brd); + return 0; + } + } memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u)); if (gdth_readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); @@ -961,12 +1382,53 @@ return 0; } + /* manipulate config. space to enable DPMEM, start RP controller */ +#if LINUX_VERSION_CODE >= 0x20363 + pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); + command |= 6; + pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); + if (pci_resource_start(pcistr->pdev, 8) == 1UL) + pci_resource_start(pcistr->pdev, 8) = 0UL; + i = 0xFEFF0001UL; + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i); + gdth_delay(1); + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, + pci_resource_start(pcistr->pdev, 8)); +#elif LINUX_VERSION_CODE >= 0x2015C + pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); + command |= 6; + pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); + if (pcistr->pdev->rom_address == 1UL) + pcistr->pdev->rom_address = 0UL; + i = 0xFEFF0001UL; + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i); + gdth_delay(1); + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, + pcistr->pdev->rom_address); +#else + pcibios_read_config_word(pcistr->bus, pcistr->device_fn, + PCI_COMMAND, &command); + command |= 6; + pcibios_write_config_word(pcistr->bus, pcistr->device_fn, + PCI_COMMAND, command); + pcibios_read_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, &rom_addr); + if (rom_addr == 1UL) + rom_addr = 0UL; + i = 0xFEFF0001UL; + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, i); + gdth_delay(1); + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, rom_addr); +#endif + /* check and reset interface area */ dp6m_ptr = (gdt6m_dpram_str *)ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) { - printk("GDT-PCI: Cannot access DPMEM at 0x%x (shadowed?)\n", - (int)pcistr->dpmem); + printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", + pcistr->dpmem); found = FALSE; for (i = 0xC8000; i < 0xE8000; i += 0x4000) { gdth_munmap(ha->brd); @@ -980,8 +1442,13 @@ continue; } gdth_munmap(ha->brd); +#if LINUX_VERSION_CODE >= 0x2015C pci_write_config_dword(pcistr->pdev, PCI_BASE_ADDRESS_0, i); +#else + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_BASE_ADDRESS_0, i); +#endif ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); @@ -1060,7 +1527,7 @@ /* controller protocol functions */ -static void __init gdth_enable_int(int hanum) +GDTH_INITFUNC(static void, gdth_enable_int(int hanum)) { gdth_ha_str *ha; ulong flags; @@ -1312,7 +1779,11 @@ gdth_from_wait = TRUE; do { +#if LINUX_VERSION_CODE >= 0x010346 gdth_interrupt((int)ha->irq,ha,NULL); +#else + gdth_interrupt((int)ha->irq,NULL); +#endif if (wait_hanum==hanum && wait_index==index) { answer_found = TRUE; break; @@ -1367,6 +1838,12 @@ cmd_ptr->u.raw.bus = (unchar)p2; cmd_ptr->u.raw.target = (unchar)p3; cmd_ptr->u.raw.lun = (unchar)(p3 >> 8); + } else if (service == SCREENSERVICE) { + if (opcode == GDT_REALTIME) { + *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1; + *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2; + *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3; + } } ha->cmd_len = sizeof(gdth_cmd_str); ha->cmd_offs_dpmem = 0; @@ -1389,19 +1866,22 @@ /* search for devices */ -static int __init gdth_search_drives(int hanum) +GDTH_INITFUNC(static int, gdth_search_drives(int hanum)) { register gdth_ha_str *ha; ushort cdev_cnt, i; - int drv_cyls, drv_hds, drv_secs; - ulong32 bus_no; - ulong32 drv_cnt, drv_no, j; + ulong32 bus_no, drv_cnt, drv_no, j; gdth_getch_str *chn; gdth_drlist_str *drl; gdth_iochan_str *ioc; gdth_raw_iochan_str *iocr; - gdth_arraylist_str *alst; - + gdth_arcdl_str *alst; + gdth_alist_str *alst2; +#ifdef GDTH_RTC + unchar rtc[12]; + ulong flags; +#endif + TRACE(("gdth_search_drives() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -1412,7 +1892,30 @@ return 0; } TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); - + +#ifdef GDTH_RTC + /* read realtime clock info, send to controller */ + /* 1. wait for the falling edge of update flag */ + spin_lock_irqsave(&rtc_lock, flags); + for (j = 0; j < 1000000; ++j) + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (j = 0; j < 1000000; ++j) + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + /* 2. read info */ + do { + for (j = 0; j < 12; ++j) + rtc[j] = CMOS_READ(j); + } while (rtc[0] != CMOS_READ(0)); + spin_lock_irqrestore(&rtc_lock, flags); + TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0], + *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8])); + /* 3. send to controller firmware */ + gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0], + *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]); +#endif + /* initialize cache service */ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) { printk("GDT: Initialization error cache service (code %d)\n", @@ -1421,19 +1924,7 @@ } TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); cdev_cnt = (ushort)ha->info; - - /* mount all cache devices */ - gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0); - TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n")); - - /* initialize cache service after mountall */ - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) { - printk("GDT: Initialization error cache service (code %d)\n", - ha->status); - return 0; - } - TRACE2(("gdth_search_drives() CACHES. init. after mountall\n")); - cdev_cnt = (ushort)ha->info; + ha->fw_vers = ha->service; /* detect number of buses - try new IOCTL */ iocr = (gdth_raw_iochan_str *)ha->pscratch; @@ -1493,7 +1984,8 @@ ha->more_proc = FALSE; if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO, INVALID_CHANNEL,sizeof(gdth_binfo_str))) { - memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, sizeof(gdth_binfo_str)); + memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, + sizeof(gdth_binfo_str)); if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES, INVALID_CHANNEL,sizeof(gdth_bfeat_str))) { TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n")); @@ -1562,22 +2054,37 @@ INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { for (j = 0; j < drv_cnt; ++j) { drv_no = ((ulong32 *)ha->pscratch)[j]; - if (drv_no < MAX_HDRIVES) { + if (drv_no < MAX_LDRIVES) { ha->hdr[drv_no].is_logdrv = TRUE; TRACE2(("Drive %d is log. drive\n",drv_no)); } } } + alst = (gdth_arcdl_str *)ha->pscratch; + alst->entries_avail = MAX_LDRIVES; + alst->first_entry = 0; + alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]); if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, - ARRAY_DRV_LIST | LA_CTRL_PATTERN, - 0, 35 * sizeof(gdth_arraylist_str))) { + ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, + INVALID_CHANNEL, sizeof(gdth_arcdl_str) + + (alst->entries_avail-1) * sizeof(gdth_alist_str))) { + for (j = 0; j < alst->entries_init; ++j) { + ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd; + ha->hdr[j].is_master = alst->list[j].is_master; + ha->hdr[j].is_parity = alst->list[j].is_parity; + ha->hdr[j].is_hotfix = alst->list[j].is_hotfix; + ha->hdr[j].master_no = alst->list[j].cd_handle; + } + } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + ARRAY_DRV_LIST | LA_CTRL_PATTERN, + 0, 35 * sizeof(gdth_alist_str))) { for (j = 0; j < 35; ++j) { - alst = &((gdth_arraylist_str *)ha->pscratch)[j]; - ha->hdr[j].is_arraydrv = alst->is_arrayd; - ha->hdr[j].is_master = alst->is_master; - ha->hdr[j].is_parity = alst->is_parity; - ha->hdr[j].is_hotfix = alst->is_hotfix; - ha->hdr[j].master_no = alst->cd_handle; + alst2 = &((gdth_alist_str *)ha->pscratch)[j]; + ha->hdr[j].is_arraydrv = alst2->is_arrayd; + ha->hdr[j].is_master = alst2->is_master; + ha->hdr[j].is_parity = alst2->is_parity; + ha->hdr[j].is_hotfix = alst2->is_hotfix; + ha->hdr[j].master_no = alst2->cd_handle; } } } @@ -1592,7 +2099,6 @@ TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); /* set/get features raw service (scatter/gather) */ - ha->raw_feat = 0; if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER, 0,0)) { TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n")); @@ -1636,44 +2142,67 @@ } } - /* scanning for cache devices */ - for (i=0; ibus_cnt,i)); - - ha->hdr[i].present = TRUE; - ha->hdr[i].size = ha->info; - - /* evaluate mapping (sectors per head, heads per cylinder) */ - ha->hdr[i].size &= ~SECS32; - if (ha->info2 == 0) { - gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs); - } else { - drv_hds = ha->info2 & 0xff; - drv_secs = (ha->info2 >> 8) & 0xff; - drv_cyls = ha->hdr[i].size /drv_hds/drv_secs; - } - ha->hdr[i].heads = (unchar)drv_hds; - ha->hdr[i].secs = (unchar)drv_secs; - /* round size */ - ha->hdr[i].size = drv_cyls * drv_hds * drv_secs; - TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", - i,ha->hdr[i].size,drv_hds,drv_secs)); + /* scanning for host drives */ + for (i = 0; i < cdev_cnt; ++i) + gdth_analyse_hdrive(hanum,i); + + TRACE(("gdth_search_drives() OK\n")); + return 1; +} + +static int gdth_analyse_hdrive(int hanum,ushort hdrive) +{ + register gdth_ha_str *ha; + int drv_cyls, drv_hds, drv_secs; + + TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive)); + if (hdrive >= MAX_HDRIVES) + return 0; + ha = HADATA(gdth_ctr_tab[hanum]); + + if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) + return 0; + ha->hdr[hdrive].present = TRUE; + ha->hdr[hdrive].size = ha->info; + + /* evaluate mapping (sectors per head, heads per cylinder) */ + ha->hdr[hdrive].size &= ~SECS32; + if (ha->info2 == 0) { + gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs); + } else { + drv_hds = ha->info2 & 0xff; + drv_secs = (ha->info2 >> 8) & 0xff; + drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs; + } + ha->hdr[hdrive].heads = (unchar)drv_hds; + ha->hdr[hdrive].secs = (unchar)drv_secs; + /* round size */ + ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; + TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", + hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs)); - /* get informations about device */ - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i, - 0,0)) { - TRACE(("gdth_search_dr() cache drive %d devtype %d\n", - i,ha->info)); - ha->hdr[i].devtype = (ushort)ha->info; - } - } + /* get informations about device */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) { + TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", + hdrive,ha->info)); + ha->hdr[hdrive].devtype = (ushort)ha->info; + } + + /* cluster info */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) { + TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", + hdrive,ha->info)); + if (!shared_access) + ha->hdr[hdrive].cluster_type = (unchar)ha->info; + } + + /* R/W attributes */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) { + TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", + hdrive,ha->info)); + ha->hdr[hdrive].rw_attribs = (unchar)ha->info; } - TRACE(("gdth_search_drives() OK\n")); return 1; } @@ -1693,8 +2222,9 @@ GDTH_LOCK_HA(ha, flags); scp->SCp.this_residual = (int)priority; - b = scp->channel; + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; t = scp->target; +#if LINUX_VERSION_CODE >= 0x010300 if (priority >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { @@ -1702,6 +2232,7 @@ scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); } } +#endif if (ha->req_first==NULL) { ha->req_first = scp; /* queue was empty */ @@ -1752,7 +2283,7 @@ for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) { if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr) pscp = (Scsi_Cmnd *)pscp->SCp.ptr; - b = nscp->channel; + b = virt_ctr ? NUMDATA(nscp->host)->busnum : nscp->channel; t = nscp->target; if (nscp->SCp.this_residual >= DEFAULT_PRI) { if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || @@ -1773,10 +2304,12 @@ firsttime = FALSE; } - if (nscp->done != gdth_scsi_done) +#if LINUX_VERSION_CODE >= 0x010300 + if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) +#endif { if (nscp->SCp.phase == -1) { - nscp->SCp.phase = SCSIRAWSERVICE; /* default: raw svc. */ + nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */ if (nscp->cmnd[0] == TEST_UNIT_READY) { TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", b, t, nscp->lun)); @@ -1789,8 +2322,9 @@ } else if ((ha->scan_mode & 0x0f) == 1) { if (b == 0 && ((t == 0 && nscp->lun == 1) || (t == 1 && nscp->lun == 0))) { - nscp->SCp.Status = GDT_SCAN_START; - nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8); + nscp->SCp.sent_command = GDT_SCAN_START; + nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) + | SCSIRAWSERVICE; ha->scan_mode = 0x12; TRACE2(("Scan mode: 0x%x (SCAN_START)\n", ha->scan_mode)); @@ -1800,29 +2334,55 @@ } } else if (ha->scan_mode == 0x12) { if (b == ha->bus_cnt && t == ha->tid_cnt-1) { - nscp->SCp.Status = GDT_SCAN_END; + nscp->SCp.phase = SCSIRAWSERVICE; + nscp->SCp.sent_command = GDT_SCAN_END; ha->scan_mode &= 0x10; TRACE2(("Scan mode: 0x%x (SCAN_END)\n", ha->scan_mode)); } } } + if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY && + nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE && + (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) { + /* always GDT_CLUST_INFO! */ + nscp->SCp.sent_command = GDT_CLUST_INFO; + } } } - if (nscp->SCp.Status != -1) { - if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { + if (nscp->SCp.sent_command != -1) { + if ((nscp->SCp.phase & 0xff) == CACHESERVICE) { + if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + this_cmd = FALSE; + next_cmd = FALSE; + } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) this_cmd = FALSE; next_cmd = FALSE; + } else { + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = NOT_READY; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } } } else - if (nscp->done == gdth_scsi_done) { +#if LINUX_VERSION_CODE >= 0x010300 + if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) { if (!(cmd_index=gdth_special_cmd(hanum,nscp))) this_cmd = FALSE; next_cmd = FALSE; } else +#endif if (b != ha->virt_bus) { if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) @@ -1833,10 +2393,14 @@ TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", nscp->cmnd[0], b, t, nscp->lun)); nscp->result = DID_BAD_TARGET << 16; - GDTH_UNLOCK_HA(ha,flags); - /* io_request_lock already active ! */ - nscp->scsi_done(nscp); - GDTH_LOCK_HA(ha,flags); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } } else { switch (nscp->cmnd[0]) { case TEST_UNIT_READY: @@ -1849,7 +2413,24 @@ TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], nscp->cmnd[4],nscp->cmnd[5])); - if (gdth_internal_cache_cmd(hanum,nscp)) { + if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) { + /* return UNIT_ATTENTION */ + TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", + nscp->cmnd[0], t)); + ha->hdr[t].media_changed = FALSE; + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = UNIT_ATTENTION; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } + } else if (gdth_internal_cache_cmd(hanum,nscp)) { GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); @@ -1864,6 +2445,7 @@ if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) { TRACE(("Prevent r. nonremov. drive->do nothing\n")); nscp->result = DID_OK << 16; + nscp->sense_buffer[0] = 0; if (!nscp->SCp.have_data_in) nscp->SCp.have_data_in++; else { @@ -1881,11 +2463,36 @@ } break; + case RESERVE: + case RELEASE: + TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ? + "RESERVE" : "RELEASE")); + if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + this_cmd = FALSE; + break; + case READ_6: case WRITE_6: case READ_10: case WRITE_10: - if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + if (ha->hdr[t].media_changed) { + /* return UNIT_ATTENTION */ + TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", + nscp->cmnd[0], t)); + ha->hdr[t].media_changed = FALSE; + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = UNIT_ATTENTION; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } + } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) this_cmd = FALSE; break; @@ -1985,7 +2592,10 @@ inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK; /* you can here set all disks to removable, if you want to do a flush using the ALLOW_MEDIUM_REMOVAL command */ - inq.modif_rmb = ha->hdr[t].devtype&1 ? 0x80:0x00; + inq.modif_rmb = 0x00; + if ((ha->hdr[t].devtype & 1) || + (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) + inq.modif_rmb = 0x80; inq.version = 2; inq.resp_aenc = 2; inq.add_length= 32; @@ -2028,7 +2638,9 @@ TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0])); break; } + scp->result = DID_OK << 16; + scp->sense_buffer[0] = 0; if (!scp->SCp.have_data_in) scp->SCp.have_data_in++; @@ -2043,8 +2655,9 @@ register gdth_ha_str *ha; register gdth_cmd_str *cmdp; struct scatterlist *sl; - ushort i; - int cmd_index; + ushort i, cnt; + ulong32 no; + int cmd_index, read_write; ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; @@ -2066,37 +2679,46 @@ gdth_set_sema0(hanum); /* fill command */ - if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) { + read_write = FALSE; + if (scp->SCp.sent_command != -1) + cmdp->OpCode = scp->SCp.sent_command; /* special cache cmd. */ + else if (scp->cmnd[0] == RESERVE) + cmdp->OpCode = GDT_RESERVE_DRV; + else if (scp->cmnd[0] == RELEASE) + cmdp->OpCode = GDT_RELEASE_DRV; + else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { if (scp->cmnd[4] & 1) /* prevent ? */ - cmdp->OpCode = GDT_MOUNT; + cmdp->OpCode = GDT_MOUNT; else if (scp->cmnd[3] & 1) /* removable drive ? */ - cmdp->OpCode = GDT_UNMOUNT; + cmdp->OpCode = GDT_UNMOUNT; + else + cmdp->OpCode = GDT_FLUSH; + } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) { + read_write = TRUE; + if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && + (ha->cache_feat & GDT_WR_THROUGH))) + cmdp->OpCode = GDT_WRITE_THR; else - cmdp->OpCode = GDT_FLUSH; + cmdp->OpCode = GDT_WRITE; } else { - if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) { - if (gdth_write_through) - cmdp->OpCode = GDT_WRITE_THR; - else - cmdp->OpCode = GDT_WRITE; - } else { - cmdp->OpCode = GDT_READ; - } + read_write = TRUE; + cmdp->OpCode = GDT_READ; } + + cmdp->BoardNode = LOCALBOARD; + cmdp->u.cache.DeviceNo = hdrive; + cmdp->u.cache.BlockNo = 1; + cmdp->u.cache.sg_canz = 0; - cmdp->BoardNode = LOCALBOARD; - cmdp->u.cache.DeviceNo = hdrive; - - if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) { - cmdp->u.cache.BlockNo = 1; - cmdp->u.cache.sg_canz = 0; - } else { + if (read_write) { if (scp->cmd_len != 6) { - cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]); - cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]); + memcpy(&no, &scp->cmnd[2], sizeof(ulong32)); + cmdp->u.cache.BlockNo = ntohl(no); + memcpy(&cnt, &scp->cmnd[7], sizeof(ushort)); + cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt); } else { - cmdp->u.cache.BlockNo = - ntohl(*(ulong32*)&scp->cmnd[0]) & 0x001fffffUL; + memcpy(&no, &scp->cmnd[0], sizeof(ulong32)); + cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL; cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; } @@ -2189,8 +2811,8 @@ gdth_set_sema0(hanum); /* fill command */ - if (scp->SCp.Status != -1) { - cmdp->OpCode = scp->SCp.Status; /* special raw cmd. */ + if (scp->SCp.sent_command != -1) { + cmdp->OpCode = scp->SCp.sent_command; /* special raw cmd. */ cmdp->BoardNode = LOCALBOARD; cmdp->u.raw.direction = (scp->SCp.phase >> 8); TRACE2(("special raw cmd 0x%x param 0x%x\n", @@ -2209,12 +2831,12 @@ cmdp->u.raw.lun = l; cmdp->u.raw.bus = b; cmdp->u.raw.priority = 0; - cmdp->u.raw.link_p = NULL; + cmdp->u.raw.link_p = 0; cmdp->u.raw.sdlen = scp->request_bufflen; cmdp->u.raw.sense_len = 16; cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer); cmdp->u.raw.direction = - gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN; + gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; memcpy(cmdp->u.raw.cmd,scp->cmnd,12); if (scp->use_sg) { @@ -2346,8 +2968,12 @@ if (ebuffer[elastidx].event_source == source && ebuffer[elastidx].event_idx == idx && - !memcmp((char *)&ebuffer[elastidx].event_data.eu, - (char *)&evt->eu, evt->size)) { + ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 && + !memcmp((char *)&ebuffer[elastidx].event_data.eu, + (char *)&evt->eu, evt->size)) || + (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 && + !strcmp((char *)&ebuffer[elastidx].event_data.event_string, + (char *)&evt->event_string)))) { e = &ebuffer[elastidx]; do_gettimeofday(&tv); e->last_stamp = tv.tv_sec; @@ -2370,6 +2996,7 @@ e->first_stamp = e->last_stamp = tv.tv_sec; e->same_count = 1; e->event_data = *evt; + e->application = 0; } return e; } @@ -2449,18 +3076,20 @@ /* SCSI interface functions */ +#if LINUX_VERSION_CODE >= 0x010346 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs) +#else +static void gdth_interrupt(int irq,struct pt_regs *regs) +#endif { register gdth_ha_str *ha; gdt6m_dpram_str *dp6m_ptr; gdt6_dpram_str *dp6_ptr; gdt2_dpram_str *dp2_ptr; Scsi_Cmnd *scp; - int hanum, rval; + int hanum, rval, i; unchar IStatus; - ushort CmdStatus, Service = 0; - ulong32 InfoBytes, InfoBytes2 = 0; - gdth_evt_data dvr; + ushort Service; ulong flags = 0; TRACE(("gdth_interrupt() IRQ %d\n",irq)); @@ -2478,9 +3107,7 @@ /* search controller */ if ((hanum = gdth_get_status(&IStatus,irq)) == -1) { - /* - TRACE2(("gdth_interrupt(): Spurious interrupt received\n")); - */ + /* spurious interrupt */ if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); return; @@ -2494,34 +3121,28 @@ if (ha->type == GDT_EISA) { if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - CmdStatus = inw(ha->bmic + MAILBOXREG+8); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus)); - if (IStatus == ASYNCINDEX) { /* async. event ? */ - Service = inw(ha->bmic + MAILBOXREG+10); - InfoBytes2 = inl(ha->bmic + MAILBOXREG+4); - } + ha->status = inw(ha->bmic + MAILBOXREG+8); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ - CmdStatus = S_OK; - InfoBytes = inl(ha->bmic + MAILBOXREG+12); - if (gdth_polling) /* init. -> more info */ - InfoBytes2 = inl(ha->bmic + MAILBOXREG+4); + ha->status = S_OK; + ha->info = inl(ha->bmic + MAILBOXREG+12); + ha->service = inw(ha->bmic + MAILBOXREG+10); + ha->info2 = inl(ha->bmic + MAILBOXREG+4); + outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ } else if (ha->type == GDT_ISA) { dp2_ptr = (gdt2_dpram_str *)ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - CmdStatus = gdth_readw(&dp2_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus)); - if (IStatus == ASYNCINDEX) { /* async. event ? */ - Service = gdth_readw(&dp2_ptr->u.ic.Service); - InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); - } + ha->status = gdth_readw(&dp2_ptr->u.ic.Status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ - CmdStatus = S_OK; - InfoBytes = gdth_readl(&dp2_ptr->u.ic.Info[0]); - if (gdth_polling) /* init. -> more info */ - InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); + ha->status = S_OK; + ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]); + ha->service = gdth_readw(&dp2_ptr->u.ic.Service); + ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]); + gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index); /* reset command index */ gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ @@ -2529,52 +3150,56 @@ dp6_ptr = (gdt6_dpram_str *)ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - CmdStatus = gdth_readw(&dp6_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus)); - if (IStatus == ASYNCINDEX) { /* async. event ? */ - Service = gdth_readw(&dp6_ptr->u.ic.Service); - InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); - } + ha->status = gdth_readw(&dp6_ptr->u.ic.Status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ - CmdStatus = S_OK; - InfoBytes = gdth_readl(&dp6_ptr->u.ic.Info[0]); - if (gdth_polling) /* init. -> more info */ - InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); + ha->status = S_OK; + ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]); + ha->service = gdth_readw(&dp6_ptr->u.ic.Service); + ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]); + gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index); /* reset command index */ gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ } else if (ha->type == GDT_PCINEW) { if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - CmdStatus = inw(PTR2USHORT(&ha->plx->status)); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus)); - if (IStatus == ASYNCINDEX) { /* async. event ? */ - Service = inw(PTR2USHORT(&ha->plx->service)); - InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1])); - } + ha->status = inw(PTR2USHORT(&ha->plx->status)); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else - CmdStatus = S_OK; + ha->status = S_OK; + ha->info = inl(PTR2USHORT(&ha->plx->info[0])); + ha->service = inw(PTR2USHORT(&ha->plx->service)); + ha->info2 = inl(PTR2USHORT(&ha->plx->info[1])); - InfoBytes = inl(PTR2USHORT(&ha->plx->info[0])); - if (gdth_polling) /* init. -> more info */ - InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1])); outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); } else if (ha->type == GDT_PCIMPR) { dp6m_ptr = (gdt6m_dpram_str *)ha->brd; if (IStatus & 0x80) { /* error flag */ IStatus &= ~0x80; - CmdStatus = gdth_readw(&dp6m_ptr->i960r.status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus)); - if (IStatus == ASYNCINDEX) { /* async. event ? */ - Service = gdth_readw(&dp6m_ptr->i960r.service); - InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]); - } + ha->status = gdth_readw(&dp6m_ptr->i960r.status); + TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); } else /* no error */ - CmdStatus = S_OK; - InfoBytes = gdth_readl(&dp6m_ptr->i960r.info[0]); - if (gdth_polling) /* init. -> more info */ - InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]); + ha->status = S_OK; + ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]); + ha->service = gdth_readw(&dp6m_ptr->i960r.service); + ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]); + + /* event string */ + if (IStatus == ASYNCINDEX) { + if (ha->service != SCREENSERVICE && + (ha->fw_vers & 0xff) >= 0x1a) { + ha->dvr.severity = + gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity); + for (i = 0; i < 256; ++i) { + ha->dvr.event_string[i] = gdth_readb + (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]); + if (ha->dvr.event_string[i] == 0) + break; + } + } + } gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg); gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg); } else { @@ -2585,10 +3210,7 @@ } TRACE(("gdth_interrupt() index %d stat %d info %d\n", - IStatus,CmdStatus,InfoBytes)); - ha->status = CmdStatus; - ha->info = InfoBytes; - ha->info2 = InfoBytes2; + IStatus,ha->status,ha->info)); if (gdth_from_wait) { wait_hanum = hanum; @@ -2597,7 +3219,7 @@ if (IStatus == ASYNCINDEX) { TRACE2(("gdth_interrupt() async. event\n")); - gdth_async_event(hanum,Service); + gdth_async_event(hanum); if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); gdth_next(hanum); @@ -2606,9 +3228,9 @@ if (IStatus == SPEZINDEX) { TRACE2(("Service unknown or not initialized !\n")); - dvr.size = sizeof(dvr.eu.driver); - dvr.eu.driver.ionode = hanum; - gdth_store_event(ha, ES_DRIVER, 4, &dvr); + ha->dvr.size = sizeof(ha->dvr.eu.driver); + ha->dvr.eu.driver.ionode = hanum; + gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); return; @@ -2618,10 +3240,10 @@ ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND; if (scp == UNUSED_CMND) { TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); - dvr.size = sizeof(dvr.eu.driver); - dvr.eu.driver.ionode = hanum; - dvr.eu.driver.index = IStatus; - gdth_store_event(ha, ES_DRIVER, 1, &dvr); + ha->dvr.size = sizeof(ha->dvr.eu.driver); + ha->dvr.eu.driver.ionode = hanum; + ha->dvr.eu.driver.index = IStatus; + gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); if (!gdth_polling) GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags); return; @@ -2652,9 +3274,7 @@ register gdth_ha_str *ha; gdth_msg_str *msg; gdth_cmd_str *cmdp; - char c='\r'; - ushort i; - gdth_evt_data dvr; + unchar b; ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; @@ -2682,11 +3302,11 @@ cmdp->OpCode = GDT_READ; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; - cmdp->u.screen.msg_handle= msg->msg_handle; - cmdp->u.screen.msg_addr = virt_to_bus(msg); + cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; + cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); ha->scratch_busy = TRUE; ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong32); ha->cmd_cnt = 0; gdth_copy_command(hanum); @@ -2695,22 +3315,19 @@ } if (msg->msg_answer && msg->msg_alen) { - for (i=0; imsg_alen && imsg_text[i] = c; - } - msg->msg_alen -= i; - if (c!='\r' && msg->msg_alen!=0) { - msg->msg_answer = 1; - msg->msg_ext = 1; + /* default answers (getchar() not possible) */ + if (msg->msg_alen == 1) { + msg->msg_alen = 0; + msg->msg_len = 1; + msg->msg_text[0] = 0; } else { - msg->msg_ext = 0; - msg->msg_answer = 0; + msg->msg_alen -= 2; + msg->msg_len = 2; + msg->msg_text[0] = 1; + msg->msg_text[1] = 0; } - msg->msg_len = i; + msg->msg_ext = 0; + msg->msg_answer = 0; while (gdth_test_busy(hanum)) gdth_delay(0); cmdp->Service = SCREENSERVICE; @@ -2720,11 +3337,11 @@ cmdp->OpCode = GDT_WRITE; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; - cmdp->u.screen.msg_handle= msg->msg_handle; - cmdp->u.screen.msg_addr = virt_to_bus(msg); + cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; + cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); ha->scratch_busy = TRUE; ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong32); ha->cmd_cnt = 0; gdth_copy_command(hanum); @@ -2734,54 +3351,110 @@ printk("\n"); } else { - if (scp->SCp.Status == -1 && scp->channel != ha->virt_bus) { - ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[scp->target]--; + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; + if (scp->SCp.sent_command == -1 && b != ha->virt_bus) { + ha->raw[BUS_L2P(ha,b)].io_cnt[scp->target]--; } /* cache or raw service */ if (ha->status == S_OK) { - scp->SCp.Message = S_OK; - if (scp->SCp.Status != -1) { + scp->SCp.Status = S_OK; + scp->SCp.Message = ha->info; + if (scp->SCp.sent_command != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", - scp->SCp.Status)); - scp->SCp.Status = -1; + scp->SCp.sent_command)); + /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ + if (scp->SCp.sent_command == GDT_CLUST_INFO) { + ha->hdr[scp->target].cluster_type = (unchar)ha->info; + if (!(ha->hdr[scp->target].cluster_type & + CLUSTER_MOUNTED)) { + /* NOT MOUNTED -> MOUNT */ + scp->SCp.sent_command = GDT_MOUNT; + if (ha->hdr[scp->target].cluster_type & + CLUSTER_RESERVED) { + /* cluster drive RESERVED (on the other node) */ + scp->SCp.phase = -2; /* reservation conflict */ + } + } else { + scp->SCp.sent_command = -1; + } + } else { + if (scp->SCp.sent_command == GDT_MOUNT) { + ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED; + ha->hdr[scp->target].media_changed = TRUE; + } else if (scp->SCp.sent_command == GDT_UNMOUNT) { + ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED; + ha->hdr[scp->target].media_changed = TRUE; + } + scp->SCp.sent_command = -1; + } + /* retry */ scp->SCp.this_residual = HIGH_PRI; return 2; + } else { + /* RESERVE/RELEASE ? */ + if (scp->cmnd[0] == RESERVE) { + ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED; + } else if (scp->cmnd[0] == RELEASE) { + ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + } + scp->result = DID_OK << 16; + scp->sense_buffer[0] = 0; } - scp->result = DID_OK << 16; } else if (ha->status == S_BSY) { TRACE2(("Controller busy -> retry !\n")); - scp->SCp.Message = S_BSY; + scp->SCp.Status = S_BSY; + scp->SCp.Message = ha->info; + if (scp->SCp.sent_command == GDT_MOUNT) + scp->SCp.sent_command = GDT_CLUST_INFO; + /* retry */ return 2; } else { - scp->SCp.Message = (int)((ha->info<<16)|ha->status); - if (scp->SCp.Status != -1) { + scp->SCp.Status = ha->status; + scp->SCp.Message = ha->info; + + if (scp->SCp.sent_command != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", - scp->SCp.Status, ha->status)); - scp->SCp.Status = -1; - scp->SCp.this_residual = HIGH_PRI; - return 2; - } - if (service == CACHESERVICE) { + scp->SCp.sent_command, ha->status)); + if (scp->SCp.sent_command == GDT_SCAN_START || + scp->SCp.sent_command == GDT_SCAN_END) { + scp->SCp.sent_command = -1; + /* retry */ + scp->SCp.this_residual = HIGH_PRI; + return 2; + } memset((char*)scp->sense_buffer,0,16); scp->sense_buffer[0] = 0x70; scp->sense_buffer[2] = NOT_READY; scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - + } else if (service == CACHESERVICE) { + if (ha->status == S_CACHE_UNKNOWN && + (ha->hdr[scp->target].cluster_type & + CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) { + /* bus reset -> force GDT_CLUST_INFO */ + ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + } + memset((char*)scp->sense_buffer,0,16); + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = NOT_READY; + scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); +#if LINUX_VERSION_CODE >= 0x010300 if (scp->done != gdth_scsi_done) +#endif { - dvr.size = sizeof(dvr.eu.sync); - dvr.eu.sync.ionode = hanum; - dvr.eu.sync.service = service; - dvr.eu.sync.status = ha->status; - dvr.eu.sync.info = ha->info; - dvr.eu.sync.hostdrive = scp->target; + ha->dvr.size = sizeof(ha->dvr.eu.sync); + ha->dvr.eu.sync.ionode = hanum; + ha->dvr.eu.sync.service = service; + ha->dvr.eu.sync.status = ha->status; + ha->dvr.eu.sync.info = ha->info; + ha->dvr.eu.sync.hostdrive = scp->target; if (ha->status >= 0x8000) - gdth_store_event(ha, ES_SYNC, 0, &dvr); + gdth_store_event(ha, ES_SYNC, 0, &ha->dvr); else - gdth_store_event(ha, ES_SYNC, service, &dvr); + gdth_store_event(ha, ES_SYNC, service, &ha->dvr); } } else { - if (ha->status!=S_RAW_SCSI || ha->info>=0x100) { + /* sense buffer filled from controller firmware (DMA) */ + if (ha->status != S_RAW_SCSI || ha->info >= 0x100) { scp->result = DID_BAD_TARGET << 16; } else { scp->result = (DID_OK << 16) | ha->info; @@ -2944,12 +3617,17 @@ "GDT HA %u, Uncorrectable DRAM error detected with ECC", /*72*/ "\011\000\002\012\001\013\001\014\001" "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block", +/*73*/ "\005\000\002\006\002" + "GDT HA %u, Host drive %u resetted locally", +/*74*/ "\005\000\002\006\002" + "GDT HA %u, Host drive %u resetted remotely", +/*75*/ "\003\000\002" + "GDT HA %u, async. status 75 unknown", }; -static int gdth_async_event(int hanum,int service) +static int gdth_async_event(int hanum) { - gdth_evt_data dvr; gdth_ha_str *ha; gdth_msg_str *msg; gdth_cmd_str *cmdp; @@ -2959,9 +3637,9 @@ cmdp= ha->pccb; msg = (gdth_msg_str *)ha->pscratch; TRACE2(("gdth_async_event() ha %d serv %d\n", - hanum,service)); + hanum,ha->service)); - if (service == SCREENSERVICE) { + if (ha->service == SCREENSERVICE) { if (ha->status == MSG_REQUEST) { while (gdth_test_busy(hanum)) gdth_delay(0); @@ -2972,11 +3650,11 @@ cmdp->OpCode = GDT_READ; cmdp->BoardNode = LOCALBOARD; cmdp->u.screen.reserved = 0; - cmdp->u.screen.msg_handle= MSG_INV_HANDLE; - cmdp->u.screen.msg_addr = virt_to_bus(msg); + cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE; + cmdp->u.screen.su.msg.msg_addr = virt_to_bus(msg); ha->scratch_busy = TRUE; ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) + ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) + sizeof(ulong32); ha->cmd_cnt = 0; gdth_copy_command(hanum); @@ -2991,14 +3669,29 @@ } } else { - dvr.size = sizeof(dvr.eu.async); - dvr.eu.async.ionode = hanum; - dvr.eu.async.service = service; - dvr.eu.async.status = ha->status; - dvr.eu.async.info = ha->info; - *(ulong32 *)dvr.eu.async.scsi_coord = ha->info2; - gdth_store_event(ha, ES_ASYNC, service, &dvr); - gdth_log_event( &dvr, NULL ); + if (ha->type == GDT_PCIMPR && + (ha->fw_vers & 0xff) >= 0x1a) { + ha->dvr.size = 0; + ha->dvr.eu.async.ionode = hanum; + ha->dvr.eu.async.status = ha->status; + /* severity and event_string already set! */ + } else { + ha->dvr.size = sizeof(ha->dvr.eu.async); + ha->dvr.eu.async.ionode = hanum; + ha->dvr.eu.async.service = ha->service; + ha->dvr.eu.async.status = ha->status; + ha->dvr.eu.async.info = ha->info; + *(ulong32 *)ha->dvr.eu.async.scsi_coord = ha->info2; + } + gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr ); + gdth_log_event( &ha->dvr, NULL ); + + /* new host drive from expand? */ + if (ha->service == CACHESERVICE && ha->status == 56) { + TRACE2(("gdth_async_event(): new host drive %d created\n", + (ushort)ha->info)); + gdth_analyse_hdrive(hanum, (ushort)ha->info); + } } return 1; } @@ -3010,7 +3703,14 @@ int i,j; TRACE2(("gdth_log_event()\n")); - if (dvr->eu.async.service == CACHESERVICE && + if (dvr->size == 0) { + if (buffer == NULL) { + printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); + } else { + sprintf(buffer,"Adapter %d: %s\n", + dvr->eu.async.ionode,dvr->event_string); + } + } else if (dvr->eu.async.service == CACHESERVICE && INDEX_OK(dvr->eu.async.status, async_cache_tab)) { TRACE2(("GDT: Async. event cache service, event no.: %d\n", dvr->eu.async.status)); @@ -3081,8 +3781,96 @@ } #endif +GDTH_INITFUNC(void, internal_setup(char *str,int *ints)) +{ + int i, argc; + char *cur_str, *argv; -int __init gdth_detect(Scsi_Host_Template *shtp) + TRACE2(("internal_setup() str %s ints[0] %d\n", + str ? str:"NULL", ints ? ints[0]:0)); + + /* read irq[] from ints[] */ + if (ints) { + argc = ints[0]; + if (argc > 0) { + if (argc > MAXHA) + argc = MAXHA; + for (i = 0; i < argc; ++i) + irq[i] = ints[i+1]; + } + } + + /* analyse string */ + argv = str; + while (argv && (cur_str = strchr(argv, ':'))) { + int val = 0, c = *++cur_str; + + if (c == 'n' || c == 'N') + val = 0; + else if (c == 'y' || c == 'Y') + val = 1; + else + val = (int)simple_strtoul(cur_str, NULL, 0); + + if (!strncmp(argv, "disable:", 8)) + disable = val; + else if (!strncmp(argv, "reserve_mode:", 13)) + reserve_mode = val; + else if (!strncmp(argv, "reverse_scan:", 13)) + reverse_scan = val; + else if (!strncmp(argv, "hdr_channel:", 12)) + hdr_channel = val; + else if (!strncmp(argv, "max_ids:", 8)) + max_ids = val; + else if (!strncmp(argv, "rescan:", 7)) + rescan = val; + else if (!strncmp(argv, "virt_ctr:", 9)) + virt_ctr = val; + else if (!strncmp(argv, "shared_access:", 14)) + shared_access = val; + else if (!strncmp(argv, "reserve_list:", 13)) { + reserve_list[0] = val; + for (i = 1; i < MAX_RES_ARGS; i++) { + cur_str = strchr(cur_str, ','); + if (!cur_str) + break; + if (!isdigit((int)*++cur_str)) { + --cur_str; + break; + } + reserve_list[i] = + (int)simple_strtoul(cur_str, NULL, 0); + } + if (!cur_str) + break; + argv = ++cur_str; + continue; + } + + if ((argv = strchr(argv, ','))) + ++argv; + } +} + +GDTH_INITFUNC(int, option_setup(char *str)) +{ + int ints[MAXHA]; + char *cur = str; + int i = 1; + + TRACE2(("option_setup() str %s\n", str ? str:"NULL")); + + while (cur && isdigit(*cur) && i <= MAXHA) { + ints[i++] = simple_strtoul(cur, NULL, 0); + if ((cur = strchr(cur, ',')) != NULL) cur++; + } + + ints[0] = i - 1; + internal_setup(cur, ints); + return 1; +} + +GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp)) { struct Scsi_Host *shp; gdth_ha_str *ha; @@ -3125,18 +3913,23 @@ break; if (gdth_search_isa(isa_bios)) { /* controller found */ shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; ha = HADATA(shp); if (!gdth_init_isa(isa_bios,ha)) { scsi_unregister(shp); continue; } +#ifdef __ia64__ + break; +#else /* controller found and initialized */ printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", isa_bios,ha->irq,ha->drq); +#if LINUX_VERSION_CODE >= 0x010346 if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) +#else + if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) +#endif { printk("GDT-ISA: Unable to allocate IRQ\n"); scsi_unregister(shp); @@ -3144,7 +3937,11 @@ } if (request_dma(ha->drq,"gdth")) { printk("GDT-ISA: Unable to allocate DMA channel\n"); +#if LINUX_VERSION_CODE >= 0x010346 free_irq(ha->irq,NULL); +#else + free_irq(ha->irq); +#endif scsi_unregister(shp); continue; } @@ -3161,7 +3958,12 @@ NUMDATA(shp)->busnum= 0; ha->pccb = CMDDATA(shp); - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD); +#if LINUX_VERSION_CODE >= 0x020322 + ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, + GDTH_SCRATCH_ORD); +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); +#endif ha->scratch_busy = FALSE; ha->req_first = NULL; ha->tid_cnt = MAX_HDRIVES; @@ -3176,8 +3978,16 @@ --gdth_ctr_count; --gdth_ctr_vcount; if (ha->pscratch != NULL) +#if LINUX_VERSION_CODE >= 0x020322 free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); +#else + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); +#endif +#if LINUX_VERSION_CODE >= 0x010346 free_irq(ha->irq,NULL); +#else + free_irq(ha->irq); +#endif scsi_unregister(shp); continue; } @@ -3185,11 +3995,29 @@ hdr_channel = ha->bus_cnt; ha->virt_bus = hdr_channel; +#if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) +#endif + { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 1; + shp->irq = ha->irq; + shp->dma_channel = ha->drq; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; + } + } + GDTH_INIT_LOCK_HA(ha); gdth_enable_int(hanum); +#endif /* !__ia64__ */ } } @@ -3199,8 +4027,6 @@ break; if (gdth_search_eisa(eisa_slot)) { /* controller found */ shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; ha = HADATA(shp); if (!gdth_init_eisa(eisa_slot,ha)) { scsi_unregister(shp); @@ -3210,7 +4036,11 @@ printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", eisa_slot>>12,ha->irq); +#if LINUX_VERSION_CODE >= 0x010346 if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) +#else + if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) +#endif { printk("GDT-EISA: Unable to allocate IRQ\n"); scsi_unregister(shp); @@ -3229,7 +4059,12 @@ NUMDATA(shp)->hanum)); ha->pccb = CMDDATA(shp); - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD); +#if LINUX_VERSION_CODE >= 0x020322 + ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, + GDTH_SCRATCH_ORD); +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); +#endif ha->scratch_busy = FALSE; ha->req_first = NULL; ha->tid_cnt = MAX_HDRIVES; @@ -3244,8 +4079,16 @@ --gdth_ctr_count; --gdth_ctr_vcount; if (ha->pscratch != NULL) +#if LINUX_VERSION_CODE >= 0x020322 free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); +#else + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); +#endif +#if LINUX_VERSION_CODE >= 0x010346 free_irq(ha->irq,NULL); +#else + free_irq(ha->irq); +#endif scsi_unregister(shp); continue; } @@ -3253,16 +4096,37 @@ hdr_channel = ha->bus_cnt; ha->virt_bus = hdr_channel; +#if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) +#endif + { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; + } + } + GDTH_INIT_LOCK_HA(ha); gdth_enable_int(hanum); } } /* scanning for PCI controllers */ +#if LINUX_VERSION_CODE >= 0x2015C if (pci_present()) +#else + if (pcibios_present()) +#endif { gdth_pci_str pcistr[MAXHA]; @@ -3272,8 +4136,6 @@ if (gdth_ctr_count >= MAXHA) break; shp = scsi_register(shtp,sizeof(gdth_ext_str)); - if(shp == NULL) - continue; ha = HADATA(shp); if (!gdth_init_pci(&pcistr[ctr],ha)) { scsi_unregister(shp); @@ -3283,14 +4145,18 @@ printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq); +#if LINUX_VERSION_CODE >= 0x010346 if (request_irq(ha->irq, gdth_interrupt, SA_INTERRUPT|SA_SHIRQ, "gdth", ha)) +#else + if (request_irq(ha->irq, gdth_interrupt, + SA_INTERRUPT|SA_SHIRQ, "gdth")) +#endif { printk("GDT-PCI: Unable to allocate IRQ\n"); scsi_unregister(shp); continue; } - scsi_set_pci_device(shp, pcistr[ctr].pdev); shp->unchecked_isa_dma = 0; shp->irq = ha->irq; shp->dma_channel = 0xff; @@ -3302,7 +4168,12 @@ NUMDATA(shp)->busnum= 0; ha->pccb = CMDDATA(shp); - ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD); +#if LINUX_VERSION_CODE >= 0x020322 + ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, + GDTH_SCRATCH_ORD); +#else + ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); +#endif ha->scratch_busy = FALSE; ha->req_first = NULL; ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES; @@ -3317,8 +4188,16 @@ --gdth_ctr_count; --gdth_ctr_vcount; if (ha->pscratch != NULL) +#if LINUX_VERSION_CODE >= 0x020322 free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); +#else + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); +#endif +#if LINUX_VERSION_CODE >= 0x010346 free_irq(ha->irq,NULL); +#else + free_irq(ha->irq); +#endif scsi_unregister(shp); continue; } @@ -3326,9 +4205,26 @@ hdr_channel = ha->bus_cnt; ha->virt_bus = hdr_channel; +#if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; + shp->max_channel = virt_ctr ? 0 : ha->bus_cnt; + if (virt_ctr) +#endif + { + virt_ctr = 1; + /* register addit. SCSI channels as virtual controllers */ + for (b = 1; b < ha->bus_cnt + 1; ++b) { + shp = scsi_register(shtp,sizeof(gdth_num_str)); + shp->unchecked_isa_dma = 0; + shp->irq = ha->irq; + shp->dma_channel = 0xff; + gdth_ctr_vtab[gdth_ctr_vcount++] = shp; + NUMDATA(shp)->hanum = (ushort)hanum; + NUMDATA(shp)->busnum = b; + } + } + GDTH_INIT_LOCK_HA(ha); gdth_enable_int(hanum); } @@ -3344,7 +4240,9 @@ gdth_timer.function = gdth_timeout; add_timer(&gdth_timer); #endif +#if LINUX_VERSION_CODE >= 0x020100 register_reboot_notifier(&gdth_notifier); +#endif } gdth_polling = FALSE; return gdth_ctr_vcount; @@ -3360,15 +4258,27 @@ if (NUMDATA(shp)->busnum == 0) { hanum = NUMDATA(shp)->hanum; ha = HADATA(gdth_ctr_tab[hanum]); +#if LINUX_VERSION_CODE >= 0x010300 gdth_flush(hanum); +#endif if (shp->irq) { +#if LINUX_VERSION_CODE >= 0x010346 free_irq(shp->irq,NULL); +#else + free_irq(shp->irq); +#endif } +#ifndef __ia64__ if (shp->dma_channel != 0xff) { free_dma(shp->dma_channel); } +#endif +#if LINUX_VERSION_CODE >= 0x020322 free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD); +#else + scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH); +#endif gdth_ctr_released++; TRACE2(("gdth_release(): HA %d of %d\n", gdth_ctr_released, gdth_ctr_count)); @@ -3377,7 +4287,9 @@ #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif +#if LINUX_VERSION_CODE >= 0x020100 unregister_reboot_notifier(&gdth_notifier); +#endif } } @@ -3437,12 +4349,17 @@ return SCSI_ABORT_SNOOZE; } +#if LINUX_VERSION_CODE >= 0x010346 int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags) +#else +int gdth_reset(Scsi_Cmnd *scp) +#endif { TRACE2(("gdth_reset()\n")); return SCSI_RESET_PUNT; } +#if LINUX_VERSION_CODE >= 0x02015F /* new error handling */ int gdth_eh_abort(Scsi_Cmnd *scp) { @@ -3462,28 +4379,50 @@ gdth_ha_str *ha; ulong flags; Scsi_Cmnd *cmnd; + unchar b; TRACE2(("gdth_eh_bus_reset()\n")); hanum = NUMDATA(scp->host)->hanum; + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; ha = HADATA(gdth_ctr_tab[hanum]); - if (scp->channel == ha->virt_bus) - return FAILED; + /* clear command tab */ GDTH_LOCK_HA(ha, flags); - for (i = 0; i < MAXID; ++i) - ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0; for (i = 0; i < GDTH_MAXCMDS; ++i) { cmnd = ha->cmd_tab[i].cmnd; - if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel) + if (!SPECIAL_SCP(cmnd) && cmnd->channel == b) ha->cmd_tab[i].cmnd = UNUSED_CMND; } - gdth_polling = TRUE; - while (gdth_test_busy(hanum)) - gdth_delay(0); - gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, - BUS_L2P(ha,scp->channel), 0, 0); - gdth_polling = FALSE; GDTH_UNLOCK_HA(ha, flags); + + if (b == ha->virt_bus) { + /* host drives */ + for (i = 0; i < MAX_HDRIVES; ++i) { + if (ha->hdr[i].present) { + GDTH_LOCK_HA(ha, flags); + gdth_polling = TRUE; + while (gdth_test_busy(hanum)) + gdth_delay(0); + if (gdth_internal_cmd(hanum, CACHESERVICE, + GDT_CLUST_RESET, i, 0, 0)) + ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED; + gdth_polling = FALSE; + GDTH_UNLOCK_HA(ha, flags); + } + } + } else { + /* raw devices */ + GDTH_LOCK_HA(ha, flags); + for (i = 0; i < MAXID; ++i) + ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0; + gdth_polling = TRUE; + while (gdth_test_busy(hanum)) + gdth_delay(0); + gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, + BUS_L2P(ha,b), 0, 0); + gdth_polling = FALSE; + GDTH_UNLOCK_HA(ha, flags); + } return SUCCESS; } @@ -3492,27 +4431,32 @@ TRACE2(("gdth_eh_host_reset()\n")); return FAILED; } +#endif +#if LINUX_VERSION_CODE >= 0x010300 int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) +#else +int gdth_bios_param(Disk *disk,int dev,int *ip) +#endif { - unchar t; + unchar b, t; int hanum; gdth_ha_str *ha; hanum = NUMDATA(disk->device->host)->hanum; + b = virt_ctr ? NUMDATA(disk->device->host)->busnum : disk->device->channel; t = disk->device->id; - TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", - hanum, disk->device->channel, t)); + TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); ha = HADATA(gdth_ctr_tab[hanum]); - if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) { + if (b != ha->virt_bus || ha->hdr[t].heads == 0) { /* raw device or host drive without mapping information */ - TRACE2(("Evaluate mapping\n")); - gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); + TRACE2(("Evaluate mapping\n")); + gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); } else { - ip[0] = ha->hdr[t].heads; - ip[1] = ha->hdr[t].secs; - ip[2] = disk->capacity / ip[0] / ip[1]; + ip[0] = ha->hdr[t].heads; + ip[1] = ha->hdr[t].secs; + ip[2] = disk->capacity / ip[0] / ip[1]; } TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", @@ -3521,24 +4465,6 @@ } -static void internal_done(Scsi_Cmnd *scp) -{ - scp->SCp.sent_command++; -} - -int gdth_command(Scsi_Cmnd *scp) -{ - TRACE2(("gdth_command()\n")); - - scp->SCp.sent_command = 0; - gdth_queuecommand(scp,internal_done); - - while (!scp->SCp.sent_command) - barrier(); - return scp->result; -} - - int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)) { int hanum; @@ -3550,171 +4476,173 @@ scp->scsi_done = (void *)done; scp->SCp.have_data_in = 1; scp->SCp.phase = -1; - scp->SCp.Status = -1; + scp->SCp.sent_command = -1; hanum = NUMDATA(scp->host)->hanum; #ifdef GDTH_STATISTICS ++act_ios; #endif priority = DEFAULT_PRI; +#if LINUX_VERSION_CODE >= 0x010300 if (scp->done == gdth_scsi_done) priority = scp->SCp.this_residual; +#endif gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6); gdth_putq( hanum, scp, priority ); gdth_next( hanum ); return 0; } +#if LINUX_VERSION_CODE >= 0x010300 /* flush routine */ static void gdth_flush(int hanum) { int i; gdth_ha_str *ha; - Scsi_Cmnd * scp; - Scsi_Device * sdev; gdth_cmd_str gdtcmd; +#if LINUX_VERSION_CODE >= 0x020322 + Scsi_Cmnd *scp; + Scsi_Device *sdev; +#else + Scsi_Cmnd scp; + Scsi_Device sdev; +#endif + char cmnd[MAX_COMMAND_SIZE]; + memset(cmnd, 0xff, 12); TRACE2(("gdth_flush() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); +#if LINUX_VERSION_CODE >= 0x020322 sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); - if (!sdev) - return; - scp = scsi_allocate_device(sdev, 1, FALSE); + scp->cmd_len = 12; + scp->use_sg = 0; +#else + memset(&sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + sdev.host = scp.host = gdth_ctr_tab[hanum]; + sdev.id = scp.target = sdev.host->this_id; + scp.device = &sdev; +#endif - if (scp) { - scp->cmd_len = 12; - scp->use_sg = 0; - - for (i = 0; i < MAX_HDRIVES; ++i) { - if (ha->hdr[i].present) { - gdtcmd.BoardNode = LOCALBOARD; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_FLUSH; - gdtcmd.u.cache.DeviceNo = i; - gdtcmd.u.cache.BlockNo = 1; - gdtcmd.u.cache.sg_canz = 0; - TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); - gdth_do_cmd(scp, &gdtcmd, 30); - } + for (i = 0; i < MAX_HDRIVES; ++i) { + if (ha->hdr[i].present) { + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_FLUSH; + gdtcmd.u.cache.DeviceNo = i; + gdtcmd.u.cache.BlockNo = 1; + gdtcmd.u.cache.sg_canz = 0; + TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); +#endif } - scsi_release_command(scp); } +#if LINUX_VERSION_CODE >= 0x020322 + scsi_release_command(scp); scsi_free_host_dev(sdev); +#endif } /* shutdown routine */ +#if LINUX_VERSION_CODE >= 0x020100 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) +#else +void gdth_halt(void) +#endif { int hanum; #ifndef __alpha__ - Scsi_Cmnd * scp; - Scsi_Device * sdev; gdth_cmd_str gdtcmd; +#if LINUX_VERSION_CODE >= 0x020322 + Scsi_Cmnd *scp; + Scsi_Device *sdev; +#else + Scsi_Cmnd scp; + Scsi_Device sdev; +#endif + char cmnd[MAX_COMMAND_SIZE]; #endif - TRACE2(("gdth_halt() event %d\n",event)); +#if LINUX_VERSION_CODE >= 0x020100 + TRACE2(("gdth_halt() event %d\n",(int)event)); if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) return NOTIFY_DONE; +#else + TRACE2(("gdth_halt()\n")); + if (halt_called) { + TRACE2(("already called\n")); + return; + } + halt_called = TRUE; +#endif printk("GDT: Flushing all host drives .. "); for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { gdth_flush(hanum); #ifndef __alpha__ /* controller reset */ - sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); - scp = scsi_allocate_device(sdev, 1, FALSE); + memset(cmnd, 0xff, 12); +#if LINUX_VERSION_CODE >= 0x020322 + sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); + scp = scsi_allocate_device(sdev, 1, FALSE); scp->cmd_len = 12; scp->use_sg = 0; +#else + memset(&sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + sdev.host = scp.host = gdth_ctr_tab[hanum]; + sdev.id = scp.target = sdev.host->this_id; + scp.device = &sdev; +#endif gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_RESET; TRACE2(("gdth_halt(): reset controller %d\n", hanum)); - gdth_do_cmd(scp, &gdtcmd, 10); - scsi_release_command(scp); - scsi_free_host_dev(sdev); +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 10); + scsi_release_command(scp); + scsi_free_host_dev(sdev); +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 10); +#endif #endif } - printk("Done.\n"); #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif +#if LINUX_VERSION_CODE >= 0x020100 +#if LINUX_VERSION_CODE < 0x020322 unregister_reboot_notifier(&gdth_notifier); +#endif return NOTIFY_OK; +#endif } +#endif -/* called from init/main.c */ -void __init gdth_setup(char *str,int *ints) -{ - int i, argc; - char *cur_str, *argv; +#if LINUX_VERSION_CODE < 0x020400 && !defined(MODULE) + +GDTH_INITFUNC(void, gdth_setup(char *str,int *ints)) +{ TRACE2(("gdth_setup() str %s ints[0] %d\n", str ? str:"NULL", ints ? ints[0]:0)); - - /* read irq[] from ints[] */ - if (ints) { - argc = ints[0]; - if (argc > 0) { - if (argc > MAXHA) - argc = MAXHA; - for (i = 0; i < argc; ++i) - irq[i] = ints[i+1]; - } - } - - /* analyse string */ - argv = str; - while (argv && (cur_str = strchr(argv, ':'))) { - int val = 0, c = *++cur_str; - - if (c == 'n' || c == 'N') - val = 0; - else if (c == 'y' || c == 'Y') - val = 1; - else - val = (int)simple_strtoul(cur_str, NULL, 0); - - if (!strncmp(argv, "disable:", 8)) - disable = val; - else if (!strncmp(argv, "reserve_mode:", 13)) - reserve_mode = val; - else if (!strncmp(argv, "reverse_scan:", 13)) - reverse_scan = val; - else if (!strncmp(argv, "hdr_channel:", 12)) - hdr_channel = val; - else if (!strncmp(argv, "max_ids:", 8)) - max_ids = val; - else if (!strncmp(argv, "rescan:", 7)) - rescan = val; - else if (!strncmp(argv, "reserve_list:", 13)) { - reserve_list[0] = val; - for (i = 1; i < MAX_RES_ARGS; i++) { - cur_str = strchr(cur_str, ','); - if (!cur_str) - break; - if (!isdigit((int)*++cur_str)) { - --cur_str; - break; - } - reserve_list[i] = - (int)simple_strtoul(cur_str, NULL, 0); - } - if (!cur_str) - break; - argv = ++cur_str; - continue; - } - - if ((argv = strchr(argv, ','))) - ++argv; - } + internal_setup(str, ints); } +#else -static Scsi_Host_Template driver_template = GDTH; +Scsi_Host_Template driver_template = GDTH; #include "scsi_module.c" +#ifndef MODULE +__setup("gdth=", option_setup); +#endif + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/gdth.h linux/drivers/scsi/gdth.h --- v2.4.4/linux/drivers/scsi/gdth.h Mon Dec 11 13:19:43 2000 +++ linux/drivers/scsi/gdth.h Sat May 19 17:43:06 2001 @@ -4,13 +4,13 @@ /* * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux * - * gdth.h Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner + * gdth.h Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner * See gdth.c for further informations and * below for supported controller types * * * - * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $ + * $Id: gdth.h,v 1.38 2001/03/15 15:06:23 achim Exp $ */ #include @@ -29,9 +29,9 @@ /* defines, macros */ /* driver version */ -#define GDTH_VERSION_STR "1.14" +#define GDTH_VERSION_STR "1.28" #define GDTH_VERSION 1 -#define GDTH_SUBVERSION 14 +#define GDTH_SUBVERSION 28 /* protocol version */ #define PROTOCOL_VERSION 1 @@ -126,7 +126,7 @@ #endif /* limits */ -#define GDTH_SCRATCH PAGE_SIZE /* 4KB scratch buffer */ +#define GDTH_SCRATCH PAGE_SIZE /* 4KB scratch buffer */ #define GDTH_SCRATCH_ORD 0 /* order 0 means 1 page */ #define GDTH_MAXCMDS 124 #define GDTH_MAXC_P_L 16 /* max. cmds per lun */ @@ -136,7 +136,8 @@ #define MAXID 127 #define MAXLUN 8 #define MAXBUS 6 -#define MAX_HDRIVES 35 /* max. host drive count */ +#define MAX_HDRIVES 100 /* max. host drive count */ +#define MAX_LDRIVES 255 /* max. log. drive count */ #define MAX_EVENTS 100 /* event buffer count */ #define MAX_RES_ARGS 40 /* device reservation, must be a multiple of 4 */ @@ -174,7 +175,13 @@ #define IC_QUEUE_BYTES 4 #define DPMEM_COMMAND_OFFSET IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS -/* cache/raw service commands */ +/* cluster_type constants */ +#define CLUSTER_DRIVE 1 +#define CLUSTER_MOUNTED 2 +#define CLUSTER_RESERVED 4 +#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED) + +/* commands for all services, cache service */ #define GDT_INIT 0 /* service initialization */ #define GDT_READ 1 /* read command */ #define GDT_WRITE 2 /* write command */ @@ -190,8 +197,13 @@ #define GDT_READ_THR 17 /* read through */ #define GDT_EXT_INFO 18 /* extended info */ #define GDT_RESET 19 /* controller reset */ +#define GDT_RESERVE_DRV 20 /* reserve host drive */ +#define GDT_RELEASE_DRV 21 /* release host drive */ +#define GDT_CLUST_INFO 22 /* cluster info */ +#define GDT_RW_ATTRIBS 23 /* R/W attribs (write thru,..)*/ +#define GDT_CLUST_RESET 24 /* releases the cluster drives*/ -/* additional raw service commands */ +/* raw service commands */ #define GDT_RESERVE 14 /* reserve dev. to raw serv. */ #define GDT_RELEASE 15 /* release device */ #define GDT_RESERVE_ALL 16 /* reserve all devices */ @@ -200,6 +212,9 @@ #define GDT_SCAN_START 19 /* start device scan */ #define GDT_SCAN_END 20 /* stop device scan */ +/* screen service commands */ +#define GDT_REALTIME 3 /* realtime clock to screens. */ + /* IOCTL command defines */ #define SCSI_DR_INFO 0x00 /* SCSI drive info */ #define SCSI_CHAN_CNT 0x05 /* SCSI channel count */ @@ -207,10 +222,11 @@ #define SCSI_DEF_CNT 0x15 /* grown/primary defects */ #define DSK_STATISTICS 0x4b /* SCSI disk statistics */ #define IOCHAN_DESC 0x5d /* description of IO channel */ -#define IOCHAN_RAW_DESC 0x5e /* description of raw IO channel */ +#define IOCHAN_RAW_DESC 0x5e /* description of raw IO chn. */ #define L_CTRL_PATTERN 0x20000000L /* SCSI IOCTL mask */ #define ARRAY_INFO 0x12 /* array drive info */ #define ARRAY_DRV_LIST 0x0f /* array drive list */ +#define ARRAY_DRV_LIST2 0x34 /* array drive list (new) */ #define LA_CTRL_PATTERN 0x10000000L /* array IOCTL mask */ #define CACHE_DRV_CNT 0x01 /* cache drive count */ #define CACHE_DRV_LIST 0x02 /* cache drive list */ @@ -223,19 +239,11 @@ #define IO_CHANNEL 0x00020000L /* default IO channel */ #define INVALID_CHANNEL 0x0000ffffL /* invalid channel */ -/* IOCTLs */ -#define GDTIOCTL_MASK ('J'<<8) -#define GDTIOCTL_GENERAL (GDTIOCTL_MASK | 0) /* general IOCTL */ -#define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */ -#define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */ -#define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */ -#define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */ -#define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */ -#define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */ - /* service errors */ #define S_OK 1 /* no error */ +#define S_GENERR 6 /* general error */ #define S_BSY 7 /* controller busy */ +#define S_CACHE_UNKNOWN 12 /* cache serv.: drive unknown */ #define S_RAW_SCSI 12 /* raw serv.: target error */ #define S_RAW_ILL 0xff /* raw serv.: illegal */ @@ -250,8 +258,8 @@ #define HIGH_PRI 0x08 /* data directions */ -#define DATA_IN 0x01000000L /* data from target */ -#define DATA_OUT 0x00000000L /* data to target */ +#define GDTH_DATA_IN 0x01000000L /* data from target */ +#define GDTH_DATA_OUT 0x00000000L /* data to target */ /* BMIC registers (EISA controllers) */ #define ID0REG 0x0c80 /* board ID */ @@ -299,7 +307,7 @@ unchar revision[4]; /* revision */ ulong32 sy_rate; /* current rate for sync. tr. */ ulong32 sy_max_rate; /* max. rate for sync. tr. */ - ulong32 no_ldrive; /* belongs to this logical drv.*/ + ulong32 no_ldrive; /* belongs to this log. drv.*/ ulong32 blkcnt; /* number of blocks */ ushort blksize; /* size of block in bytes */ unchar available; /* flag: access is available */ @@ -454,7 +462,15 @@ unchar is_parity; /* Flag: is parity drive? */ unchar is_hotfix; /* Flag: is hotfix drive? */ unchar res[3]; -} PACKED gdth_arraylist_str; +} PACKED gdth_alist_str; + +typedef struct { + ulong32 entries_avail; /* allocated entries */ + ulong32 entries_init; /* returned entries */ + ulong32 first_entry; /* first entry number */ + ulong32 list_offset; /* offset of following list */ + gdth_alist_str list[1]; /* list */ +} PACKED gdth_arcdl_str; /* cache info/config IOCTL */ typedef struct { @@ -586,8 +602,13 @@ } PACKED ioctl; /* IOCTL command structure */ struct { ushort reserved; - ulong32 msg_handle; /* message handle */ - ulong32 msg_addr; /* message buffer address */ + union { + struct { + ulong32 msg_handle; /* message handle */ + ulong32 msg_addr; /* message buffer address */ + } PACKED msg; + unchar data[12]; /* buffer for rtc data, ... */ + } su; } PACKED screen; /* screen service cmd. str. */ struct { ushort reserved; @@ -604,7 +625,7 @@ unchar priority; /* only 0 used */ ulong32 sense_len; /* sense data length */ ulong32 sense_data; /* sense data addr. */ - struct raw *link_p; /* linked cmds (not supp.) */ + ulong32 link_p; /* linked cmds (not supp.) */ ulong32 sg_ranz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ } PACKED raw; /* raw service cmd. struct. */ @@ -650,6 +671,8 @@ ulong32 l1, l2, l3, l4; } PACKED test; } eu; + ulong32 severity; + unchar event_string[256]; } PACKED gdth_evt_data; typedef struct { @@ -799,7 +822,9 @@ unchar unused5[7]; unchar edoor_en_reg; /* board interrupts enable */ unchar unused6[27]; - ulong32 unused7[1004]; /* size: 4 KB */ + ulong32 unused7[939]; + ulong32 severity; + char evt_str[256]; /* event string */ } PACKED gdt6m_i960_regs; /* DPRAM PCI MPR controllers */ @@ -815,7 +840,9 @@ /* PCI resources */ typedef struct { +#if LINUX_VERSION_CODE >= 0x02015C struct pci_dev *pdev; +#endif ushort device_id; /* device ID (0,..,9) */ unchar bus; /* PCI bus */ unchar device_fn; /* PCI device/function no. */ @@ -831,6 +858,7 @@ ushort type; /* controller class */ ushort raw_feat; /* feat. raw service (s/g,..) */ ulong32 stype; /* controller subtype */ + ushort fw_vers; /* firmware version */ ushort cache_feat; /* feat. cache serv. (s/g,..) */ ushort bmic; /* BMIC address (EISA) */ void *brd; /* DPRAM address */ @@ -843,12 +871,13 @@ unchar irq; /* IRQ */ unchar drq; /* DRQ (ISA controllers) */ ushort status; /* command status */ + ushort service; /* service/firmware ver./.. */ ulong32 info; ulong32 info2; /* additional info */ Scsi_Cmnd *req_first; /* top of request queue */ struct { unchar present; /* Flag: host drive present? */ - unchar is_logdrv; /* Flag: logical drive (master)? */ + unchar is_logdrv; /* Flag: log. drive (master)? */ unchar is_arraydrv; /* Flag: array drive? */ unchar is_master; /* Flag: array drive master? */ unchar is_parity; /* Flag: parity drive? */ @@ -861,13 +890,15 @@ ulong32 size; /* capacity */ unchar ldr_no; /* log. drive no. */ unchar rw_attribs; /* r/w attributes */ + unchar cluster_type; /* cluster properties */ + unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */ ulong32 start_sec; /* start sector */ - } hdr[MAX_HDRIVES]; /* host drives */ + } hdr[MAX_LDRIVES]; /* host drives */ struct { unchar lock; /* channel locked? (hot plug) */ unchar pdev_cnt; /* physical device count */ unchar local_no; /* local channel number */ - unchar io_cnt[MAXID]; /* current IO count */ + unchar io_cnt[MAXID]; /* current IO count */ ulong32 address; /* channel address */ ulong32 id_list[MAXID]; /* IDs of the phys. devices */ } raw[MAXBUS]; /* SCSI channels */ @@ -887,7 +918,10 @@ gdth_cpar_str cpar; /* controller cache par. */ gdth_bfeat_str bfeat; /* controller features */ gdth_binfo_str binfo; /* controller info */ + gdth_evt_data dvr; /* event structure */ +#if LINUX_VERSION_CODE >= 0x02015F spinlock_t smp_lock; +#endif } gdth_ha_str; /* structure for scsi_register(), SCSI bus != 0 */ @@ -965,12 +999,16 @@ int gdth_detect(Scsi_Host_Template *); int gdth_release(struct Scsi_Host *); -int gdth_command(Scsi_Cmnd *); int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *)); int gdth_abort(Scsi_Cmnd *); +#if LINUX_VERSION_CODE >= 0x010346 int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags); +#else +int gdth_reset(Scsi_Cmnd *); +#endif const char *gdth_info(struct Scsi_Host *); +#if LINUX_VERSION_CODE >= 0x020322 int gdth_bios_param(Disk *,kdev_t,int *); int gdth_proc_info(char *,char **,off_t,int,int,int); int gdth_eh_abort(Scsi_Cmnd *scp); @@ -983,7 +1021,7 @@ detect: gdth_detect, \ release: gdth_release, \ info: gdth_info, \ - command: gdth_command, \ + command: NULL, \ queuecommand: gdth_queuecommand, \ eh_abort_handler: gdth_eh_abort, \ eh_device_reset_handler: gdth_eh_device_reset, \ @@ -1000,5 +1038,85 @@ unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING, \ use_new_eh_code: 1 /* use new error code */ } + +#elif LINUX_VERSION_CODE >= 0x02015F +int gdth_bios_param(Disk *,kdev_t,int *); +extern struct proc_dir_entry proc_scsi_gdth; +int gdth_proc_info(char *,char **,off_t,int,int,int); +int gdth_eh_abort(Scsi_Cmnd *scp); +int gdth_eh_device_reset(Scsi_Cmnd *scp); +int gdth_eh_bus_reset(Scsi_Cmnd *scp); +int gdth_eh_host_reset(Scsi_Cmnd *scp); +#define GDTH { proc_dir: &proc_scsi_gdth, \ + proc_info: gdth_proc_info, \ + name: "GDT SCSI Disk Array Controller",\ + detect: gdth_detect, \ + release: gdth_release, \ + info: gdth_info, \ + command: NULL, \ + queuecommand: gdth_queuecommand, \ + eh_abort_handler: gdth_eh_abort, \ + eh_device_reset_handler: gdth_eh_device_reset, \ + eh_bus_reset_handler: gdth_eh_bus_reset, \ + eh_host_reset_handler: gdth_eh_host_reset, \ + abort: gdth_abort, \ + reset: gdth_reset, \ + bios_param: gdth_bios_param, \ + can_queue: GDTH_MAXCMDS, \ + this_id: -1, \ + sg_tablesize: GDTH_MAXSG, \ + cmd_per_lun: GDTH_MAXC_P_L, \ + present: 0, \ + unchecked_isa_dma: 1, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 /* use new error code */ } + +#elif LINUX_VERSION_CODE >= 0x010300 +int gdth_bios_param(Disk *,kdev_t,int *); +extern struct proc_dir_entry proc_scsi_gdth; +int gdth_proc_info(char *,char **,off_t,int,int,int); +#define GDTH { NULL, NULL, \ + &proc_scsi_gdth, \ + gdth_proc_info, \ + "GDT SCSI Disk Array Controller", \ + gdth_detect, \ + gdth_release, \ + gdth_info, \ + NULL, \ + gdth_queuecommand, \ + gdth_abort, \ + gdth_reset, \ + NULL, \ + gdth_bios_param, \ + GDTH_MAXCMDS, \ + -1, \ + GDTH_MAXSG, \ + GDTH_MAXC_P_L, \ + 0, \ + 1, \ + ENABLE_CLUSTERING} + +#else +int gdth_bios_param(Disk *,int,int *); +#define GDTH { NULL, NULL, \ + "GDT SCSI Disk Array Controller", \ + gdth_detect, \ + gdth_release, \ + gdth_info, \ + NULL, \ + gdth_queuecommand, \ + gdth_abort, \ + gdth_reset, \ + NULL, \ + gdth_bios_param, \ + GDTH_MAXCMDS, \ + -1, \ + GDTH_MAXSG, \ + GDTH_MAXC_P_L, \ + 0, \ + 1, \ + ENABLE_CLUSTERING} +#endif + #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/gdth_ioctl.h linux/drivers/scsi/gdth_ioctl.h --- v2.4.4/linux/drivers/scsi/gdth_ioctl.h Mon Jan 11 10:17:20 1999 +++ linux/drivers/scsi/gdth_ioctl.h Sat May 19 17:43:06 2001 @@ -2,7 +2,7 @@ #define _GDTH_IOCTL_H /* gdth_ioctl.h - * $Id: gdth_ioctl.h,v 1.2 1998/12/17 15:42:49 achim Exp $ + * $Id: gdth_ioctl.h,v 1.9 2001/01/10 14:39:37 achim Exp $ */ /* IOCTLs */ @@ -11,13 +11,19 @@ #define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */ #define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */ #define GDTIOCTL_OSVERS (GDTIOCTL_MASK | 3) /* get OS version */ +#define GDTIOCTL_HDRLIST (GDTIOCTL_MASK | 4) /* get host drive list */ #define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */ #define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */ #define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */ #define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */ +#define GDTIOCTL_SCSI (GDTIOCTL_MASK | 9) /* SCSI command */ +#define GDTIOCTL_RESET_BUS (GDTIOCTL_MASK |10) /* reset SCSI bus */ +#define GDTIOCTL_RESCAN (GDTIOCTL_MASK |11) /* rescan host drives */ +#define GDTIOCTL_RESET_DRV (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */ -#define GDTIOCTL_MAGIC 0xaffe0001UL - +#define GDTIOCTL_MAGIC 0xaffe0004 +#define EVENT_SIZE 294 +#define MAX_HDRIVES 100 /* IOCTL structure (write) */ typedef struct { @@ -34,7 +40,7 @@ struct { unchar lock; /* lock/unlock */ unchar drive_cnt; /* drive count */ - ushort drives[35]; /* drives */ + ushort drives[MAX_HDRIVES];/* drives */ } lockdrv; struct { unchar lock; /* lock/unlock */ @@ -43,8 +49,19 @@ struct { int erase; /* erase event ? */ int handle; - unchar evt[34]; /* event structure */ + unchar evt[EVENT_SIZE]; /* event structure */ } event; + struct { + unchar bus; /* SCSI bus */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar cmd_len; /* command length */ + unchar cmd[12]; /* SCSI command */ + } scsi; + struct { + ushort hdr_no; /* host drive number */ + unchar flag; /* old meth./add/remove */ + } rescan; } iu; } gdth_iowr_str; @@ -77,8 +94,14 @@ } ctrcnt; struct { int handle; - unchar evt[34]; /* event structure */ + unchar evt[EVENT_SIZE]; /* event structure */ } event; + struct { + unchar bus; /* SCSI bus, 0xff: invalid */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar cluster_type; /* cluster properties */ + } hdr_list[MAX_HDRIVES]; /* index is host drive number */ } iu; } gdth_iord_str; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c --- v2.4.4/linux/drivers/scsi/gdth_proc.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/gdth_proc.c Sat May 19 17:43:06 2001 @@ -1,5 +1,5 @@ /* gdth_proc.c - * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $ + * $Id: gdth_proc.c,v 1.27 2001/03/14 10:47:00 achim Exp $ */ #include "gdth_ioctl.h" @@ -31,27 +31,30 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) { int ret_val; - Scsi_Cmnd * scp; - Scsi_Device * sdev; +#if LINUX_VERSION_CODE >= 0x020322 + Scsi_Cmnd *scp; + Scsi_Device *sdev; +#else + Scsi_Cmnd scp; + Scsi_Device sdev; +#endif gdth_iowr_str *piowr; TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum)); piowr = (gdth_iowr_str *)buffer; +#if LINUX_VERSION_CODE >= 0x020322 sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); - - if(sdev==NULL) - return -ENOMEM; - scp = scsi_allocate_device(sdev, 1, FALSE); - - if(scp==NULL) - { - scsi_free_host_dev(sdev); - return -ENOMEM; - } scp->cmd_len = 12; scp->use_sg = 0; +#else + memset(&sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.id = scp.target = sdev.host->this_id; + scp.device = &sdev; +#endif if (length >= 4) { if (strncmp(buffer,"gdth",4) == 0) { @@ -61,20 +64,29 @@ } else if (piowr->magic == GDTIOCTL_MAGIC) { ret_val = gdth_set_bin_info( buffer, length, hanum, scp ); } else { - printk("GDT: Wrong signature: %6s\n",buffer); + printk("GDT: Wrong signature %x (%x required)!\n", + piowr->magic, GDTIOCTL_MAGIC); + if (piowr->magic > GDTIOCTL_MAGIC) + printk("GDT: Please update your driver.\n"); + else + printk("GDT: Please update your tool.\n"); ret_val = -EINVAL; } } else { ret_val = -EINVAL; } - +#if LINUX_VERSION_CODE >= 0x020322 scsi_release_command(scp); scsi_free_host_dev(sdev); - +#endif return ret_val; } -static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp) +#if LINUX_VERSION_CODE >= 0x020322 +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) +#else +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) +#endif { int orig_length, drive, wb_mode; int i, found; @@ -82,6 +94,10 @@ gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; + char cmnd[MAX_COMMAND_SIZE]; + memset(cmnd, 0xff, 12); + memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); + TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); orig_length = length + 5; @@ -108,13 +124,15 @@ if (drive != -1 && i != drive) continue; found = TRUE; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_FLUSH; gdtcmd.u.cache.DeviceNo = i; gdtcmd.u.cache.BlockNo = 1; - gdtcmd.u.cache.sg_canz = 0; - gdth_do_cmd(scp, &gdtcmd, 30); +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); +#endif } } if (!found) @@ -159,7 +177,6 @@ return(-EBUSY); pcpar = (gdth_cpar_str *)ha->pscratch; memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar); @@ -167,7 +184,11 @@ gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; pcpar->write_back = wb_mode==1 ? 0:1; - gdth_do_cmd(scp, &gdtcmd, 30); +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); +#endif gdth_ioctl_free(hanum); printk("Done.\n"); return(orig_length); @@ -177,17 +198,27 @@ return(-EINVAL); } -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp) +#if LINUX_VERSION_CODE >= 0x020322 +static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) +#else +static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) +#endif { unchar i, j; + ushort k, hdr_cnt, status; gdth_ha_str *ha; gdth_iowr_str *piowr; gdth_iord_str *piord; gdth_cmd_str *pcmd; gdth_evt_str *pevt; - ulong32 *ppadd, add_size; - ulong32 *ppadd2, add_size2; + ulong32 *ppadd, add_size, *ppadd2, add_size2, info; ulong flags; + gdth_cmd_str gdtcmd; + int drv_cyls, drv_hds, drv_secs; + + char cmnd[MAX_COMMAND_SIZE]; + memset(cmnd, 0xff, 12); + memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -250,8 +281,13 @@ *ppadd2 = virt_to_bus(piord->iu.general.data+add_size); } /* do IOCTL */ - gdth_do_cmd(scp, pcmd, piowr->timeout); - piord->status = (ulong32)scp->SCp.Message; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); + piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; +#else + gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); + piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; +#endif break; case GDTIOCTL_DRVERS: @@ -371,10 +407,10 @@ pevt->event_data.size = sizeof(pevt->event_data.eu.async); gdth_log_event(&pevt->event_data, NULL); } - GDTH_LOCK_HA(ha, flags); + GDTH_LOCK_HA(ha, flags); gdth_store_event(ha, pevt->event_source, pevt->event_idx, &pevt->event_data); - GDTH_UNLOCK_HA(ha, flags); + GDTH_UNLOCK_HA(ha, flags); } else if (piowr->iu.event.erase == 0xfe) { gdth_clear_events(); } else if (piowr->iu.event.erase == 0) { @@ -390,11 +426,236 @@ piord->status = S_OK; break; + case GDTIOCTL_SCSI: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + memcpy(cmnd, piowr->iu.scsi.cmd, 12); +#if LINUX_VERSION_CODE >= 0x020322 + scp->target = piowr->iu.scsi.target; + scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; + scp->cmd_len = piowr->iu.scsi.cmd_len; + gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); + piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; +#else + scp.target = piowr->iu.scsi.target; + scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; + scp.cmd_len = piowr->iu.scsi.cmd_len; + gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); + piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; +#endif + break; + + case GDTIOCTL_RESET_BUS: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); +#if LINUX_VERSION_CODE >= 0x020322 + scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; + piord->status = (ulong32)gdth_eh_bus_reset( scp ); + if (piord->status == SUCCESS) + piord->status = S_OK; + else + piord->status = S_GENERR; +#elif LINUX_VERSION_CODE >= 0x02015F + scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; + piord->status = (ulong32)gdth_eh_bus_reset( &scp ); + if (piord->status == SUCCESS) + piord->status = S_OK; + else + piord->status = S_GENERR; +#else + piord->status = S_OK; +#endif + break; + + case GDTIOCTL_HDRLIST: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + piord->status = S_OK; + for (i = 0; i < MAX_HDRIVES; ++i) { + if (ha->hdr[i].present) { + piord->iu.hdr_list[i].bus = ha->virt_bus; + piord->iu.hdr_list[i].target = i; + piord->iu.hdr_list[i].lun = 0; + piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; + if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_CLUST_INFO; + gdtcmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status == S_OK) + piord->iu.hdr_list[i].cluster_type = + (unchar)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status == S_OK) + piord->iu.hdr_list[i].cluster_type = + (unchar)scp.SCp.Message; +#endif + } + } else { + piord->iu.hdr_list[i].bus = 0xff; + } + } + break; + + case GDTIOCTL_RESCAN: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + piord->status = S_OK; + if (piowr->iu.rescan.flag == 0) { + /* old method: scan all host drives + re-initialize cache service to get host drive count + */ + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_INIT; + gdtcmd.u.cache.DeviceNo = LINUX_OS; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + if (status != S_OK) + break; + k = 0; + hdr_cnt = (ushort)info; + } else { + k = piowr->iu.rescan.hdr_no; + hdr_cnt = k + 1; + } + if (hdr_cnt > MAX_HDRIVES) + hdr_cnt = MAX_HDRIVES; + /* scanning for host drives */ + for (; k < hdr_cnt; ++k) { + /* info about host drive */ + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_INFO; + gdtcmd.u.cache.DeviceNo = k; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + piord->iu.hdr_list[k].bus = ha->virt_bus; + piord->iu.hdr_list[k].target = k; + piord->iu.hdr_list[k].lun = 0; + if (status != S_OK) { + ha->hdr[k].present = FALSE; + } else { + ha->hdr[k].present = TRUE; + ha->hdr[k].size = info; + /* evaluate mapping (sectors per head, heads per cylinder) */ + ha->hdr[k].size &= ~SECS32; + gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs); + ha->hdr[k].heads = (unchar)drv_hds; + ha->hdr[k].secs = (unchar)drv_secs; + /* round size */ + ha->hdr[k].size = drv_cyls * drv_hds * drv_secs; + } + GDTH_UNLOCK_HA(ha, flags); + if (status != S_OK) + continue; /* next host drive */ + + /* devtype, cluster info, R/W attributes */ + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_DEVTYPE; + gdtcmd.u.cache.DeviceNo = k; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[k].devtype = 0; + if (status == S_OK) + ha->hdr[k].devtype = (ushort)info; + GDTH_UNLOCK_HA(ha, flags); + + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_CLUST_INFO; + gdtcmd.u.cache.DeviceNo = k; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[k].cluster_type = 0; + if (status == S_OK && !shared_access) + ha->hdr[k].cluster_type = (ushort)info; + GDTH_UNLOCK_HA(ha, flags); + piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type; + + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_RW_ATTRIBS; + gdtcmd.u.cache.DeviceNo = k; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + status = (ushort)scp->SCp.Status; + info = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + status = (ushort)scp.SCp.Status; + info = (ulong32)scp.SCp.Message; +#endif + GDTH_LOCK_HA(ha, flags); + ha->hdr[k].rw_attribs = 0; + if (status == S_OK) + ha->hdr[k].rw_attribs = (ushort)info; + GDTH_UNLOCK_HA(ha, flags); + } + break; + + case GDTIOCTL_RESET_DRV: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + piord->status = S_OK; + i = piowr->iu.scsi.target; + if (ha->hdr[i].present) { + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_CLUST_RESET; + gdtcmd.u.cache.DeviceNo = i; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; +#endif + } + break; + default: return(-EINVAL); } - /* we return a buffer ID to detect the right buffer during READ-IOCTL */ - return 1; + return length; } static int gdth_get_info(char *buffer,char **start,off_t offset, @@ -410,8 +671,13 @@ gdth_cmd_str gdtcmd; gdth_evt_str estr; - Scsi_Cmnd * scp; +#if LINUX_VERSION_CODE >= 0x020322 + Scsi_Cmnd *scp; Scsi_Device *sdev; +#else + Scsi_Cmnd scp; + Scsi_Device sdev; +#endif char hrec[161]; struct timeval tv; @@ -422,17 +688,28 @@ gdth_cdrinfo_str *pcdi; gdth_hget_str *phg; + char cmnd[MAX_COMMAND_SIZE]; + memset(cmnd, 0xff, 12); + memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); + TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum)); ha = HADATA(gdth_ctr_tab[hanum]); - id = length; +#if LINUX_VERSION_CODE >= 0x020322 sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); scp = scsi_allocate_device(sdev, 1, FALSE); scp->cmd_len = 12; scp->use_sg = 0; +#else + memset(&sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.id = scp.target = sdev.host->this_id; + scp.device = &sdev; +#endif - /* look for buffer ID in length */ - if (id > 1) { + /* ioctl from tool? */ + if (!gdth_ioctl_check_bin(hanum, (ushort)length)) { /* request is i.e. "cat /proc/scsi/gdth/0" */ /* format: %-15s\t%-10s\t%-15s\t%s */ /* driver parameters */ @@ -457,17 +734,13 @@ max_ids, hdr_channel); len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - /* controller information */ size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); len += size; pos = begin + len; - strcpy(hrec, ha->binfo.type_string); + if (virt_ctr) + sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); + else + strcpy(hrec, ha->binfo.type_string); size = sprintf(buffer+len, " Number: \t%d \tName: \t%s\n", hanum, hrec); @@ -503,17 +776,10 @@ ha->binfo.ser_no, ha->binfo.memsize / 1024); len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - /* 2. about physical devices */ size = sprintf(buffer+len,"\nPhysical Devices:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; @@ -521,7 +787,6 @@ /* 2.a statistics (and retries/reassigns) */ TRACE2(("pdr_statistics() chn %d\n",i)); pds = (gdth_dskstat_str *)(ha->pscratch + GDTH_SCRATCH/4); - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pds); @@ -535,11 +800,16 @@ sizeof(pds->list[0]); if (pds->entries > cnt) pds->entries = cnt; - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message != S_OK) +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status != S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status != S_OK) +#endif + { pds->count = 0; - TRACE2(("pdr_statistics() entries %d status %d\n", - pds->count, scp->SCp.Message)); + } /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { @@ -547,7 +817,6 @@ TRACE2(("scsi_drv_info() chn %d dev %d\n", i, ha->raw[i].id_list[j])); pdi = (gdth_diskinfo_str *)ha->pscratch; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pdi); @@ -555,8 +824,14 @@ gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; gdtcmd.u.ioctl.channel = ha->raw[i].address | ha->raw[i].id_list[j]; - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message == S_OK) { +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status == S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status == S_OK) +#endif + { strncpy(hrec,pdi->vendor,8); strncpy(hrec+8,pdi->product,16); strncpy(hrec+24,pdi->revision,4); @@ -565,7 +840,7 @@ "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", 'A'+i,pdi->target_id,pdi->lun,hrec); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; pdi->no_ldrive &= 0xffff; if (pdi->no_ldrive == 0xffff) strcpy(hrec,"--"); @@ -597,7 +872,6 @@ TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", i, ha->raw[i].id_list[j])); pdef = (gdth_defcnt_str *)ha->pscratch; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pdef); @@ -606,37 +880,43 @@ gdtcmd.u.ioctl.channel = ha->raw[i].address | ha->raw[i].id_list[j]; pdef->sddc_type = 0x08; - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message == S_OK) { +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status == S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status == S_OK) +#endif + { size = sprintf(buffer+len, " Grown Defects:\t%d\n", pdef->sddc_cnt); len += size; pos = begin + len; } } + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; } } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - if (pos < offset) { - len = 0; - begin = pos; + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; } - if (pos > offset + length) - goto stop_output; /* 3. about logical drives */ size = sprintf(buffer+len,"\nLogical Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv) continue; drv_no = i; @@ -646,16 +926,22 @@ /* 3.a log. drive info */ TRACE2(("cache_drv_info() drive no %d\n",drv_no)); pcdi = (gdth_cdrinfo_str *)ha->pscratch; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi); gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; gdtcmd.u.ioctl.channel = drv_no; - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message != S_OK) +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status != S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status != S_OK) +#endif + { break; + } pcdi->ld_dtype >>= 16; j++; if (pcdi->ld_dtype > 2) { @@ -674,7 +960,7 @@ "\n Number: \t%-2d \tStatus: \t%s\n", drv_no, hrec); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; no_mdrv = pcdi->cd_ldcnt; if (no_mdrv > 1 || pcdi->ld_slave != -1) { is_mirr = TRUE; @@ -700,6 +986,12 @@ len += size; pos = begin + len; } drv_no = pcdi->ld_slave; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; } while (drv_no != -1); if (is_mirr) { @@ -716,42 +1008,47 @@ size = sprintf(buffer+len, " To Array Drv.:\t%s\n", hrec); len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } /* 4. about array drives */ size = sprintf(buffer+len,"\nArray Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) continue; /* 4.a array drive info */ TRACE2(("array_info() drive no %d\n",i)); pai = (gdth_arrayinf_str *)ha->pscratch; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(pai); gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; gdtcmd.u.ioctl.channel = i; - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message == S_OK) { +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status == S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status == S_OK) +#endif + { if (pai->ai_state == 0) strcpy(hrec, "idle"); else if (pai->ai_state == 2) @@ -787,36 +1084,35 @@ pai->ai_size/(1024*1024/pai->ai_secsize), hrec); len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; } } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - if (pos < offset) { - len = 0; - begin = pos; + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; } - if (pos > offset + length) - goto stop_output; /* 5. about host drives */ size = sprintf(buffer+len,"\nHost Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv || (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) continue; /* 5.a get host drive list */ TRACE2(("host_get() drv_no %d\n",i)); phg = (gdth_hget_str *)ha->pscratch; - gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = virt_to_bus(phg); @@ -825,23 +1121,27 @@ gdtcmd.u.ioctl.channel = i; phg->entries = MAX_HDRIVES; phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); - gdth_do_cmd(scp, &gdtcmd, 30); - if (scp->SCp.Message != S_OK) { +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + if (scp->SCp.Status != S_OK) +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if (scp.SCp.Status != S_OK) +#endif + { ha->hdr[i].ldr_no = i; ha->hdr[i].rw_attribs = 0; ha->hdr[i].start_sec = 0; } else { for (j = 0; j < phg->entries; ++j) { k = phg->entry[j].host_drive; - if (k >= MAX_HDRIVES) + if (k >= MAX_LDRIVES) continue; ha->hdr[k].ldr_no = phg->entry[j].log_drive; ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; ha->hdr[k].start_sec = phg->entry[j].start_sec; } } - TRACE2(("host_get entries %d status %d\n", - phg->entries, scp->SCp.Message)); } gdth_ioctl_free(hanum); @@ -853,24 +1153,24 @@ "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", i, ha->hdr[i].ldr_no); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; size = sprintf(buffer+len, " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", ha->hdr[i].size/2048, ha->hdr[i].start_sec); len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; } - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - if (pos < offset) { - len = 0; - begin = pos; + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; } - if (pos > offset + length) - goto stop_output; } /* controller events */ @@ -886,7 +1186,7 @@ gdth_log_event(&estr.event_data, hrec); do_gettimeofday(&tv); sec = (int)(tv.tv_sec - estr.first_stamp); - if (sec < 0) sec = 0; + if (sec < 0) sec = 0; size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", sec/3600, sec%3600/60, sec%60, hrec); len += size; pos = begin + len; @@ -908,21 +1208,14 @@ length = piord->size; memcpy(buffer+len, (char *)piord, length); gdth_ioctl_free(hanum); - len += length; pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; + len = length; } stop_output: - +#if LINUX_VERSION_CODE >= 0x020322 scsi_release_command(scp); scsi_free_host_dev(sdev); - +#endif *start = buffer +(offset-begin); len -= (offset-begin); if (len > length) @@ -932,18 +1225,33 @@ return(len); } -static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout) +static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, + char *cmnd, int timeout) { - char cmnd[MAX_COMMAND_SIZE]; + unsigned bufflen; +#if LINUX_VERSION_CODE >= 0x020322 DECLARE_MUTEX_LOCKED(sem); +#else + struct semaphore sem = MUTEX_LOCKED; +#endif TRACE2(("gdth_do_cmd()\n")); - memset(cmnd, 0, MAX_COMMAND_SIZE); + if (gdtcmd != NULL) { + scp->SCp.this_residual = IOCTL_PRI; + bufflen = sizeof(gdth_cmd_str); + } else { + scp->SCp.this_residual = DEFAULT_PRI; + bufflen = 0; + } scp->request.rq_status = RQ_SCSI_BUSY; scp->request.sem = &sem; - scp->SCp.this_residual = IOCTL_PRI; - scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), - gdth_scsi_done, timeout*HZ, 1); +#if LINUX_VERSION_CODE >= 0x020322 + scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); +#else + GDTH_LOCK_SCSI_DOCMD(); + scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); + GDTH_UNLOCK_SCSI_DOCMD(); +#endif down(&sem); } @@ -992,21 +1300,41 @@ GDTH_UNLOCK_HA(ha, flags); } +static int gdth_ioctl_check_bin(int hanum, ushort size) +{ + gdth_ha_str *ha; + ulong flags; + int ret_val; + + ha = HADATA(gdth_ctr_tab[hanum]); + GDTH_LOCK_HA(ha, flags); + + ret_val = FALSE; + if (ha->scratch_busy) { + if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size) + ret_val = TRUE; + } + GDTH_UNLOCK_HA(ha, flags); + return ret_val; +} + + static void gdth_wait_completion(int hanum, int busnum, int id) { gdth_ha_str *ha; ulong flags; int i; Scsi_Cmnd *scp; + unchar b; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (i = 0; i < GDTH_MAXCMDS; ++i) { scp = ha->cmd_tab[i].cmnd; - if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && - scp->channel == (unchar)busnum) - { + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; + if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && + b == (unchar)busnum) { scp->SCp.have_data_in = 0; GDTH_UNLOCK_HA(ha, flags); while (!scp->SCp.have_data_in) @@ -1025,14 +1353,14 @@ gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; + unchar b; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { - if (scp->target == (unchar)id && - scp->channel == (unchar)busnum) - { + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; + if (scp->target == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_stop_timeout(): update_timeout()\n")); scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); } @@ -1045,14 +1373,14 @@ gdth_ha_str *ha; ulong flags; Scsi_Cmnd *scp; + unchar b; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { - if (scp->target == (unchar)id && - scp->channel == (unchar)busnum) - { + b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; + if (scp->target == (unchar)id && b == (unchar)busnum) { TRACE2(("gdth_start_timeout(): update_timeout()\n")); gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual); } @@ -1067,6 +1395,7 @@ oldto = scp->timeout_per_command; scp->timeout_per_command = timeout; +#if LINUX_VERSION_CODE >= 0x02014B if (timeout == 0) { del_timer(&scp->eh_timeout); scp->eh_timeout.data = (unsigned long) NULL; @@ -1078,5 +1407,17 @@ scp->eh_timeout.expires = jiffies + timeout; add_timer(&scp->eh_timeout); } +#else + if (timeout > 0) { + if (timer_table[SCSI_TIMER].expires == 0) { + timer_table[SCSI_TIMER].expires = jiffies + timeout; + timer_active |= 1 << SCSI_TIMER; + } else { + if (jiffies + timeout < timer_table[SCSI_TIMER].expires) + timer_table[SCSI_TIMER].expires = jiffies + timeout; + } + } +#endif + return oldto; } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/gdth_proc.h linux/drivers/scsi/gdth_proc.h --- v2.4.4/linux/drivers/scsi/gdth_proc.h Fri Jan 21 09:48:11 2000 +++ linux/drivers/scsi/gdth_proc.h Sat May 19 17:43:06 2001 @@ -2,23 +2,31 @@ #define _GDTH_PROC_H /* gdth_proc.h - * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $ + * $Id: gdth_proc.h,v 1.10 2000/07/24 09:30:01 achim Exp $ */ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum); -static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp); -static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd * scp); static int gdth_get_info(char *buffer,char **start,off_t offset, int length,int vh,int hanum,int busnum); +#if LINUX_VERSION_CODE >= 0x020322 +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp); +static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp); +#else +static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp); +static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp); +#endif +static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, + char *cmnd, int timeout); + static int gdth_ioctl_alloc(int hanum, ushort size); static void gdth_ioctl_free(int hanum); +static int gdth_ioctl_check_bin(int hanum, ushort size); static void gdth_wait_completion(int hanum, int busnum, int id); static void gdth_stop_timeout(int hanum, int busnum, int id); static void gdth_start_timeout(int hanum, int busnum, int id); static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout); -static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout); void gdth_scsi_done(Scsi_Cmnd *scp); #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.4.4/linux/drivers/scsi/ibmmca.c Fri Mar 2 18:38:38 2001 +++ linux/drivers/scsi/ibmmca.c Tue May 1 16:05:00 2001 @@ -50,7 +50,7 @@ /* driver debugging - #undef all for normal operation */ /* if defined: count interrupts and ignore this special one: */ -#undef IM_DEBUG_TIMEOUT 50 +#undef IM_DEBUG_TIMEOUT //50 #define TIMEOUT_PUN 0 #define TIMEOUT_LUN 0 /* verbose interrupt: */ diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.4.4/linux/drivers/scsi/ips.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/ips.c Sat May 19 17:43:06 2001 @@ -86,6 +86,20 @@ /* Merge in changes through kernel 2.4.0test1ac21 */ /* 4.20.13 - Fix some failure cases / reset code */ /* - Hook into the reboot_notifier to flush the controller cache */ +/* 4.50.01 - Fix problem when there is a hole in logical drive numbering */ +/* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */ +/* - Add IPSSEND Flash Support */ +/* - Set Sense Data for Unknown SCSI Command */ +/* - Use Slot Number from NVRAM Page 5 */ +/* - Restore caller's DCDB Structure */ +/* 4.70.12 - Corrective actions for bad controller ( during initialization )*/ +/* 4.70.13 - Don't Send CDB's if we already know the device is not present */ +/* - Don't release HA Lock in ips_next() until SC taken off queue */ +/* - Unregister SCSI device in ips_release() */ +/* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */ +/* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */ +/* Code Clean-Up for 2.4.x kernel */ +/* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */ /* */ /*****************************************************************************/ @@ -110,10 +124,8 @@ * nocmdline - Turn off passthru support * noi2o - Don't use I2O Queues (ServeRAID 4 only) * nommap - Don't use memory mapped I/O + * ioctlsize - Initial size of the IOCTL buffer */ - - -#include #include #include @@ -122,7 +134,7 @@ #include #include #include -#include +#include #include #include #include @@ -130,6 +142,8 @@ #include #include #include +#include +#include #include #include @@ -143,6 +157,8 @@ #include "hosts.h" #include "ips.h" +#include + #include #include @@ -166,8 +182,9 @@ /* * DRIVER_VER */ -#define IPS_VERSION_HIGH "4.20" -#define IPS_VERSION_LOW ".20 " +#define IPS_VERSION_HIGH "4.72" +#define IPS_VERSION_LOW ".00 " + #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) struct proc_dir_entry proc_scsi_ips = { @@ -214,6 +231,10 @@ static int ips_force_i2o = 1; /* Always use I2O command delivery */ static int ips_resetcontroller = 1; /* Reset the controller */ static int ips_cmdline = 1; /* Support for passthru */ +static int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */ +static int ips_cd_boot = 0; /* Booting from ServeRAID Manager CD */ +static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */ +static int ips_FlashDataInUse = 0; /* CD Boot - Flash Data In Use Flag */ #ifdef IPS_DEBUG static int ips_debug = 0; /* Debug mode */ @@ -224,7 +245,7 @@ */ static int ips_halt(struct notifier_block *nb, ulong event, void *buf); -#define MAX_ADAPTER_NAME 9 +#define MAX_ADAPTER_NAME 11 static char ips_adapter_name[][30] = { "ServeRAID", @@ -235,7 +256,9 @@ "ServeRAID 3L", "ServeRAID 4H", "ServeRAID 4M", - "ServeRAID 4L" + "ServeRAID 4L", + "ServeRAID 4Mx", + "ServeRAID 4Lx" }; static struct notifier_block ips_notifier = { @@ -347,6 +370,12 @@ static u32 ips_statupd_copperhead(ips_ha_t *); static u32 ips_statupd_copperhead_memio(ips_ha_t *); static u32 ips_statupd_morpheus(ips_ha_t *); +static void ips_flash_bios_section(void *); +static void ips_flash_bios_segment(void *); +static void ips_scheduled_flash_bios(void *); +static void ips_create_nvrampage5(ips_ha_t *, IPS_NVRAM_P5 *); +static void ips_get_bios_version(ips_ha_t *, int); +static void ips_identify_controller(ips_ha_t *); static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *); static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); static void ips_enable_int_copperhead(ips_ha_t *); @@ -380,15 +409,15 @@ static inline ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); static inline ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t *); static int ips_erase_bios(ips_ha_t *); -static int ips_program_bios(ips_ha_t *, char *, int); -static int ips_verify_bios(ips_ha_t *, char *, int); +static int ips_program_bios(ips_ha_t *, char *, u32, u32); +static int ips_verify_bios(ips_ha_t *, char *, u32, u32); static int ips_erase_bios_memio(ips_ha_t *); -static int ips_program_bios_memio(ips_ha_t *, char *, int); -static int ips_verify_bios_memio(ips_ha_t *, char *, int); +static int ips_program_bios_memio(ips_ha_t *, char *, u32, u32); +static int ips_verify_bios_memio(ips_ha_t *, char *, u32, u32); #ifndef NO_IPS_CMDLINE static int ips_is_passthru(Scsi_Cmnd *); -static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *); +static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static int ips_newusrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); @@ -432,6 +461,8 @@ {"noi2o", &ips_force_i2o, 0}, {"nommap", &ips_force_memio, 0}, {"nocmdline", &ips_cmdline, 0}, + {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, + {"cdboot", &ips_cd_boot, 0}, }; METHOD_TRACE("ips_setup", 1); @@ -498,8 +529,10 @@ u8 func; u8 irq; u16 deviceID[2]; + u16 subdevice_id; int i; int j; + u32 count; char *ioremap_ptr; char *mem_ptr; struct pci_dev *dev[2]; @@ -522,6 +555,16 @@ #endif #endif + /* If Booting from the ServeRAID Manager CD, Allocate a large Flash */ + /* Buffer ( so we won't need to allocate one for each adapter ). */ + if ( ips_cd_boot ) { + ips_FlashData = ( char * ) __get_free_pages( GFP_KERNEL, 7 ); + if (ips_FlashData == NULL) { + /* The validity of this pointer is checked in ips_make_passthru() before it is used */ + printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" ); + } + } + SHT->proc_info = ips_proc_info; #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) SHT->proc_dir = &proc_scsi_ips; @@ -530,53 +573,53 @@ #endif #if defined(CONFIG_PCI) - + /* initalize number of controllers */ ips_num_controllers = 0; ips_next_controller = 0; ips_released_controllers = 0; - + if (!pci_present()) return (0); - morpheus = pci_find_device(IPS_VENDORID, IPS_MORPHEUS_DEVICEID, morpheus); - trombone = pci_find_device(IPS_VENDORID, IPS_COPPERHEAD_DEVICEID, trombone); - + morpheus = pci_find_device(IPS_VENDORID, IPS_DEVICEID_MORPHEUS, morpheus); + trombone = pci_find_device(IPS_VENDORID, IPS_DEVICEID_COPPERHEAD, trombone); + /* determine which controller to probe first */ if (!morpheus) { /* we only have trombone */ dev[0] = trombone; dev[1] = NULL; - deviceID[0] = IPS_COPPERHEAD_DEVICEID; + deviceID[0] = IPS_DEVICEID_COPPERHEAD; } else if (!trombone) { /* we only have morpheus */ dev[0] = morpheus; dev[1] = NULL; - deviceID[0] = IPS_MORPHEUS_DEVICEID; + deviceID[0] = IPS_DEVICEID_MORPHEUS; } else { /* we have both in the system */ if (trombone->bus < morpheus->bus) { dev[0] = trombone; dev[1] = morpheus; - deviceID[0] = IPS_COPPERHEAD_DEVICEID; - deviceID[1] = IPS_MORPHEUS_DEVICEID; + deviceID[0] = IPS_DEVICEID_COPPERHEAD; + deviceID[1] = IPS_DEVICEID_MORPHEUS; } else if (trombone->bus > morpheus->bus) { dev[0] = morpheus; dev[1] = trombone; - deviceID[0] = IPS_MORPHEUS_DEVICEID; - deviceID[1] = IPS_COPPERHEAD_DEVICEID; + deviceID[0] = IPS_DEVICEID_MORPHEUS; + deviceID[1] = IPS_DEVICEID_COPPERHEAD; } else { /* further detection required */ if (trombone->devfn < morpheus->devfn) { dev[0] = trombone; dev[1] = morpheus; - deviceID[0] = IPS_COPPERHEAD_DEVICEID; - deviceID[1] = IPS_MORPHEUS_DEVICEID; + deviceID[0] = IPS_DEVICEID_COPPERHEAD; + deviceID[1] = IPS_DEVICEID_MORPHEUS; } else { dev[0] = morpheus; dev[1] = trombone; - deviceID[0] = IPS_MORPHEUS_DEVICEID; - deviceID[1] = IPS_COPPERHEAD_DEVICEID; + deviceID[0] = IPS_DEVICEID_MORPHEUS; + deviceID[1] = IPS_DEVICEID_COPPERHEAD; } } } @@ -711,14 +754,14 @@ /* get planer status */ if (pci_read_config_word(dev[i], 0x04, &planer)) { - printk(KERN_WARNING "(%s%d) can't get planer status.\n", + printk(KERN_WARNING "(%s%d) can't get planer status.\n", ips_name, ips_next_controller); ips_next_controller++; continue; } - + /* check to see if an onboard planer controller is disabled */ if (!(planer & 0x000C)) { @@ -743,6 +786,20 @@ continue; } +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,15) + /* get the subdevice id */ + if (pci_read_config_word(dev[i], 0x2e, &subdevice_id)) { + printk(KERN_WARNING "(%s%d) can't get subdevice id.\n", + ips_name, ips_next_controller); + + ips_next_controller++; + + continue; + } +#else + subdevice_id = dev[i]->subsystem_device; +#endif + /* found a controller */ sh = scsi_register(SHT, sizeof(ips_ha_t)); @@ -771,7 +828,7 @@ ips_num_controllers++; ha->active = 1; - ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC|GFP_DMA); + ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC); if (!ha->enq) { printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n", @@ -779,26 +836,33 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC|GFP_DMA); + ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC); if (!ha->adapt) { printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n", ips_name, ips_next_controller); + ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC|GFP_DMA); + ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC); if (!ha->conf) { printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n", @@ -806,13 +870,16 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC|GFP_DMA); + ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC); if (!ha->nvram) { printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n", @@ -820,13 +887,16 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC|GFP_DMA); + ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC); if (!ha->subsys) { printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n", @@ -834,13 +904,16 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC|GFP_DMA); + ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC); if (!ha->dummy) { printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n", @@ -848,24 +921,29 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; continue; } - ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_ATOMIC|GFP_DMA); - ha->ioctl_datasize = IPS_IOCTL_SIZE; + for (count = PAGE_SIZE, ha->ioctl_order = 0; + count < ips_ioctlsize; + ha->ioctl_order++, count <<= 1); + + ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order); + ha->ioctl_datasize = count; + if (!ha->ioctl_data) { - printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n", + printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n", ips_name, ips_next_controller); - ha->active = 0; - ips_free(ha); - ips_next_controller++; - ips_num_controllers--; - - continue; + ha->ioctl_data = NULL; + ha->ioctl_order = 0; + ha->ioctl_datasize = 0; } /* Store away needed values for later use */ @@ -879,7 +957,11 @@ sh->cmd_per_lun = sh->hostt->cmd_per_lun; sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; sh->use_clustering = sh->hostt->use_clustering; - scsi_set_pci_device(sh, dev[i]); +/***** Implement the following if it gets into a future kernel +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,4) + sh->max_sectors = 128; +#endif +******/ #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32) sh->wish_block = FALSE; @@ -895,7 +977,9 @@ ha->ioremap_ptr = ioremap_ptr; ha->host_num = ips_next_controller; ha->revision_id = revision_id; + ha->slot_num = PCI_SLOT(dev[i]->devfn); ha->device_id = deviceID[i]; + ha->subdevice_id = subdevice_id; ha->pcidev = dev[i]; /* @@ -962,6 +1046,9 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; @@ -976,6 +1063,9 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; ips_next_controller++; ips_num_controllers--; @@ -985,7 +1075,7 @@ /* * Allocate a temporary SCB for initialization */ - ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA); + ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC); if (!ha->scbs) { /* couldn't allocate a temp SCB */ printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", @@ -993,6 +1083,9 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; free_irq(ha->irq, ha); ips_next_controller++; ips_num_controllers--; @@ -1001,7 +1094,7 @@ } memset(ha->scbs, 0, sizeof(ips_scb_t)); - ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA); + ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC); if (!ha->scbs->sg_list) { /* couldn't allocate a temp SCB S/G list */ printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", @@ -1009,6 +1102,9 @@ ha->active = 0; ips_free(ha); + scsi_unregister(sh); + ips_ha[ips_next_controller] = 0; + ips_sh[ips_next_controller] = 0; free_irq(ha->irq, ha); ips_next_controller++; ips_num_controllers--; @@ -1027,6 +1123,13 @@ * Controller init */ for (i = 0; i < ips_next_controller; i++) { + + if (ips_ha[i] == 0) { + printk(KERN_WARNING "(%s%d) ignoring bad controller\n", + ips_name, i); + continue; + } + ha = ips_ha[i]; sh = ips_sh[i]; @@ -1165,6 +1268,8 @@ /* free IRQ */ free_irq(ha->irq, ha); + scsi_unregister(sh); + ips_released_controllers++; if (ips_num_controllers == ips_released_controllers) @@ -1376,7 +1481,7 @@ if (!ret) { Scsi_Cmnd *scsi_cmd; - printk(KERN_NOTICE + printk(KERN_NOTICE "(%s%d) Controller reset failed - controller now offline.\n", ips_name, ha->host_num); @@ -1408,7 +1513,7 @@ if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { Scsi_Cmnd *scsi_cmd; - printk(KERN_NOTICE + printk(KERN_NOTICE "(%s%d) Controller reset failed - controller now offline.\n", ips_name, ha->host_num); @@ -1622,17 +1727,29 @@ kern_area = ha->ioctl_data; datasize = *((u32 *) &SC->cmnd[8]); - if (copy_to_user(user_area, kern_area, datasize) > 0) { - DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data", - ips_name, ha->host_num); + if (datasize) { + if (copy_to_user(user_area, kern_area, datasize) > 0) { + DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data", + ips_name, ha->host_num); - SC->result = DID_ERROR << 16; - SC->scsi_done(SC); + SC->result = DID_ERROR << 16; + SC->scsi_done(SC); + } else { + SC->scsi_done(SC); + } } else { SC->scsi_done(SC); } } + /* If We were using the CD Boot Flash Buffer, Restore the Old Values */ + if ( ips_FlashData == ha->ioctl_data ) { + ha->ioctl_data = ha->save_ioctl_data; + ha->ioctl_order = ha->save_ioctl_order; + ha->ioctl_datasize = ha->save_ioctl_datasize; + ips_FlashDataInUse = 0; + } + return (0); } @@ -1718,6 +1835,9 @@ device->queue_depth = ha->max_cmds / count - 1; else device->queue_depth = 2; + + if (device->queue_depth < 2) + device->queue_depth = 2; } } } @@ -1979,10 +2099,11 @@ /* Find our host structure */ for (i = 0; i < ips_next_controller; i++) { - if (ips_sh[i] && ips_sh[i]->host_no == hostno) { - ha = (ips_ha_t *) ips_sh[i]->hostdata; - - break; + if (ips_sh[i]) { + if (ips_sh[i]->host_no == hostno) { + ha = (ips_ha_t *) ips_sh[i]->hostdata; + break; + } } } @@ -2051,7 +2172,8 @@ /* */ /****************************************************************************/ static int -ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) { +ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb, int intr) { + IPS_NVRAM_P5 nvram; ips_passthru_t *pt; METHOD_TRACE("ips_make_passthru", 1); @@ -2128,19 +2250,375 @@ return (IPS_FAILURE); } + if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) && + (pt->CoppCP.cmd.nvram.page == 5) && + (pt->CoppCP.cmd.nvram.write == 0)) { + + if (pt->CmdBSize < sizeof(IPS_NVRAM_P5)) { + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + ips_get_bios_version(ha, IPS_INTR_IORL); + ips_create_nvrampage5(ha, &nvram); + + /* Copy the result back */ + memcpy(SC->request_buffer + sizeof(ips_passthru_t), &nvram, sizeof(IPS_NVRAM_P5)); + + SC->result = DID_OK << 16; + pt->BasicStatus = 0x00; + pt->ExtendedStatus = 0x00; + + return (IPS_SUCCESS_IMM); + } + if (ips_usrcmd(ha, pt, scb)) return (IPS_SUCCESS); else return (IPS_FAILURE); } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) { + char *user_area; + char *kern_area; + u32 datasize; + if (SC->request_bufflen < (sizeof(ips_passthru_t))) { /* wrong size */ DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", ips_name, ha->host_num); + SC->result = DID_ERROR << 16; + return (IPS_FAILURE); } + + /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */ + /* avoid allocating a huge buffer per adapter ( which can fail ). */ + if ( (ips_FlashData) && + (pt->CmdBSize == IPS_IMAGE_SIZE) && + (ips_FlashDataInUse == 0) ) { + ips_FlashDataInUse = 1; + ha->save_ioctl_data = ha->ioctl_data; + ha->save_ioctl_order = ha->ioctl_order; + ha->save_ioctl_datasize = ha->ioctl_datasize; + ha->ioctl_data = ips_FlashData; + ha->ioctl_order = 7; + ha->ioctl_datasize = IPS_IMAGE_SIZE; + } + + if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) && + (pt->CoppCP.cmd.nvram.page == 5) && + (pt->CoppCP.cmd.nvram.write == 0)) { + + datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]); + + if (datasize < sizeof(IPS_NVRAM_P5)) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + ips_get_bios_version(ha, IPS_INTR_IORL); + ips_create_nvrampage5(ha, &nvram); + + user_area = *((char **) &scb->scsi_cmd->cmnd[4]); + kern_area = (char *) &nvram; + datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]); + + if (datasize > sizeof(IPS_NVRAM_P5)) + datasize = sizeof(IPS_NVRAM_P5); + + /* Copy out the buffer */ + if (copy_to_user((void *) user_area, (void *) kern_area, datasize) > 0) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + pt->BasicStatus = 0x00; + pt->ExtendedStatus = 0x00; + SC->result = DID_OK << 16; + + return (IPS_SUCCESS_IMM); + } + + /* + * IPSSEND flashing BIOS + */ + if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) && + (pt->CoppCP.cmd.flashfw.type == 1) && + (pt->CoppCP.cmd.flashfw.direction == 2) && + (ha->device_id == IPS_DEVICEID_COPPERHEAD)) { + struct tq_struct task; + IPS_FLASH_DATA flash_data; + DECLARE_MUTEX_LOCKED(sem); + + /* We only support one packet */ + if (pt->CoppCP.cmd.flashfw.total_packets != 1) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* copy in the size/buffer ptr from the scsi command */ + memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4); + memcpy(&pt->CmdBSize, &SC->cmnd[8], 4); + + if (pt->CmdBSize > pt->CoppCP.cmd.flashfw.count) { + pt->CmdBSize = pt->CoppCP.cmd.flashfw.count; + } else { + /* ERROR: Command/Buffer mismatch */ + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + if ((!ha->func.programbios) || + (!ha->func.erasebios) || + (!ha->func.verifybios)) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* must have a buffer */ + if ((!pt->CmdBSize) || (!pt->CmdBuffer)) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* make sure buffer is big enough */ + if (pt->CmdBSize > ha->ioctl_datasize) { + void *bigger_struct; + u32 count; + u32 order; + + /* try to allocate a bigger struct */ + for (count = PAGE_SIZE, order = 0; + count < pt->CmdBSize; + order++, count <<= 1); + + bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order); + if (bigger_struct) { + /* free the old memory */ + free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order); + + /* use the new memory */ + ha->ioctl_data = (char *) bigger_struct; + ha->ioctl_order = order; + ha->ioctl_datasize = count; + } else { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + spin_unlock(&ha->ips_lock); + + return (IPS_FAILURE); + } + } + + /* copy in the buffer */ + if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + flash_data.userbuffer = pt->CmdBuffer; + flash_data.usersize = pt->CmdBSize; + flash_data.kernbuffer = ha->ioctl_data; + flash_data.kernsize = ha->ioctl_datasize; + flash_data.offset = 0; + flash_data.SC = (void *) SC; + flash_data.pt = (void *) pt; + flash_data.ha = (void *) ha; + flash_data.sem = &sem; + + task.sync = 0; + task.routine = ips_scheduled_flash_bios; + task.data = (void *) &flash_data; + + /* Unlock the master lock */ + spin_unlock_irq(&io_request_lock); + + queue_task(&task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + /* Wait for the flash to complete */ + down(&sem); + + /* Obtain the master lock */ + spin_lock_irq(&io_request_lock); + + return (flash_data.retcode); + } + + /* + * IPSSEND flashing BIOS in sectioned mode + */ + if ((pt->CoppCP.cmd.flashbios.op_code == IPS_CMD_RW_BIOSFW) && + (pt->CoppCP.cmd.flashbios.type == 1) && + (pt->CoppCP.cmd.flashbios.direction == 4) && + (ha->device_id == IPS_DEVICEID_COPPERHEAD)) { + struct tq_struct task; + IPS_FLASH_DATA flash_data; + DECLARE_MUTEX_LOCKED(sem); + + /* copy in the size/buffer ptr from the scsi command */ + memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4); + memcpy(&pt->CmdBSize, &SC->cmnd[8], 4); + + if (pt->CmdBSize > pt->CoppCP.cmd.flashbios.count) { + pt->CmdBSize = pt->CoppCP.cmd.flashbios.count; + } else { + /* ERROR: Command/Buffer mismatch */ + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* Update the Card BIOS */ + if ((!ha->func.programbios) || + (!ha->func.erasebios) || + (!ha->func.verifybios)) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* must have a buffer */ + if ((!pt->CmdBSize) || (!pt->CmdBuffer)) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + /* make sure buffer is big enough */ + if (pt->CmdBSize > ha->ioctl_datasize) { + void *bigger_struct; + u32 count; + u32 order; + + /* try to allocate a bigger struct */ + for (count = PAGE_SIZE, order = 0; + count < pt->CmdBSize; + order++, count <<= 1); + + bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order); + if (bigger_struct) { + /* free the old memory */ + free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order); + + /* use the new memory */ + ha->ioctl_data = (char *) bigger_struct; + ha->ioctl_order = order; + ha->ioctl_datasize = count; + } else { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + spin_unlock(&ha->ips_lock); + + return (IPS_FAILURE); + } + } + + /* copy in the buffer */ + if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + flash_data.userbuffer = pt->CmdBuffer; + flash_data.usersize = pt->CmdBSize; + flash_data.kernbuffer = ha->ioctl_data; + flash_data.kernsize = ha->ioctl_datasize; + flash_data.offset = pt->CoppCP.cmd.flashbios.offset; + flash_data.SC = (void *) SC; + flash_data.pt = (void *) pt; + flash_data.ha = (void *) ha; + flash_data.sem = &sem; + + task.sync = 0; + task.routine = ips_flash_bios_section; + task.data = (void *) &flash_data; + + /* Unlock the master lock */ + spin_unlock_irq(&io_request_lock); + + queue_task(&task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + /* Wait for the flash to complete */ + down(&sem); + + /* Obtain the master lock */ + spin_lock_irq(&io_request_lock); + + return (flash_data.retcode); + } + + if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) && + (pt->CoppCP.cmd.flashfw.type == 1) && + (pt->CoppCP.cmd.flashfw.direction == 3) && + (ha->device_id == IPS_DEVICEID_COPPERHEAD)) { + /* Erase the Card BIOS */ + if (!ha->func.erasebios) { + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + if ((*ha->func.erasebios)(ha)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + + return (IPS_FAILURE); + } + + SC->result = DID_OK << 16; + pt->BasicStatus = 0x00; + pt->ExtendedStatus = 0x00; + + return (IPS_SUCCESS_IMM); + } + if (ips_newusrcmd(ha, pt, scb)) return (IPS_SUCCESS); else @@ -2149,87 +2627,152 @@ break; - case IPS_FLASHBIOS: - /* we must use the new interface */ - if (SC->cmnd[0] != IPS_IOCTL_NEW_COMMAND) - return (IPS_FAILURE); + } /* end switch */ - /* don't flash the BIOS on future cards */ - if ((ha->device_id != IPS_COPPERHEAD_DEVICEID) || - (ha->revision_id > IPS_REVID_TROMBONE64)) { - DEBUG_VAR(1, "(%s%d) flash bios failed - unsupported controller", - ips_name, ha->host_num); + return (IPS_FAILURE); +} - return (IPS_FAILURE); - } +/****************************************************************************/ +/* */ +/* Routine Name: ips_scheduled_flash_bios */ +/* */ +/* Routine Description: */ +/* */ +/* Flash the BIOS on a Copperhead style controller */ +/* To be called from a task queue */ +/* */ +/****************************************************************************/ +static void +ips_scheduled_flash_bios(void *data) { + ips_ha_t *ha; + Scsi_Cmnd *SC; + ips_passthru_t *pt; + IPS_FLASH_DATA *fd; - /* - * Check to make sure we have functions - * to handle the request - */ - if ((!ha->func.programbios) || - (!ha->func.erasebios) || - (!ha->func.verifybios)) - return (IPS_FAILURE); + fd = (IPS_FLASH_DATA *) data; + ha = (ips_ha_t *) fd->ha; + pt = (ips_passthru_t *) fd->pt; + SC = (Scsi_Cmnd *) fd->SC; - /* copy in the size/buffer ptr from the scsi command */ - memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4); - memcpy(&pt->CmdBSize, &SC->cmnd[8], 4); + /* + * Set initial return codes + */ + SC->result = DID_OK << 16; + pt->BasicStatus = 0x00; + pt->ExtendedStatus = 0x00; + fd->retcode = IPS_SUCCESS_IMM; - /* must have a buffer */ - if ((!pt->CmdBSize) || (!pt->CmdBuffer)) - return (IPS_FAILURE); + /* + * Fix the size/ptr to account for the + * flash header + */ + fd->kernbuffer += 0xC0; + fd->kernsize -= 0xC0; + fd->userbuffer += 0xC0; + fd->usersize -= 0xC0; - /* make sure buffer is big enough */ - if (pt->CmdBSize > ha->ioctl_datasize) { - void *bigger_struct; + if ((*ha->func.erasebios)(ha)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + fd->retcode = IPS_FAILURE; + up(fd->sem); - /* try to allocate a bigger struct */ - bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA); - if (bigger_struct) { - /* free the old memory */ - kfree(ha->ioctl_data); + return ; + } - /* use the new memory */ - ha->ioctl_data = bigger_struct; - ha->ioctl_datasize = pt->CmdBSize; - } else - return (IPS_FAILURE); - } + ips_flash_bios_segment(data); - /* copy in the buffer */ - if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) { - DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer", - ips_name, ha->host_num); + if (fd->retcode == IPS_FAILURE) + return ; - return (IPS_FAILURE); - } + if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + fd->retcode = IPS_FAILURE; + up(fd->sem); - if ((*ha->func.erasebios)(ha)) { - DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash", - ips_name, ha->host_num); + return ; + } - return (IPS_FAILURE); - } + /* Tell them we are done */ + if (fd->retcode != IPS_FAILURE) + up(fd->sem); +} - if ((*ha->func.programbios)(ha, ha->ioctl_data, pt->CmdBSize)) { - DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash", - ips_name, ha->host_num); +/****************************************************************************/ +/* */ +/* Routine Name: ips_flash_bios_section */ +/* */ +/* Routine Description: */ +/* */ +/* wrapper for ips_flash_bios_segment that raises the semaphore */ +/* */ +/****************************************************************************/ +static void +ips_flash_bios_section(void *data) { + ips_ha_t *ha; + Scsi_Cmnd *SC; + ips_passthru_t *pt; + IPS_FLASH_DATA *fd; - return (IPS_FAILURE); - } + fd = (IPS_FLASH_DATA *) data; + ha = (ips_ha_t *) fd->ha; + pt = (ips_passthru_t *) fd->pt; + SC = (Scsi_Cmnd *) fd->SC; - if ((*ha->func.verifybios)(ha, ha->ioctl_data, pt->CmdBSize)) { - DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash", - ips_name, ha->host_num); + /* + * Set initial return codes + */ + SC->result = DID_OK << 16; + pt->BasicStatus = 0x00; + pt->ExtendedStatus = 0x00; + fd->retcode = IPS_SUCCESS_IMM; - return (IPS_FAILURE); - } + ips_flash_bios_segment(data); - return (IPS_SUCCESS_IMM); - } /* end switch */ + if (fd->retcode != IPS_FAILURE) + up(fd->sem); +} - return (IPS_FAILURE); +/****************************************************************************/ +/* */ +/* Routine Name: ips_flash_bios_segment */ +/* */ +/* Routine Description: */ +/* */ +/* Flash a portion of the BIOS on a Copperhead style controller */ +/* To be called from a task queue */ +/* */ +/****************************************************************************/ +static void +ips_flash_bios_segment(void *data) { + ips_ha_t *ha; + Scsi_Cmnd *SC; + ips_passthru_t *pt; + IPS_FLASH_DATA *fd; + + fd = (IPS_FLASH_DATA *) data; + ha = (ips_ha_t *) fd->ha; + pt = (ips_passthru_t *) fd->pt; + SC = (Scsi_Cmnd *) fd->SC; + + if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash", + ips_name, ha->host_num); + pt->BasicStatus = 0x0B; + pt->ExtendedStatus = 0x00; + SC->result = DID_ERROR << 16; + fd->retcode = IPS_FAILURE; + up(fd->sem); + + return ; + } } /****************************************************************************/ @@ -2363,16 +2906,23 @@ if (pt->CmdBSize) { if (pt->CmdBSize > ha->ioctl_datasize) { void *bigger_struct; + u32 count; + u32 order; /* try to allocate a bigger struct */ - bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA); + for (count = PAGE_SIZE, order = 0; + count < pt->CmdBSize; + order++, count <<= 1); + + bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order); if (bigger_struct) { /* free the old memory */ - kfree(ha->ioctl_data); + free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order); /* use the new memory */ - ha->ioctl_data = bigger_struct; - ha->ioctl_datasize = pt->CmdBSize; + ha->ioctl_data = (char *) bigger_struct; + ha->ioctl_order = order; + ha->ioctl_datasize = count; } else return (0); @@ -2450,6 +3000,10 @@ pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer; /* Copy data back to the user */ + if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) { /* Copy DCDB Back to Caller's Area */ + memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof(IPS_DCDB_TABLE)); + } + if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_COMMAND) { /* Copy data back to the user */ pt->BasicStatus = scb->basic_status; @@ -2606,6 +3160,253 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_identify_controller */ +/* */ +/* Routine Description: */ +/* */ +/* Identify this controller */ +/* */ +/****************************************************************************/ +static void +ips_identify_controller(ips_ha_t *ha) { + METHOD_TRACE("ips_identify_controller", 1); + + switch (ha->device_id) { + case IPS_DEVICEID_COPPERHEAD: + if (ha->revision_id <= IPS_REVID_SERVERAID) { + ha->ad_type = IPS_ADTYPE_SERVERAID; + } else if (ha->revision_id == IPS_REVID_SERVERAID2) { + ha->ad_type = IPS_ADTYPE_SERVERAID2; + } else if (ha->revision_id == IPS_REVID_NAVAJO) { + ha->ad_type = IPS_ADTYPE_NAVAJO; + } else if ((ha->revision_id == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) { + ha->ad_type = IPS_ADTYPE_KIOWA; + } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) && + (ha->revision_id <= IPS_REVID_CLARINETP3)) { + if (ha->enq->ucMaxPhysicalDevices == 15) + ha->ad_type = IPS_ADTYPE_SERVERAID3L; + else + ha->ad_type = IPS_ADTYPE_SERVERAID3; + } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) && + (ha->revision_id <= IPS_REVID_TROMBONE64)) { + ha->ad_type = IPS_ADTYPE_SERVERAID4H; + } + break; + + case IPS_DEVICEID_MORPHEUS: + switch (ha->subdevice_id) { + case IPS_SUBDEVICEID_4L: + ha->ad_type = IPS_ADTYPE_SERVERAID4L; + break; + + case IPS_SUBDEVICEID_4M: + ha->ad_type = IPS_ADTYPE_SERVERAID4M; + break; + + case IPS_SUBDEVICEID_4MX: + ha->ad_type = IPS_ADTYPE_SERVERAID4MX; + break; + + case IPS_SUBDEVICEID_4LX: + ha->ad_type = IPS_ADTYPE_SERVERAID4LX; + break; + } + + break; + } +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_create_nvrampage5 */ +/* */ +/* Routine Description: */ +/* */ +/* Create a pseudo nvram page 5 */ +/* */ +/****************************************************************************/ +static void +ips_create_nvrampage5(ips_ha_t *ha, IPS_NVRAM_P5 *nvram) { + METHOD_TRACE("ips_create_nvrampage5", 1); + + memset(nvram, 0, sizeof(IPS_NVRAM_P5)); + + nvram->signature = IPS_NVRAM_P5_SIG; + nvram->adapter_slot = ha->slot_num; + nvram->adapter_type = ha->ad_type; + nvram->operating_system = IPS_OS_LINUX; + strncpy((char *) nvram->driver_high, IPS_VERSION_HIGH, 4); + strncpy((char *) nvram->driver_low, IPS_VERSION_LOW, 4); + strncpy((char *) nvram->bios_high, ha->bios_version, 4); + strncpy((char *) nvram->bios_low, ha->bios_version + 4, 4); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_get_bios_version */ +/* */ +/* Routine Description: */ +/* */ +/* Get the BIOS revision number */ +/* */ +/****************************************************************************/ +static void +ips_get_bios_version(ips_ha_t *ha, int intr) { + ips_scb_t *scb; + int ret; + u8 major; + u8 minor; + u8 subminor; + u8 *buffer; + char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + METHOD_TRACE("ips_get_bios_version", 1); + + major = 0; + minor = 0; + + strncpy(ha->bios_version, " ?", 8); + + if (ha->device_id == IPS_DEVICEID_COPPERHEAD) { + if (IPS_USE_MEMIO(ha)) { + /* Memory Mapped I/O */ + + /* test 1st byte */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) + return; + + writel(1, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) + return; + + /* Get Major version */ + writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + major = readb(ha->mem_ptr + IPS_REG_FLDP); + + /* Get Minor version */ + writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + minor = readb(ha->mem_ptr + IPS_REG_FLDP); + + /* Get Sub Minor version */ + writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5);/* 5 us */ + + subminor = readb(ha->mem_ptr + IPS_REG_FLDP); + + + } else { + /* Programmed I/O */ + + /* test 1st byte */ + outl(0, ha->io_addr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) + return ; + + outl(1, ha->io_addr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) + return ; + + /* Get Major version */ + outl(0x1FF, ha->io_addr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + major = inb(ha->io_addr + IPS_REG_FLDP); + + /* Get Minor version */ + outl(0x1FE, ha->io_addr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + minor = inb(ha->io_addr + IPS_REG_FLDP); + + /* Get SubMinor version */ + outl(0x1FD, ha->io_addr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + udelay(5); /* 5 us */ + + subminor = inb(ha->io_addr + IPS_REG_FLDP); + + } + } else { + /* Morpheus Family - Send Command to the card */ + + buffer = kmalloc(0x1000, GFP_ATOMIC); + if (!buffer) + return; + + memset(buffer, 0, 0x1000); + + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = IPS_CMD_RW_BIOSFW; + + scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; + scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.flashfw.type = 1; + scb->cmd.flashfw.direction = 0; + scb->cmd.flashfw.count = 0x800; + scb->cmd.flashfw.buffer_addr = VIRT_TO_BUS(buffer); + scb->cmd.flashfw.total_packets = 1; + scb->cmd.flashfw.packet_num = 0; + + /* issue the command */ + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { + /* Error occurred */ + kfree(buffer); + + return; + } + + if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { + major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */ + minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */ + subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fe after the header (0xc0) */ + + } else { + return; + } + + kfree(buffer); + } + + ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4]; + ha->bios_version[1] = '.'; + ha->bios_version[2] = hexDigits[major & 0x0F]; + ha->bios_version[3] = hexDigits[subminor]; + ha->bios_version[4] = '.'; + ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4]; + ha->bios_version[6] = hexDigits[minor & 0x0F]; + ha->bios_version[7] = 0; +} + +/****************************************************************************/ +/* */ /* Routine Name: ips_hainit */ /* */ /* Routine Description: */ @@ -2651,6 +3452,9 @@ return (0); } + /* Identify this controller */ + ips_identify_controller(ha); + if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n", ips_name, ha->host_num); @@ -2799,30 +3603,47 @@ (scb = ips_getscb(ha))) { IPS_QUEUE_UNLOCK(&ha->copp_waitlist); - IPS_HA_UNLOCK(cpu_flags); item = ips_removeq_copp_head(&ha->copp_waitlist); + IPS_HA_UNLOCK(cpu_flags); scb->scsi_cmd = item->scsi_cmd; scb->sem = item->sem; kfree(item); - ret = ips_make_passthru(ha, scb->scsi_cmd, scb); + ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); switch (ret) { case IPS_FAILURE: if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_ERROR << 16; + /* raise the semaphore */ - if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) - up(scb->sem); + if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) { + u32 datasize; - scb->scsi_cmd->result = DID_ERROR << 16; + datasize = 0; + memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4); + up(scb->sem); + } else { + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } } + ips_freescb(ha, scb); break; case IPS_SUCCESS_IMM: if (scb->scsi_cmd) { + scb->scsi_cmd->result = DID_OK << 16; + /* raise the semaphore */ - if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) + if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) { + u32 datasize; + + datasize = 0; + memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4); up(scb->sem); + } else { + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + } } ips_freescb(ha, scb); @@ -2891,10 +3712,12 @@ continue; } - IPS_HA_UNLOCK(cpu_flags); - q = p; SC = ips_removeq_wait(&ha->scb_waitlist, q); + if (SC == NULL) /* Should never happen, but good to check anyway */ + continue; + + IPS_HA_UNLOCK(cpu_flags); /* Unlock HA after command is taken off queue */ SC->result = DID_OK; SC->host_scribble = NULL; @@ -2932,27 +3755,37 @@ scb->data_busaddr = VIRT_TO_BUS(sg[0].address); scb->sg_len = 0; } else { + /* Check for the first Element being bigger than MAX_XFER */ + if (sg[0].length > ha->max_xfer) { + scb->sg_list[0].address = VIRT_TO_BUS(sg[0].address); + scb->sg_list[0].length = ha->max_xfer; + scb->data_len = ha->max_xfer; + scb->breakup = 0; + scb->sg_break=1; + scb->sg_len = 1; + } + else { + for (i = 0; i < SC->use_sg; i++) { + scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i].length = sg[i].length; + + if (scb->data_len + sg[i].length > ha->max_xfer) { + /* + * Data Breakup required + */ + scb->breakup = i; + break; + } - for (i = 0; i < SC->use_sg; i++) { - scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); - scb->sg_list[i].length = sg[i].length; - - if (scb->data_len + sg[i].length > ha->max_xfer) { - /* - * Data Breakup required - */ - scb->breakup = i; - break; + scb->data_len += sg[i].length; } - scb->data_len += sg[i].length; + if (!scb->breakup) + scb->sg_len = SC->use_sg; + else + scb->sg_len = scb->breakup; } - if (!scb->breakup) - scb->sg_len = SC->use_sg; - else - scb->sg_len = scb->breakup; - scb->dcdb.transfer_length = scb->data_len; scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); } @@ -3590,9 +4423,9 @@ * data and had to be broke up. If so, queue * the rest of the data and continue. */ - if (scb->breakup) { - /* we had a data breakup */ - u16 bk_save; + if (scb->breakup || scb->sg_break) { + /* We had a data breakup */ + u8 bk_save; bk_save = scb->breakup; scb->breakup = 0; @@ -3618,34 +4451,68 @@ scb->dcdb.transfer_length = scb->data_len; scb->sg_len = 0; } else { - scb->data_len = 0; - - for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { - scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); - scb->sg_list[i - bk_save].length = sg[i].length; - - if (scb->data_len + sg[i].length > ha->max_xfer) { - /* - * Data Breakup required - */ - scb->breakup = i; - break; + /* We're here because there was MORE than one s/g unit. */ + /* bk_save points to which sg unit to look at */ + /* sg_break points to how far through this unit we are */ + /* NOTE: We will not move from one sg to another here, */ + /* just finish the one we are in. Not the most */ + /* efficient, but it keeps it from getting too hacky */ + + /* IF sg_break is non-zero, then just work on this current sg piece, */ + /* pointed to by bk_save */ + if (scb->sg_break) { + scb->sg_len = 1; + scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address+ha->max_xfer*scb->sg_break); + if (ha->max_xfer > sg[bk_save].length-ha->max_xfer * scb->sg_break) + scb->sg_list[0].length = sg[bk_save].length-ha->max_xfer * scb->sg_break; + else + scb->sg_list[0].length = ha->max_xfer; + scb->sg_break++; /* MUST GO HERE for math below to work */ + scb->data_len = scb->sg_list[0].length;; + + if (sg[bk_save].length <= ha->max_xfer * scb->sg_break ) { + scb->sg_break = 0; /* No more work in this unit */ + if (( bk_save + 1 ) >= scb->scsi_cmd->use_sg) + scb->breakup = 0; + else + scb->breakup = bk_save + 1; } + } else { + /* ( sg_break == 0 ), so this is our first look at a new sg piece */ + if (sg[bk_save].length > ha->max_xfer) { + scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address); + scb->sg_list[0].length = ha->max_xfer; + scb->breakup = bk_save; + scb->sg_break = 1; + scb->data_len = ha->max_xfer; + scb->sg_len = 1; + } else { + /* OK, the next sg is a short one, so loop until full */ + scb->data_len = 0; + scb->sg_len = 0; + scb->sg_break = 0; + /* We're only doing full units here */ + for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { + scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i - bk_save].length = sg[i].length; + if (scb->data_len + sg[i].length > ha->max_xfer) { + scb->breakup = i; /* sneaky, if not more work, than breakup is 0 */ + break; + } + scb->data_len += sg[i].length; + scb->sg_len++; /* only if we didn't get too big */ + } + } + } - scb->data_len += sg[i].length; - } - - if (!scb->breakup) - scb->sg_len = scb->scsi_cmd->use_sg - bk_save; - else - scb->sg_len = scb->breakup - bk_save; - + /* Also, we need to be sure we don't queue work ( breakup != 0 ) + if no more sg units for next time */ scb->dcdb.transfer_length = scb->data_len; scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); - } - } else { + } + } else { /* Non S/G Request */ - if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) { + if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) { /* Further breakup required */ scb->data_len = ha->max_xfer; scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer)); @@ -3882,7 +4749,9 @@ static int ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) { int ret; - + char *sp; + int device_error; + METHOD_TRACE("ips_send_cmd", 1); ret = IPS_SUCCESS; @@ -4068,7 +4937,20 @@ break; default: - scb->scsi_cmd->result = DID_ERROR << 16; + /* Set the Return Info to appear like the Command was */ + /* attempted, a Check Condition occurred, and Sense */ + /* Data indicating an Invalid CDB OpCode is returned. */ + sp = (char *) scb->scsi_cmd->sense_buffer; + memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer)); + + sp[0] = 0x70; /* Error Code */ + sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */ + sp[7] = 0x0A; /* Additional Sense Length */ + sp[12] = 0x20; /* ASC = Invalid OpCode */ + sp[13] = 0x00; /* ASCQ */ + + device_error = 2; /* Indicate Check Condition */ + scb->scsi_cmd->result = device_error | (DID_OK << 16); break; } /* end switch */ } /* end if */ @@ -4083,6 +4965,13 @@ else scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; + /* If we already know the Device is Not there, no need to attempt a Command */ + /* This also protects an NT FailOver Controller from getting CDB's sent to it */ + if ( ha->conf->dev[scb->bus-1][scb->target_id].ucState == 0 ) { + scb->scsi_cmd->result = DID_NO_CONNECT << 16; + return (IPS_SUCCESS_IMM); + } + ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id); scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb); @@ -4289,8 +5178,7 @@ return (0); } - if (scb->target_id < ha->adapt->logical_drive_info.no_of_log_drive && - ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE && + if (ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE && ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_FREE && ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_CRS && ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_SYS) @@ -4510,9 +5398,10 @@ } if (ha->ioctl_data) { - kfree(ha->ioctl_data); + free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order); ha->ioctl_data = NULL; ha->ioctl_datasize = 0; + ha->ioctl_order = 0; } if (ha->scbs) { @@ -4552,9 +5441,10 @@ METHOD_TRACE("ips_allocatescbs", 1); /* Allocate memory for the CCBs */ - ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA); - if(ha->scbs == NULL) - return 0; + ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC); + if (ha->scbs == NULL) + return 0; + memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t)); @@ -4562,7 +5452,7 @@ scb_p = &ha->scbs[i]; /* allocate S/G list */ - scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA); + scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC); if (! scb_p->sg_list) return (0); @@ -4713,7 +5603,7 @@ /****************************************************************************/ static int ips_isinit_copperhead_memio(ips_ha_t *ha) { - u8 isr; + u8 isr=0; u8 scpr; METHOD_TRACE("ips_is_init_copperhead_memio", 1); @@ -4903,7 +5793,7 @@ /****************************************************************************/ static int ips_init_copperhead_memio(ips_ha_t *ha) { - u8 Isr; + u8 Isr=0; u8 Cbsp; u8 PostByte[IPS_MAX_POST_BYTES]; u8 ConfigByte[IPS_MAX_CONFIG_BYTES]; @@ -5372,7 +6262,7 @@ TimeOut = 0; while ((val = inw(ha->io_addr + IPS_REG_CCCR)) & IPS_BIT_SEM) { - UDELAY(1000); + udelay(1000); if (++TimeOut >= IPS_SEM_TIMEOUT) { if (!(val & IPS_BIT_START_STOP)) @@ -5435,7 +6325,7 @@ TimeOut = 0; while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { - UDELAY(1000); + udelay(1000); if (++TimeOut >= IPS_SEM_TIMEOUT) { if (!(val & IPS_BIT_START_STOP)) @@ -5674,7 +6564,7 @@ */ while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) - UDELAY(1000); + udelay(1000); (*ha->func.intr)(ha); @@ -5700,7 +6590,7 @@ spin_lock(&io_request_lock); while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) - UDELAY(1000); + udelay(1000); (*ha->func.intr)(ha); @@ -5709,7 +6599,7 @@ spin_unlock(&io_request_lock); } - UDELAY(1000); /* 1 milisecond */ + udelay(1000); /* 1 milisecond */ time--; } @@ -5752,9 +6642,6 @@ ha->nvram->bios_low[0], ha->nvram->bios_low[1], ha->nvram->bios_low[2], ha->nvram->bios_low[3]); - /* save controller type */ - ha->ad_type = ha->nvram->adapter_type; - /* change values (as needed) */ ha->nvram->operating_system = IPS_OS_LINUX; strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); @@ -5768,6 +6655,9 @@ return (0); } + /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ + ha->slot_num = ha->nvram->adapter_slot; + return (1); } @@ -6154,40 +7044,40 @@ static int ips_erase_bios(ips_ha_t *ha) { int timeout; - u8 status; + u8 status=0; METHOD_TRACE("ips_erase_bios", 1); /* Clear the status register */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(0x50, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Setup */ outb(0x20, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Confirm */ outb(0xD0, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Status */ outb(0x70, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ timeout = 80000; /* 80 seconds */ while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = inb(ha->io_addr + IPS_REG_FLDP); @@ -6206,14 +7096,14 @@ /* try to suspend the erase */ outb(0xB0, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = inb(ha->io_addr + IPS_REG_FLDP); @@ -6242,12 +7132,12 @@ /* clear status */ outb(0x50, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* enable reads */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (0); } @@ -6270,33 +7160,33 @@ /* Clear the status register */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Setup */ writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Confirm */ writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* Erase Status */ writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ timeout = 80000; /* 80 seconds */ while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = readb(ha->mem_ptr + IPS_REG_FLDP); @@ -6315,14 +7205,14 @@ /* try to suspend the erase */ writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = readb(ha->mem_ptr + IPS_REG_FLDP); @@ -6351,12 +7241,12 @@ /* clear status */ writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* enable reads */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (0); } @@ -6370,33 +7260,33 @@ /* */ /****************************************************************************/ static int -ips_program_bios(ips_ha_t *ha, char *buffer, int buffersize) { +ips_program_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) { int i; int timeout; - u8 status; + u8 status=0; METHOD_TRACE("ips_program_bios", 1); for (i = 0; i < buffersize; i++) { /* write a byte */ - outl(i, ha->io_addr + IPS_REG_FLAP); + outl(i + offset, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(0x40, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(buffer[i], ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* wait up to one second */ timeout = 1000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = inb(ha->io_addr + IPS_REG_FLDP); @@ -6412,11 +7302,11 @@ /* timeout error */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (1); } @@ -6426,11 +7316,11 @@ /* programming error */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (1); } @@ -6439,11 +7329,11 @@ /* Enable reading */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (0); } @@ -6457,33 +7347,33 @@ /* */ /****************************************************************************/ static int -ips_program_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) { +ips_program_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) { int i; int timeout; - u8 status; + u8 status=0; METHOD_TRACE("ips_program_bios_memio", 1); for (i = 0; i < buffersize; i++) { /* write a byte */ - writel(i, ha->mem_ptr + IPS_REG_FLAP); + writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ /* wait up to one second */ timeout = 1000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ } status = readb(ha->mem_ptr + IPS_REG_FLDP); @@ -6499,11 +7389,11 @@ /* timeout error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (1); } @@ -6513,11 +7403,11 @@ /* programming error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (1); } @@ -6526,11 +7416,11 @@ /* Enable reading */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ return (0); } @@ -6544,7 +7434,7 @@ /* */ /****************************************************************************/ static int -ips_verify_bios(ips_ha_t *ha, char *buffer, int buffersize) { +ips_verify_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) { u8 checksum; int i; @@ -6553,23 +7443,23 @@ /* test 1st byte */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return (1); outl(1, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) return (1); checksum = 0xff; for (i = 2; i < buffersize; i++) { - outl(i, ha->io_addr + IPS_REG_FLAP); + outl(i + offset, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ checksum = (u8) checksum + inb(ha->io_addr + IPS_REG_FLDP); } @@ -6591,7 +7481,7 @@ /* */ /****************************************************************************/ static int -ips_verify_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) { +ips_verify_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) { u8 checksum; int i; @@ -6600,23 +7490,23 @@ /* test 1st byte */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) return (1); writel(1, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) return (1); checksum = 0xff; for (i = 2; i < buffersize; i++) { - writel(i, ha->mem_ptr + IPS_REG_FLAP); + writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) - UDELAY(5); /* 5 us */ + udelay(5); /* 5 us */ checksum = (u8) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); } @@ -6631,7 +7521,6 @@ static Scsi_Host_Template driver_template = IPS; #include "scsi_module.c" - /* diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- v2.4.4/linux/drivers/scsi/ips.h Mon Dec 11 13:38:29 2000 +++ linux/drivers/scsi/ips.h Sat May 19 17:43:06 2001 @@ -69,13 +69,13 @@ #define IPS_HA(x) ((ips_ha_t *) x->hostdata) #define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs) - #define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \ + #define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \ (ha->revision_id >= IPS_REVID_TROMBONE32) && \ (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0) - #define IPS_IS_CLARINET(ha) (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \ + #define IPS_IS_CLARINET(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \ (ha->revision_id >= IPS_REVID_CLARINETP1) && \ (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0) - #define IPS_IS_MORPHEUS(ha) (ha->device_id == IPS_MORPHEUS_DEVICEID) + #define IPS_IS_MORPHEUS(ha) (ha->device_id == IPS_DEVICEID_MORPHEUS) #define IPS_USE_I2O_DELIVER(ha) ((IPS_IS_MORPHEUS(ha) || \ (IPS_IS_TROMBONE(ha) && \ (ips_force_i2o))) ? 1 : 0) @@ -99,23 +99,11 @@ #ifndef verify_area_20 #define verify_area_20(t,a,sz) (0) /* success */ #endif - - #ifndef PUT_USER - #define PUT_USER put_user - #endif - - #ifndef __PUT_USER - #define __PUT_USER __put_user - #endif - - #ifndef GET_USER - #define GET_USER get_user - #endif - #ifndef __GET_USER - #define __GET_USER __get_user + #ifndef DECLARE_MUTEX_LOCKED + #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED; #endif - + /* * Lock macros */ @@ -186,6 +174,7 @@ #define IPS_CMD_DCDB_SG 0x84 #define IPS_CMD_CONFIG_SYNC 0x58 #define IPS_CMD_ERROR_TABLE 0x17 + #define IPS_CMD_RW_BIOSFW 0x22 /* * Adapter Equates @@ -217,11 +206,16 @@ #define IPS_INTR_HAL 2 #define IPS_ADAPTER_ID 0xF #define IPS_VENDORID 0x1014 - #define IPS_COPPERHEAD_DEVICEID 0x002E - #define IPS_MORPHEUS_DEVICEID 0x01BD + #define IPS_DEVICEID_COPPERHEAD 0x002E + #define IPS_DEVICEID_MORPHEUS 0x01BD + #define IPS_SUBDEVICEID_4M 0x01BE + #define IPS_SUBDEVICEID_4L 0x01BF + #define IPS_SUBDEVICEID_4MX 0x0208 + #define IPS_SUBDEVICEID_4LX 0x020E #define IPS_IOCTL_SIZE 8192 #define IPS_STATUS_SIZE 4 #define IPS_STATUS_Q_SIZE (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE + #define IPS_IMAGE_SIZE 500 * 1024 #define IPS_MEMMAP_SIZE 128 #define IPS_ONE_MSEC 1 #define IPS_ONE_SEC 1000 @@ -285,6 +279,21 @@ #define IPS_REVID_TROMBONE64 0x10 /* + * NVRAM Page 5 Adapter Defines + */ + #define IPS_ADTYPE_SERVERAID 0x01 + #define IPS_ADTYPE_SERVERAID2 0x02 + #define IPS_ADTYPE_NAVAJO 0x03 + #define IPS_ADTYPE_KIOWA 0x04 + #define IPS_ADTYPE_SERVERAID3 0x05 + #define IPS_ADTYPE_SERVERAID3L 0x06 + #define IPS_ADTYPE_SERVERAID4H 0x07 + #define IPS_ADTYPE_SERVERAID4M 0x08 + #define IPS_ADTYPE_SERVERAID4L 0x09 + #define IPS_ADTYPE_SERVERAID4MX 0x0A + #define IPS_ADTYPE_SERVERAID4LX 0x0B + + /* * Adapter Command/Status Packet Definitions */ #define IPS_SUCCESS 0x01 /* Successfully completed */ @@ -538,17 +547,41 @@ u8 reserved2; } IPS_FFDC_CMD, *PIPS_FFDC_CMD; +typedef struct { + u8 op_code; + u8 command_id; + u8 type; + u8 direction; + u32 count; + u32 buffer_addr; + u8 total_packets; + u8 packet_num; + u16 reserved; +} IPS_FLASHFW_CMD, *PIPS_FLASHFW_CMD; + +typedef struct { + u8 op_code; + u8 command_id; + u8 type; + u8 direction; + u32 count; + u32 buffer_addr; + u32 offset; +} IPS_FLASHBIOS_CMD, *PIPS_FLASHBIOS_CMD; + typedef union { - IPS_IO_CMD basic_io; - IPS_LD_CMD logical_info; - IPS_IOCTL_CMD ioctl_info; - IPS_DCDB_CMD dcdb; - IPS_CS_CMD config_sync; - IPS_US_CMD unlock_stripe; - IPS_FC_CMD flush_cache; - IPS_STATUS_CMD status; - IPS_NVRAM_CMD nvram; - IPS_FFDC_CMD ffdc; + IPS_IO_CMD basic_io; + IPS_LD_CMD logical_info; + IPS_IOCTL_CMD ioctl_info; + IPS_DCDB_CMD dcdb; + IPS_CS_CMD config_sync; + IPS_US_CMD unlock_stripe; + IPS_FC_CMD flush_cache; + IPS_STATUS_CMD status; + IPS_NVRAM_CMD nvram; + IPS_FFDC_CMD ffdc; + IPS_FLASHFW_CMD flashfw; + IPS_FLASHBIOS_CMD flashbios; } IPS_HOST_COMMAND, *PIPS_HOST_COMMAND; typedef struct { @@ -839,6 +872,19 @@ int option_value; } IPS_OPTION; +typedef struct { + void *userbuffer; + u32 usersize; + void *kernbuffer; + u32 kernsize; + void *ha; + void *SC; + void *pt; + struct semaphore *sem; + u32 offset; + u32 retcode; +} IPS_FLASH_DATA; + /* * Status Info */ @@ -893,8 +939,8 @@ int (*isintr)(struct ips_ha *); int (*init)(struct ips_ha *); int (*erasebios)(struct ips_ha *); - int (*programbios)(struct ips_ha *, char *, int); - int (*verifybios)(struct ips_ha *, char *, int); + int (*programbios)(struct ips_ha *, char *, u32, u32); + int (*verifybios)(struct ips_ha *, char *, u32, u32); u32 (*statupd)(struct ips_ha *); void (*statinit)(struct ips_ha *); void (*intr)(struct ips_ha *); @@ -936,7 +982,11 @@ u32 last_ffdc; /* last time we sent ffdc info*/ u8 revision_id; /* Revision level */ u16 device_id; /* PCI device ID */ - u8 reserved; + u8 slot_num; /* PCI Slot Number */ + u16 subdevice_id; /* Subsystem device ID */ + u8 ioctl_order; /* Number of pages in ioctl */ + u8 reserved2; /* Empty */ + u8 bios_version[8]; /* BIOS Revision */ u32 mem_addr; /* Memory mapped address */ u32 io_len; /* Size of IO Address */ u32 mem_len; /* Size of memory address */ @@ -947,6 +997,9 @@ spinlock_t scb_lock; spinlock_t copp_lock; spinlock_t ips_lock; + char *save_ioctl_data; /* Save Area for ioctl_data */ + u8 save_ioctl_order; /* Save Area for ioctl_order */ + u32 save_ioctl_datasize;/* Save Area for ioctl_datasize */ } ips_ha_t; typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *); @@ -966,7 +1019,8 @@ u32 timeout; u8 basic_status; u8 extended_status; - u16 breakup; + u8 breakup; + u8 sg_break; u32 data_len; u32 sg_len; u32 flags; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.4/linux/drivers/scsi/pci2220i.c Fri Apr 27 13:59:19 2001 +++ linux/drivers/scsi/pci2220i.c Mon Apr 30 17:13:07 2001 @@ -2657,7 +2657,7 @@ for ( z = 0; z < BIGD_MAXDRIVES; z++ ) DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z); - scsi_set_pci_info(pshost, pcidev); + scsi_set_pci_device(pshost, pcidev); pshost->max_id = padapter->numberOfDrives; padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE); for ( z = 0; z < padapter->numberOfDrives; z++ ) diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c --- v2.4.4/linux/drivers/scsi/qlogicfas.c Wed Apr 11 19:02:37 2001 +++ linux/drivers/scsi/qlogicfas.c Tue May 22 10:23:16 2001 @@ -563,6 +563,7 @@ if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) ) break; + release_region(qbase, 0x10 ); } if (qbase == 0x430) return 0; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.4/linux/drivers/scsi/scsi.c Wed Apr 25 16:18:54 2001 +++ linux/drivers/scsi/scsi.c Thu May 24 15:34:14 2001 @@ -104,7 +104,7 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 16, 12, 10, 10 + 12, 12, 10, 10 }; static unsigned long serial_number; static Scsi_Cmnd *scsi_bh_queue_head; @@ -843,7 +843,7 @@ */ scsi_insert_special_req(SRpnt, 0); - SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_req()\n")); } /* @@ -929,7 +929,7 @@ SCpnt->abort_reason = 0; SCpnt->result = 0; - SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_init_cmd_from_req()\n")); } /* @@ -1572,6 +1572,11 @@ copy_from_user(buffer, buf, length); err = -EINVAL; + if (length < PAGE_SIZE) + buffer[length] ='\0'; + else if (buffer[length]) + goto out; + if (length < 11 || strncmp("scsi", buffer, 4)) goto out; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.4/linux/drivers/scsi/scsi_lib.c Fri Mar 2 18:38:39 2001 +++ linux/drivers/scsi/scsi_lib.c Fri May 4 15:16:28 2001 @@ -1108,9 +1108,13 @@ */ void scsi_unblock_requests(struct Scsi_Host * SHpnt) { + Scsi_Device *SDloop; + SHpnt->host_self_blocked = FALSE; + /* Now that we are unblocked, try to start the queues. */ + for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) + scsi_queue_next_request(&SDloop->request_queue, NULL); } - /* * Function: scsi_report_bus_reset() diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v2.4.4/linux/drivers/scsi/scsi_proc.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/scsi_proc.c Sat May 19 17:43:06 2001 @@ -104,7 +104,11 @@ if (!(page = (char *) __get_free_page(GFP_KERNEL))) return -ENOMEM; - copy_from_user(page, buf, count); + if(copy_from_user(page, buf, count)) + { + free_page((ulong) page); + return -EFAULT; + } if (hpnt->hostt->proc_info == NULL) ret = -ENOSYS; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.4/linux/drivers/scsi/sd.c Sat Feb 3 11:45:55 2001 +++ linux/drivers/scsi/sd.c Fri May 25 09:54:50 2001 @@ -993,8 +993,7 @@ the_result = SRpnt->sr_result; if (the_result) { - printk("%s: test WP failed, assume Write Protected\n", nbuff); - rscsi_disks[i].write_prot = 1; + printk("%s: test WP failed, assume Write Enabled\n", nbuff); } else { rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); printk("%s: Write Protect is %s\n", nbuff, @@ -1261,12 +1260,7 @@ for (i = max_p - 1; i >= 0; i--) { int index = start + i; - kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV_SD_PARTITION(index), 1); sd_gendisks->part[index].start_sect = 0; sd_gendisks->part[index].nr_sects = 0; /* @@ -1314,12 +1308,7 @@ for (j = max_p - 1; j >= 0; j--) { int index = start + j; - kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV_SD_PARTITION(index), 1); sd_gendisks->part[index].start_sect = 0; sd_gendisks->part[index].nr_sects = 0; sd_sizes[index] = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.4/linux/drivers/scsi/sr.c Mon Feb 19 10:25:17 2001 +++ linux/drivers/scsi/sr.c Sat Apr 28 11:28:08 2001 @@ -496,13 +496,6 @@ return 0; } -/* - * do_sr_request() is the request handler function for the sr driver. - * Its function in life is to take block device requests, and - * translate them to SCSI commands. - */ - - static int sr_detect(Scsi_Device * SDp) { @@ -869,16 +862,11 @@ for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) if (cpnt->device == SDp) { - kdev_t devi = MKDEV(MAJOR_NR, i); - struct super_block *sb = get_super(devi); - /* * Since the cdrom is read-only, no need to sync the device. * We should be kind to our buffer cache, however. */ - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR, i), 0); /* * Reset things back to a sane state so that one can re-load a new diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.4.4/linux/drivers/scsi/u14-34f.c Sun Feb 4 10:05:30 2001 +++ linux/drivers/scsi/u14-34f.c Sat May 19 17:43:06 2001 @@ -1,6 +1,9 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 1 May 2001 Rev. 6.05 for linux 2.4.4 + * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) + * * 25 Jan 2001 Rev. 6.03 for linux 2.4.0 * + "check_region" call replaced by "request_region". * @@ -1005,7 +1008,7 @@ static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b + 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d }; static const unsigned char data_none_cmds[] = { diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h --- v2.4.4/linux/drivers/scsi/u14-34f.h Sun Feb 4 10:05:30 2001 +++ linux/drivers/scsi/u14-34f.h Sat May 19 17:43:06 2001 @@ -13,7 +13,7 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "6.03.00" +#define U14_34F_VERSION "6.05.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -u --recursive --new-file v2.4.4/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c --- v2.4.4/linux/drivers/sound/cs4281/cs4281m.c Wed Apr 18 11:49:11 2001 +++ linux/drivers/sound/cs4281/cs4281m.c Tue May 1 16:05:00 2001 @@ -194,9 +194,6 @@ } \ }) -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - //LIST_HEAD(cs4281_devs); struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs }; diff -u --recursive --new-file v2.4.4/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.4/linux/drivers/sound/cs46xx.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/sound/cs46xx.c Thu May 24 15:14:08 2001 @@ -47,6 +47,9 @@ * 20010117-tw 2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0 * 20010118-tw basic PM support for 2.2.16+ and 2.4.0/2.4.2. * 20010228-dh patch from David Huggins - cs_update_ptr recursion. + * 20010409-tw add hercules game theatre XP amp code. + * 20010420-tw cleanup powerdown/up code. + * 20010521-tw eliminate pops, and fixes for powerdown. * * Status: * Playback/Capture supported from 8k-48k. @@ -56,9 +59,9 @@ * be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro * definition. * - * Hercules Game Pro XP - the EGPIO2 pin controls the external Amp, - * but the static image can not modify the EGPIO pins, so we can not - * turn on the external amp. + * Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp, + * so, use the drain/polarity to enable. + * hercules_egpio_disable set to 1, will force a 0 to EGPIODR. * * VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control * the external amplifier for the "back" speakers, since we do not @@ -109,6 +112,11 @@ #define CS_TRUE 1 #define CS_FALSE 0 +#define CS_INC_USE_COUNT(m) (atomic_inc(m)) +#define CS_DEC_USE_COUNT(m) (atomic_dec(m)) +#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m)) +#define CS_IN_USE(m) (atomic_read(m) != 0) + #define CS_DBGBREAKPOINT {__asm__("INT $3");} /* * CS461x definitions @@ -167,6 +175,8 @@ static unsigned long cs_debugmask=CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */ MODULE_PARM(cs_debugmask, "i"); #endif +static unsigned long hercules_egpio_disable=0; /* if non-zero set all EGPIO to 0 */ +MODULE_PARM(hercules_egpio_disable, "i"); static unsigned long initdelay=700; /* PM delay in millisecs */ MODULE_PARM(initdelay, "i"); static unsigned long powerdown=1; /* turn on/off powerdown processing in driver */ @@ -189,7 +199,7 @@ }; #define CS46XX_MAJOR_VERSION "1" -#define CS46XX_MINOR_VERSION "22" +#define CS46XX_MINOR_VERSION "27" #ifdef __ia64__ #define CS46XX_ARCH "64" //architecture key @@ -287,6 +297,9 @@ so we use a single per card lock */ spinlock_t lock; + /* mixer use count */ + atomic_t mixer_use_cnt; + /* PCI device stuff */ struct pci_dev * pci_dev; struct list_head list; @@ -358,6 +371,7 @@ static int cs_hardware_init(struct cs_card *card); static int cs46xx_powerup(struct cs_card *card, unsigned int type); static int cs461x_powerdown(struct cs_card *card, unsigned int type); +static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type); static inline unsigned ld2(unsigned int x) { @@ -667,6 +681,45 @@ dmabuf->divisor) ); } +/* +* mute some of the more prevalent registers to avoid popping. +*/ +static void cs_mute(struct cs_card *card, int state) +{ + struct ac97_codec *dev=card->ac97_codec[0]; + + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()+ %s\n", + (state == CS_TRUE) ? "Muting" : "UnMuting") ); + + if(state == CS_TRUE) + { + /* + * fix pops when powering up on thinkpads + */ + card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, + (u8)BA0_AC97_MASTER_VOLUME); + card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_HEADPHONE_VOLUME); + card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_MASTER_VOLUME_MONO); + card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_PCM_OUT_VOLUME); + + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000); + } + else + { + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume); + cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume); + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono); + cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume); + } + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()-\n")); +} + /* set playback sample rate */ static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate) { @@ -1386,12 +1439,17 @@ { DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card=state->card; unsigned long flags; unsigned long tmo; int count; + CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n")); if (dmabuf->mapped || !dmabuf->ready) + { + CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n")); return 0; + } add_wait_queue(&dmabuf->wait, &wait); for (;;) { @@ -1427,8 +1485,16 @@ remove_wait_queue(&dmabuf->wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) + { + CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n")); + /* + * set to silence and let that clear the fifos. + */ + cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC); return -ERESTARTSYS; + } + CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n")); return 0; } @@ -1524,7 +1590,7 @@ } if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - CS_DBGOUT(CS_ERROR, 2, printk( + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n", dmabuf->count)); /* @@ -1584,7 +1650,7 @@ struct cs_state *playstate = card->channel[1].state; u32 status; - CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()+ \n")); + CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n")); spin_lock(&card->lock); @@ -1614,7 +1680,7 @@ /* clear 'em */ cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); spin_unlock(&card->lock); - CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()- \n")); + CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n")); } @@ -2298,7 +2364,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_WRITE - state CS_TRUE prog_dmabuf DAC\n") ); + "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2307,7 +2373,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_READ - state CS_TRUE prog_dmabuf ADC\n") ); + "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2955,31 +3021,36 @@ } } + /* - * For the VTB Santa Cruz card, the Secondary Codec must have the - * GPIO pins 7 and 8 manipulated, not the Primary codec. - * Currently, only the primary codec is supported, so the following - * code will not function. Additionally, slot 12 must be setup - * to allow proper output for 7 and 8 to occur (trw). + * Game Theatre XP card - EGPIO[2] is used to enable the external amp. */ -static void amp_voyetra_4294(struct cs_card *card, int change) +static void amp_hercules(struct cs_card *card, int change) { - struct ac97_codec *c=card->ac97_codec[0]; - + int old=card->amplifier; + if(!card) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs46xx: amp_hercules() called before initialized.\n")); + return; + } card->amplifier+=change; - - if(card->amplifier) + if( (card->amplifier && !old) && !(hercules_egpio_disable)) { - /* Switch the GPIO pins 7 and 8 to open drain */ - cs_ac97_set(c, 0x4C, cs_ac97_get(c, 0x4C) & 0xFE7F); - cs_ac97_set(c, 0x4E, cs_ac97_get(c, 0x4E) | 0x0180); - /* Now wake the AMP (this might be backwards) */ - cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) & ~0x0180); + CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO + "cs46xx: amp_hercules() external amp enabled\n")); + cs461x_pokeBA0(card, BA0_EGPIODR, + EGPIODR_GPOE2); /* enable EGPIO2 output */ + cs461x_pokeBA0(card, BA0_EGPIOPTR, + EGPIOPTR_GPPT2); /* open-drain on output */ } - else + else if(old && !card->amplifier) { - cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) | 0x0180); + CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO + "cs46xx: amp_hercules() external amp disabled\n")); + cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */ + cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */ } } @@ -3016,7 +3087,7 @@ /* Flip CLKRUN off while running */ if(!card->active && old) { - CS_DBGOUT(CS_PARMS , 9, printk( + CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO "cs46xx: clkrun() enable clkrun - change=%d active=%d\n", change,card->active)); outw(control|0x2000, port+0x10); @@ -3026,7 +3097,7 @@ /* * sometimes on a resume the bit is set, so always reset the bit. */ - CS_DBGOUT(CS_PARMS , 9, printk( + CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO "cs46xx: clkrun() disable clkrun - change=%d active=%d\n", change,card->active)); outw(control&~0x2000, port+0x10); @@ -3404,7 +3475,7 @@ "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) ); } - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_suspend()-\n")); + CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n")); } /**************************************************************************** @@ -3417,7 +3488,7 @@ int Count,i; struct ac97_codec *dev=card->ac97_codec[0]; - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()+\n")); + CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n")); /* * First, we restore the state of the general purpose register. This @@ -3458,7 +3529,7 @@ if(card->amp_init) card->amp_init(card); - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()-\n")); + CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n")); } @@ -3521,7 +3592,7 @@ { unsigned int tmp; CS_DBGOUT(CS_PM | CS_FUNCTION, 4, - printk("cs46xx: cs46xx_suspend()+ flags=%d s=0x%x\n", + printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=0x%x\n", (unsigned)card->pm.flags,(unsigned)card)); /* * check the current state, only suspend if IDLE @@ -3604,7 +3675,7 @@ printpm(card); CS_DBGOUT(CS_PM | CS_FUNCTION, 4, - printk("cs46xx: cs46xx_suspend()- flags=%d\n", + printk("cs46xx: cs46xx_suspend()- flags=0x%x\n", (unsigned)card->pm.flags)); return 0; } @@ -3614,7 +3685,7 @@ int i; CS_DBGOUT(CS_PM | CS_FUNCTION, 4, - printk( "cs46xx: cs46xx_resume()+ flags=%d\n", + printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n", (unsigned)card->pm.flags)); if(!(card->pm.flags & CS46XX_PM_SUSPENDED)) { @@ -3654,7 +3725,7 @@ card->active_ctrl(card, -1); - CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=%d\n", + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n", (unsigned)card->pm.flags)); return 0; } @@ -3919,12 +3990,17 @@ file->private_data = card->ac97_codec[i]; card->active_ctrl(card,1); - if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) ) + if(!CS_IN_USE(&card->mixer_use_cnt)) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO - "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) ); - return -EIO; + if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) ); + return -EIO; + } } + card->amplifier_ctrl(card, 1); + CS_INC_USE_COUNT(&card->mixer_use_cnt); MOD_INC_USE_COUNT; CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n")); @@ -3938,8 +4014,9 @@ struct list_head *entry; int i; unsigned int tmp; - - + + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n")); list_for_each(entry, &cs46xx_devs) { card = list_entry(entry, struct cs_card, list); @@ -3955,14 +4032,26 @@ return -ENODEV; } match: + card->active_ctrl(card, -1); + card->amplifier_ctrl(card, -1); + MOD_DEC_USE_COUNT; + if(!CS_DEC_AND_TEST(&card->mixer_use_cnt)) + { + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n")); + return 0; + } +/* +* ok, no outstanding mixer opens, so powerdown. +*/ if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) ) { CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) ); return -EIO; } - card->active_ctrl(card, -1); - MOD_DEC_USE_COUNT; + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n")); return 0; } @@ -4027,7 +4116,7 @@ else { CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n", + "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n", val)); } return 0; @@ -4181,9 +4270,9 @@ cs461x_poke(card, BA1_FRMT, 0xadf); } -static void cs461x_clear_serial_FIFOs(struct cs_card *card) +static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type) { - int idx, loop, powerdown = 0; + int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0; unsigned int tmp; /* @@ -4192,7 +4281,7 @@ */ if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) { cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE); - powerdown = 1; + powerdown1 = 1; } /* @@ -4203,9 +4292,25 @@ cs461x_pokeBA0(card, BA0_SERBWP, 0); /* - * Fill all 256 sample FIFO locations. + * Check for which FIFO locations to clear, if we are currently + * playing or capturing then we don't want to put in 128 bytes of + * "noise". + */ + if(type & CS_TYPE_DAC) + { + startfifo = 128; + endfifo = 256; + } + if(type & CS_TYPE_ADC) + { + startfifo = 0; + if(!endfifo) + endfifo = 128; + } + /* + * Fill sample FIFO locations (256 locations total). */ - for (idx = 0; idx < 256; idx++) { + for (idx = startfifo; idx < endfifo; idx++) { /* * Make sure the previous FIFO write operation has completed. */ @@ -4215,7 +4320,7 @@ break; } if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) { - if (powerdown) + if (powerdown1) cs461x_pokeBA0(card, BA0_CLKCR1, tmp); } /* @@ -4231,7 +4336,7 @@ * Now, if we powered up the devices, then power them back down again. * This is kinda ugly, but should never happen. */ - if (powerdown) + if (powerdown1) cs461x_pokeBA0(card, BA0_CLKCR1, tmp); } @@ -4268,6 +4373,15 @@ "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp)); return 0; } +/* +* for now, always keep power to the mixer block. +* not sure why it's a problem but it seems to be if we power off. +*/ + type &= ~CS_POWER_MIXVON; + type &= ~CS_POWER_MIXVOFF; + + cs_mute(card, CS_TRUE); + /* * Power down indicated areas. */ @@ -4443,6 +4557,7 @@ } } tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + cs_mute(card, CS_FALSE); CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp)); return 0; @@ -4462,6 +4577,8 @@ type |= CS_POWER_MIXVOFF; if(type & (CS_POWER_DAC | CS_POWER_ADC)) type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF; + + cs_mute(card, CS_TRUE); /* * Power up indicated areas. */ @@ -4637,6 +4754,7 @@ } } tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + cs_mute(card, CS_FALSE); CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp)); return 0; @@ -4741,7 +4859,6 @@ */ if(!(card->pm.flags & CS46XX_PM_IDLE)) mdelay(initdelay); - /* * Write the selected clock control setup to the hardware. Do not turn on * SWCE yet (if requested), so that the devices clocked by the output of @@ -4770,7 +4887,7 @@ /* * Fill the serial port FIFOs with silence. */ - cs461x_clear_serial_FIFOs(card); + cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC); /* * Set the serial port FIFO pointer to the first sample in the FIFO. @@ -4951,12 +5068,25 @@ */ if(card->pm.flags & CS46XX_PM_IDLE) { - if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | - CS_POWER_MIXVON )) ) + if(!powerdown) { - CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO - "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); - return -EIO; + if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) ); + return -EIO; + } + } + else + { + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); + return -EIO; + } } } CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO @@ -4964,11 +5094,9 @@ return 0; } - /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ - /* * Card subid table */ @@ -4987,8 +5115,12 @@ {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL}, {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL, NULL}, {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL}, - {0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, - {0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, + {0x14AF, 0x0050, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0x0050, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0x0051, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0x0052, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0x0053, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0x0054, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, /* Not sure if the 570 needs the clkrun hack */ {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack}, {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack}, @@ -5016,6 +5148,11 @@ CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO "cs46xx: probe()+\n")); + if (pci_enable_device(pci_dev)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs46xx: pci_enable_device() failed\n")); + return -1; + } if (!RSRCISMEMORYREGION(pci_dev, 0) || !RSRCISMEMORYREGION(pci_dev, 1)) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR @@ -5042,12 +5179,6 @@ return -ENOMEM; } memset(card, 0, sizeof(*card)); - - if (pci_enable_device(pci_dev)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs46xx: pci_enable_device() failed\n")); - goto fail2; - } card->ba0_addr = RSRCADDRESS(pci_dev, 0); card->ba1_addr = RSRCADDRESS(pci_dev, 1); card->pci_dev = pci_dev; @@ -5096,7 +5227,7 @@ card->amplifier_ctrl = amp_none; card->active_ctrl = clkrun_hack; } - + if (external_amp == 1) { printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n"); @@ -5120,7 +5251,7 @@ card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO - "cs46xx: card->ba0=0x%.08x\n",(unsigned)card->ba0) ); + "cs46xx: card=0x%x card->ba0=0x%.08x\n",(unsigned)card,(unsigned)card->ba0) ); CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO "cs46xx: card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n", (unsigned)card->ba1.name.data0, @@ -5319,9 +5450,9 @@ unregister_sound_dsp(card->dev_audio); if(card->dev_midi) unregister_sound_midi(card->dev_midi); + list_del(&card->list); kfree(card); PCI_SET_DRIVER_DATA(pci_dev,NULL); - list_del(&card->list); CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs46xx_remove()-: remove successful\n")); @@ -5329,8 +5460,8 @@ enum { CS46XX_4610 = 0, - CS46XX_4612, /* same as 4624 */ - CS46XX_4615, /* same as 4630 */ + CS46XX_4612, /* same as 4630 */ + CS46XX_4615, /* same as 4624 */ }; static struct pci_device_id cs46xx_pci_tbl[] __devinitdata = { diff -u --recursive --new-file v2.4.4/linux/drivers/sound/emu10k1/cardwo.c linux/drivers/sound/emu10k1/cardwo.c --- v2.4.4/linux/drivers/sound/emu10k1/cardwo.c Mon Aug 14 08:32:48 2000 +++ linux/drivers/sound/emu10k1/cardwo.c Sat May 19 17:43:07 2001 @@ -87,7 +87,8 @@ pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; - ((u32 *) card->virtualpagetable.addr)[pageindex] = (busaddx * 2) | pageindex; + ((u32 *) card->virtualpagetable.addr)[pageindex] = + cpu_to_le32((busaddx * 2) | pageindex); } } diff -u --recursive --new-file v2.4.4/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.4.4/linux/drivers/sound/emu10k1/main.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/sound/emu10k1/main.c Sat May 19 17:43:07 2001 @@ -475,7 +475,8 @@ } for (pagecount = 0; pagecount < MAXPAGES; pagecount++) - ((u32 *) card->virtualpagetable.addr)[pagecount] = (card->silentpage.dma_handle * 2) | pagecount; + ((u32 *) card->virtualpagetable.addr)[pagecount] = + cpu_to_le32((card->silentpage.dma_handle * 2) | pagecount); /* Init page table & tank memory base register */ sblive_writeptr_tag(card, 0, @@ -612,6 +613,10 @@ { struct emu10k1_card *card; u32 subsysvid; + int ret; + + if ((ret=pci_enable_device(pci_dev))) + return ret; if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "emu10k1: out of memory\n"); @@ -621,11 +626,6 @@ if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) { printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); - kfree(card); - return -ENODEV; - } - - if (pci_enable_device(pci_dev)) { kfree(card); return -ENODEV; } diff -u --recursive --new-file v2.4.4/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c --- v2.4.4/linux/drivers/sound/emu10k1/midi.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/sound/emu10k1/midi.c Sat May 19 17:43:07 2001 @@ -56,7 +56,7 @@ { struct midi_hdr *midihdr; - if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) { + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) { ERROR(); return -EINVAL; } @@ -328,7 +328,7 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) return -EINVAL; midihdr->bufferlength = count; diff -u --recursive --new-file v2.4.4/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.4/linux/drivers/sound/es1370.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/sound/es1370.c Tue May 22 10:23:16 2001 @@ -2560,19 +2560,21 @@ { SOUND_MIXER_WRITE_OGAIN, 0x4040 } }; -#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ - pci_resource_flags((dev), (num)) & IORESOURCE_IO) - static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1370_state *s; mm_segment_t fs; - int i, val; + int i, val, ret; + + if ((ret=pci_enable_device(pcidev))) + return ret; - if (!RSRCISIOREGION(pcidev, 0)) - return -1; + if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) || + !pci_resource_start(pcidev, 0) + ) + return -ENODEV; if (pcidev->irq == 0) - return -1; + return -ENODEV; i = pci_set_dma_mask(pcidev, 0xffffffff); if (i) { printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); @@ -2580,7 +2582,7 @@ } if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { printk(KERN_WARNING "es1370: out of memory\n"); - return -1; + return -ENOMEM; } memset(s, 0, sizeof(struct es1370_state)); init_waitqueue_head(&s->dma_adc.wait); @@ -2597,14 +2599,14 @@ s->irq = pcidev->irq; if (!request_region(s->io, ES1370_EXTENT, "es1370")) { printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); + ret = -EBUSY; goto err_region; } - if (pci_enable_device(pcidev)) - goto err_irq; - if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) { + if ((ret=request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370",s))) { printk(KERN_ERR "es1370: irq %u in use\n", s->irq); goto err_irq; } + /* initialize codec registers */ /* note: setting CTRL_SERR_DIS is reported to break * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ @@ -2631,14 +2633,22 @@ (s->ctrl & CTRL_XCTL0) ? "out" : "in", (s->ctrl & CTRL_XCTL1) ? "1" : "0"); /* register devices */ - if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) + if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) { + ret = s->dev_audio; goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) + } + if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) { + ret = s->dev_mixer; goto err_dev2; - if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) + } + if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) { + ret = s->dev_dac; goto err_dev3; - if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) + } + if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) { + ret = s->dev_midi; goto err_dev4; + } /* initialize the chips */ outl(s->ctrl, s->io+ES1370_REG_CONTROL); outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); @@ -2688,7 +2698,7 @@ release_region(s->io, ES1370_EXTENT); err_region: kfree(s); - return -1; + return ret; } static void __devinit es1370_remove(struct pci_dev *dev) diff -u --recursive --new-file v2.4.4/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.4/linux/drivers/sound/es1371.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/sound/es1371.c Tue May 22 10:23:16 2001 @@ -2771,22 +2771,22 @@ { SOUND_MIXER_WRITE_IGAIN, 0x4040 } }; -#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ - (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) - static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1371_state *s; mm_segment_t fs; - int i, val; + int i, val, res = -1; unsigned long tmo; signed long tmo2; unsigned int cssr; - if (!RSRCISIOREGION(pcidev, 0)) - return -1; + if ((res=pci_enable_device(pcidev))) + return res; + + if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO)) + return -ENODEV; if (pcidev->irq == 0) - return -1; + return -ENODEV; i = pci_set_dma_mask(pcidev, 0xffffffff); if (i) { printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); @@ -2794,7 +2794,7 @@ } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { printk(KERN_WARNING PFX "out of memory\n"); - return -1; + return -ENOMEM; } memset(s, 0, sizeof(struct es1371_state)); init_waitqueue_head(&s->dma_adc.wait); @@ -2820,24 +2820,23 @@ s->vendor, s->device, s->rev); if (!request_region(s->io, ES1371_EXTENT, "es1371")) { printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); + res = -EBUSY; goto err_region; } - if (pci_enable_device(pcidev)) - goto err_irq; - if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { + if ((res=request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371",s))) { printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; } printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n" KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); /* register devices */ - if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) + if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1))<0)) goto err_dev1; - if ((s->codec.dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0) + if ((res=(s->codec.dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)) goto err_dev2; - if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0) + if ((res=(s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0)) goto err_dev3; - if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0) + if ((res=(s->dev_midi = register_sound_midi(&es1371_midi_fops, -1))<0 )) goto err_dev4; #ifdef ES1371_DEBUG /* intialize the debug proc device */ @@ -2916,8 +2915,10 @@ /* init the sample rate converter */ src_init(s); /* codec init */ - if (!ac97_probe_codec(&s->codec)) + if (!ac97_probe_codec(&s->codec)) { + res = -ENODEV; goto err_gp; + } /* set default values */ fs = get_fs(); @@ -2964,7 +2965,7 @@ release_region(s->io, ES1371_EXTENT); err_region: kfree(s); - return -1; + return res; } static void __devinit es1371_remove(struct pci_dev *dev) diff -u --recursive --new-file v2.4.4/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.4/linux/drivers/sound/esssolo1.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/sound/esssolo1.c Tue May 22 10:23:16 2001 @@ -77,6 +77,8 @@ * Fix SETTRIGGER non OSS API conformity * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro * for abs. Bug report by Andrew Morton + * 15.05.2001 pci_enable_device moved, return values in probe cleaned + * up. Marcus Meissner */ /*****************************************************************************/ @@ -128,17 +130,6 @@ /* --------------------------------------------------------------------- */ -/* prevent picking up a bogus abs macro */ -#undef abs -extern inline int abs(int x) -{ - if (x < 0) - return -x; - return x; -} - -/* --------------------------------------------------------------------- */ - #ifndef PCI_VENDOR_ID_ESS #define PCI_VENDOR_ID_ESS 0x125d #endif @@ -2288,22 +2279,21 @@ return 0; } - -#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ - (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) - static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; struct pm_dev *pmdev; + int ret; - if (!RSRCISIOREGION(pcidev, 0) || - !RSRCISIOREGION(pcidev, 1) || - !RSRCISIOREGION(pcidev, 2) || - !RSRCISIOREGION(pcidev, 3)) - return -1; + if ((ret=pci_enable_device(pcidev))) + return ret; + if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) || + !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) || + !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) || + !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO)) + return -ENODEV; if (pcidev->irq == 0) - return -1; + return -ENODEV; /* Recording requires 24-bit DMA, so attempt to set dma mask * to 24 bits first, then 32 bits (playback only) if that fails. @@ -2311,12 +2301,12 @@ if (pci_set_dma_mask(pcidev, 0x00ffffff) && pci_set_dma_mask(pcidev, 0xffffffff)) { printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); - return -1; + return -ENODEV; } if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { printk(KERN_WARNING "solo1: out of memory\n"); - return -1; + return -ENOMEM; } memset(s, 0, sizeof(struct solo1_state)); init_waitqueue_head(&s->dma_adc.wait); @@ -2336,6 +2326,7 @@ s->gameport.io = pci_resource_start(pcidev, 4); s->gameport.size = pci_resource_len(pcidev,4); s->irq = pcidev->irq; + ret = -EBUSY; if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { printk(KERN_ERR "solo1: io ports in use\n"); goto err_region1; @@ -2358,24 +2349,32 @@ printk(KERN_ERR "solo1: gameport io ports in use\n"); s->gameport.io = s->gameport.size = 0; } - if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { + if ((ret=request_irq(s->irq,solo1_interrupt,SA_SHIRQ,"ESS Solo1",s))) { printk(KERN_ERR "solo1: irq %u in use\n", s->irq); goto err_irq; } - if (pci_enable_device(pcidev)) - goto err_irq; printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1); /* register devices */ - if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) + if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) { + ret = s->dev_audio; goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) + } + if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) { + ret = s->dev_mixer; goto err_dev2; - if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) + } + if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) { + ret = s->dev_midi; goto err_dev3; - if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) + } + if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) { + ret = s->dev_dmfm; goto err_dev4; - if (setup_solo1(s)) + } + if (setup_solo1(s)) { + ret = -EIO; goto err; + } /* register gameport */ gameport_register_port(&s->gameport); /* store it in the driver field */ @@ -2412,7 +2411,7 @@ release_region(s->mpubase, MPUBASE_EXTENT); err_region1: kfree(s); - return -1; + return ret; } static void __devinit solo1_remove(struct pci_dev *dev) diff -u --recursive --new-file v2.4.4/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.4/linux/drivers/sound/i810_audio.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/sound/i810_audio.c Sat May 19 17:43:07 2001 @@ -96,6 +96,9 @@ #ifndef PCI_DEVICE_ID_INTEL_ICH2 #define PCI_DEVICE_ID_INTEL_ICH2 0x2445 #endif +#ifndef PCI_DEVICE_ID_INTEL_ICH3 +#define PCI_DEVICE_ID_INTEL_ICH3 0x2485 +#endif #ifndef PCI_DEVICE_ID_INTEL_440MX #define PCI_DEVICE_ID_INTEL_440MX 0x7195 #endif @@ -210,13 +213,15 @@ ICH82901AB, INTEL440MX, INTELICH2, + INTELICH3 }; static char * card_names[] = { "Intel ICH 82801AA", "Intel ICH 82901AB", "Intel 440MX", - "Intel ICH2" + "Intel ICH2", + "Intel ICH3" }; static struct pci_device_id i810_pci_tbl [] __initdata = { @@ -228,6 +233,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3}, {0,} }; @@ -1520,7 +1527,9 @@ val = 16384; if (val > 65536) val = 65536; - dmabuf->ossfragsize = val/dmabuf->ossmaxfrags; + dmabuf->ossmaxfrags = val/dmabuf->ossfragsize; + if(dmabuf->ossmaxfrags<4) + dmabuf->ossfragsize = val/4; dmabuf->ready = 0; #ifdef DEBUG printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, diff -u --recursive --new-file v2.4.4/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.4/linux/drivers/sound/nm256_audio.c Sat Nov 11 18:33:14 2000 +++ linux/drivers/sound/nm256_audio.c Tue May 1 16:05:00 2001 @@ -15,6 +15,8 @@ * Changes: * 11-10-2000 Bartlomiej Zolnierkiewicz * Added some __init + * 19-04-2001 Marcus Meissner + * Ported to 2.4 PCI API. */ #define __NO_VERSION__ @@ -49,8 +51,6 @@ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) - /* List of cards. */ static struct nm256_info *nmcard_list; @@ -1042,6 +1042,9 @@ struct pm_dev *pmdev; int x; + if (pci_enable_device(pcidev)) + return 0; + card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL); if (card == NULL) { printk (KERN_ERR "NM256: out of memory!\n"); @@ -1055,7 +1058,7 @@ /* Init the memory port info. */ for (x = 0; x < 2; x++) { - card->port[x].physaddr = RSRCADDRESS (pcidev, x); + card->port[x].physaddr = pci_resource_start (pcidev, x); card->port[x].ptr = NULL; card->port[x].start_offset = 0; card->port[x].end_offset = 0; @@ -1201,6 +1204,8 @@ } } + pci_set_drvdata(pcidev,card); + /* Insert the card in the list. */ card->next_card = nmcard_list; nmcard_list = card; @@ -1251,37 +1256,38 @@ return 0; } -/* - * This loop walks the PCI configuration database and finds where - * the sound cards are. - */ - -int __init -init_nm256(void) +static int __devinit +nm256_probe(struct pci_dev *pcidev,const struct pci_device_id *pciid) { - struct pci_dev *pcidev = NULL; - int count = 0; - - if(! pci_present()) - return -ENODEV; - - while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC, - PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, - pcidev)) != NULL) { - count += nm256_install(pcidev, REV_NM256AV, "256AV"); - } - - while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC, - PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, - pcidev)) != NULL) { - count += nm256_install(pcidev, REV_NM256ZX, "256ZX"); + if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO) + return nm256_install(pcidev, REV_NM256AV, "256AV"); + if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO) + return nm256_install(pcidev, REV_NM256ZX, "256ZX"); + return -1; /* should not come here ... */ +} + +static void __devinit +nm256_remove(struct pci_dev *pcidev) { + struct nm256_info *xcard = pci_get_drvdata(pcidev); + struct nm256_info *card,*next_card = NULL; + + for (card = nmcard_list; card != NULL; card = next_card) { + next_card = card->next_card; + if (card == xcard) { + stopPlay (card); + stopRecord (card); + if (card->has_irq) + free_irq (card->irq, card); + nm256_release_ports (card); + sound_unload_mixerdev (card->mixer_oss_dev); + sound_unload_audiodev (card->dev[0]); + sound_unload_audiodev (card->dev[1]); + kfree (card); + break; + } } - - if (count == 0) - return -ENODEV; - - printk (KERN_INFO "Done installing NM256 audio driver.\n"); - return 0; + if (nmcard_list == card) + nmcard_list = next_card; } /* @@ -1639,9 +1645,21 @@ local_qlen: nm256_audio_local_qlen, }; -EXPORT_SYMBOL(init_nm256); +static struct pci_device_id nm256_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0}, + {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, nm256_pci_tbl); -static int loaded = 0; +struct pci_driver nm256_pci_driver = { + name:"nm256_audio", + id_table:nm256_pci_tbl, + probe:nm256_probe, + remove:nm256_remove, +}; MODULE_PARM (usecache, "i"); MODULE_PARM (buffertop, "i"); @@ -1650,37 +1668,13 @@ static int __init do_init_nm256(void) { - nmcard_list = NULL; - printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); - - if (init_nm256 () == 0) { - loaded = 1; - return 0; - } - else - return -ENODEV; + printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n"); + return pci_module_init(&nm256_pci_driver); } static void __exit cleanup_nm256 (void) { - if (loaded) { - struct nm256_info *card; - struct nm256_info *next_card; - - for (card = nmcard_list; card != NULL; card = next_card) { - stopPlay (card); - stopRecord (card); - if (card->has_irq) - free_irq (card->irq, card); - nm256_release_ports (card); - sound_unload_mixerdev (card->mixer_oss_dev); - sound_unload_audiodev (card->dev[0]); - sound_unload_audiodev (card->dev[1]); - next_card = card->next_card; - kfree (card); - } - nmcard_list = NULL; - } + pci_unregister_driver(&nm256_pci_driver); pm_unregister_all (&handle_pm_event); } diff -u --recursive --new-file v2.4.4/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.4.4/linux/drivers/sound/sb_card.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/sb_card.c Tue May 22 10:23:16 2001 @@ -338,6 +338,16 @@ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, {"Sound Blaster AWE 32", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), @@ -531,6 +541,9 @@ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 }, { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 }, + + { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 }, { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), diff -u --recursive --new-file v2.4.4/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.4/linux/drivers/sound/trident.c Fri Apr 6 10:51:19 2001 +++ linux/drivers/sound/trident.c Sat May 19 17:43:10 2001 @@ -732,7 +732,7 @@ struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; - channel->lba = virt_to_bus(dmabuf->rawbuf); + channel->lba = dmabuf->dma_handle; channel->delta = compute_rate_play(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; @@ -808,7 +808,7 @@ return; } - channel->lba = virt_to_bus(dmabuf->rawbuf); + channel->lba = dmabuf->dma_handle; channel->delta = compute_rate_rec(dmabuf->rate); if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) { rate = ali_get_spdif_in_rate(card); @@ -1074,14 +1074,21 @@ } } else { - if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) - dmabuf->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order); + if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) { + dmabuf->rawbuf = pci_alloc_consistent(state->card->pci_dev, + PAGE_SIZE << order, + &dmabuf->dma_handle); + } if (!dmabuf->rawbuf) { free_pages((unsigned long)state->dmabuf.rawbuf, state->dmabuf.buforder); state->dmabuf.rawbuf = NULL; i-=2; - for (; i >= 0; i--) - free_pages((unsigned long)state->other_states[i]->dmabuf.rawbuf, state->other_states[i]->dmabuf.buforder); + for (; i >= 0; i--) { + pci_free_consistent(state->card->pci_dev, + PAGE_SIZE << state->other_states[i]->dmabuf.buforder, + state->other_states[i]->dmabuf.rawbuf, + state->other_states[i]->dmabuf.dma_handle); + } unlock_set_fmt(state); return -ENOMEM; } @@ -1967,9 +1974,9 @@ case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && dmabuf->enable) + if ((file->f_mode & FMODE_READ) && dmabuf->enable) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable) + if ((file->f_mode & FMODE_WRITE) && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); @@ -3157,20 +3164,34 @@ { struct trident_card *card = (struct trident_card *)data; unsigned long flags; + char c; + + if (count<0) + return -EINVAL; + if (count == 0) + return 0; + if (get_user(c, buffer)) + return -EFAULT; spin_lock_irqsave(&card->lock, flags); - if (*buffer == '0') { //default + switch (c) { + case '0': ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); - } - else if (*buffer == '1') + break; + case '1': ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_PCM); - else if (*buffer == '2') //AC3 data + break; + case '2': ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_NON_PCM); - else if (*buffer == '3') + break; + case '3': ali_disable_spdif_in(card); //default - else if (*buffer == '4') + break; + case '4': ali_setup_spdif_in(card); + break; + } spin_unlock_irqrestore(&card->lock, flags); return count; @@ -3307,11 +3328,23 @@ { unsigned long iobase; struct trident_card *card; + dma_addr_t mask; + int bits; u8 revision; - if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) { + if (pci_enable_device(pci_dev)) + return -ENODEV; + + if (pci_dev->device == PCI_DEVICE_ID_ALI_5451) { + mask = 0xffffffff; + bits = 32; + } else { + mask = TRIDENT_DMA_MASK; + bits = 30; + } + if (pci_set_dma_mask(pci_dev, mask)) { printk(KERN_ERR "trident: architecture does not support" - " 30bit PCI busmaster DMA\n"); + " %dbit PCI busmaster DMA\n", bits); return -ENODEV; } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); @@ -3322,9 +3355,6 @@ iobase); return -ENODEV; } - - if (pci_enable_device(pci_dev)) - return -ENODEV; if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); diff -u --recursive --new-file v2.4.4/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.4/linux/drivers/sound/via82cxxx_audio.c Fri Mar 2 11:02:15 2001 +++ linux/drivers/sound/via82cxxx_audio.c Tue May 1 16:05:00 2001 @@ -3020,6 +3020,11 @@ if (printed_version++ == 0) printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n"); + if (pci_enable_device (pdev)) { + rc = -EIO; + goto err_out_none; + } + if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), VIA_MODULE_NAME)) { @@ -3028,10 +3033,6 @@ goto err_out; } - if (pci_enable_device (pdev)) { - rc = -EIO; - goto err_out_none; - } card = kmalloc (sizeof (*card), GFP_KERNEL); if (!card) { diff -u --recursive --new-file v2.4.4/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.4.4/linux/drivers/sound/wavfront.c Fri Mar 2 11:12:11 2001 +++ linux/drivers/sound/wavfront.c Thu May 24 15:14:08 2001 @@ -131,7 +131,7 @@ #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ static int (*midi_load_patch) (int devno, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ /* if WF_DEBUG not defined, no run-time debugging messages will be available via the debug flag setting. Given the current @@ -279,7 +279,7 @@ int fx_mididev; /* devno for FX MIDI interface */ #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ int oss_dev; /* devno for OSS sequencer synth */ -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ char fw_version[2]; /* major = [0], minor = [1] */ char hw_version[2]; /* major = [0], minor = [1] */ @@ -2139,7 +2139,7 @@ bender: midi_synth_bender, setup_voice: midi_synth_setup_voice }; -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL @@ -2158,7 +2158,7 @@ (void) uninstall_wavefront (); } -#endif OSS_SUPPORT_STATIC_INSTALL +#endif /* OSS_SUPPORT_STATIC_INSTALL */ /***********************************************************************/ /* WaveFront: Linux modular sound kernel installation interface */ @@ -2674,7 +2674,7 @@ &wavefront_oss_load_patch; } -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ /* Turn on Virtual MIDI, but first *always* turn it off, since otherwise consectutive reloads of the driver will @@ -2852,14 +2852,14 @@ } else { synth_devs[dev.oss_dev] = &wavefront_operations; } -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ if (wavefront_init (1) < 0) { printk (KERN_WARNING LOGNAME "initialization failed.\n"); #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ sound_unload_synthdev (dev.oss_dev); -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ return -1; } @@ -2890,7 +2890,7 @@ #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ sound_unload_synthdev (dev.oss_dev); -#endif OSS_SUPPORT_SEQ +#endif /* OSS_SUPPORT_SEQ */ uninstall_wf_mpu (); } diff -u --recursive --new-file v2.4.4/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.4.4/linux/drivers/sound/ymfpci.c Thu Apr 26 22:17:27 2001 +++ linux/drivers/sound/ymfpci.c Sat May 19 17:47:55 2001 @@ -989,11 +989,6 @@ status = ymfpci_readl(codec, YDSXGR_STATUS); if (status & 0x80000000) { - spin_lock(&codec->reg_lock); - ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); - mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; - ymfpci_writel(codec, YDSXGR_MODE, mode); - spin_unlock(&codec->reg_lock); codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1; spin_lock(&codec->voice_lock); for (nvoice = 0; nvoice < 64; nvoice++) { @@ -1007,6 +1002,11 @@ ymf_cap_interrupt(codec, cap); } spin_unlock(&codec->voice_lock); + spin_lock(&codec->reg_lock); + ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); + mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; + ymfpci_writel(codec, YDSXGR_MODE, mode); + spin_unlock(&codec->reg_lock); } status = ymfpci_readl(codec, YDSXGR_INTFLAG); @@ -2059,9 +2059,10 @@ } if (mpuio >= 0 || oplio >= 0) { - v = 0x003e; + /* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */ + v = 0x001e; pci_write_config_word(pcidev, PCIR_LEGCTRL, v); - + switch (pcidev->device) { case PCI_DEVICE_ID_YAMAHA_724: case PCI_DEVICE_ID_YAMAHA_740: @@ -2106,6 +2107,8 @@ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); } + pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0); + pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0); } static void ymfpci_enable_dsp(ymfpci_t *codec) diff -u --recursive --new-file v2.4.4/linux/drivers/sound/ymfpci.h linux/drivers/sound/ymfpci.h --- v2.4.4/linux/drivers/sound/ymfpci.h Fri Jan 26 23:31:16 2001 +++ linux/drivers/sound/ymfpci.h Tue May 15 11:16:26 2001 @@ -135,6 +135,8 @@ #define PCIR_LEGCTRL 0x40 #define PCIR_ELEGCTRL 0x42 #define PCIR_DSXGCTRL 0x48 +#define PCIR_DSXPWRCTRL1 0x4a +#define PCIR_DSXPWRCTRL2 0x4e #define PCIR_OPLADR 0x60 #define PCIR_SBADR 0x62 #define PCIR_MPUADR 0x64 diff -u --recursive --new-file v2.4.4/linux/drivers/sound/yss225.h linux/drivers/sound/yss225.h --- v2.4.4/linux/drivers/sound/yss225.h Sat Jul 18 14:11:41 1998 +++ linux/drivers/sound/yss225.h Thu May 24 15:14:08 2001 @@ -20,5 +20,5 @@ extern unsigned char coefficients3[404]; -#endif __ys225_h__ +#endif /* __ys225_h__ */ diff -u --recursive --new-file v2.4.4/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c --- v2.4.4/linux/drivers/telephony/ixj.c Fri Mar 2 18:38:39 2001 +++ linux/drivers/telephony/ixj.c Sat May 19 17:47:55 2001 @@ -4434,7 +4434,8 @@ lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL); if (lcp == NULL) return -ENOMEM; - if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE))) + if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)) || + (unsigned)lcp->elements_used >= ~0U/sizeof(IXJ_CADENCE) ) { kfree(lcp); return -EFAULT; @@ -4475,7 +4476,7 @@ { IXJ_FILTER_CADENCE *lcp; - lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL); + lcp = kmalloc(sizeof(IXJ_FILTER_CADENCE), GFP_KERNEL); if (lcp == NULL) return -ENOMEM; if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE))) diff -u --recursive --new-file v2.4.4/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.4.4/linux/drivers/usb/Config.in Mon Nov 27 18:10:35 2000 +++ linux/drivers/usb/Config.in Tue May 22 10:25:36 2001 @@ -32,6 +32,7 @@ if [ "$CONFIG_USB_STORAGE" != "n" ]; then bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG bool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM + bool ' Microtech CompactFlash/SmartMedia reader' CONFIG_USB_STORAGE_DPCM fi dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB @@ -57,6 +58,7 @@ comment 'USB Multimedia devices' dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB diff -u --recursive --new-file v2.4.4/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.4.4/linux/drivers/usb/Makefile Fri Dec 29 14:07:23 2000 +++ linux/drivers/usb/Makefile Fri May 25 09:48:50 2001 @@ -17,6 +17,14 @@ list-multi := usbcore.o usbcore-objs := usb.o usb-debug.o hub.o +ifneq ($(CONFIG_USB_PWC),n) + export-objs += pwc-uncompress.o + list-multi += pwc.o +endif + +pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o + + # Optional parts of multipart objects. ifeq ($(CONFIG_USB_DEVICEFS),y) @@ -47,6 +55,7 @@ obj-$(CONFIG_USB_PRINTER) += printer.o obj-$(CONFIG_USB_AUDIO) += audio.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o +obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_DC2XX) += dc2xx.o obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_USS720) += uss720.o @@ -79,4 +88,7 @@ usbcore.o: $(usbcore-objs) $(LD) -r -o $@ $(usbcore-objs) + +pwc.o: $(pwc-objs) + $(LD) -r -o $@ $(pwc-objs) diff -u --recursive --new-file v2.4.4/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.4.4/linux/drivers/usb/acm.c Fri Feb 16 16:06:17 2001 +++ linux/drivers/usb/acm.c Mon May 21 15:02:06 2001 @@ -55,6 +55,13 @@ #include /* + * Version Information + */ +#define DRIVER_VERSION "v0.18" +#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik" +#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" + +/* * CMSPAR, some architectures can't have space and mark parity. */ @@ -233,8 +240,14 @@ dbg("nonzero read bulk status received: %d", urb->status); if (!urb->status & !acm->throttle) { - for (i = 0; i < urb->actual_length && !acm->throttle; i++) + for (i = 0; i < urb->actual_length && !acm->throttle; i++) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, + * we drop them. */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } tty_insert_flip_char(tty, data[i], 0); + } tty_flip_buffer_push(tty); } @@ -304,6 +317,10 @@ acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS); + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates data can get lost. */ + tty->low_latency = 1; + return 0; } @@ -692,6 +709,9 @@ return -1; } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -704,5 +724,6 @@ module_init(acm_init); module_exit(acm_exit); -MODULE_AUTHOR("Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"); -MODULE_DESCRIPTION("USB Abstract Control Model driver for USB modems and ISDN adapters"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.4.4/linux/drivers/usb/audio.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/audio.c Mon May 21 15:02:06 2001 @@ -92,6 +92,8 @@ * 2000-11-26: Thomas Sailer * Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for * its 8 bit modes, but expects signed data (and should therefore have used PCM). + * 2001-04-08: gb + * Identify version on module load. * */ @@ -190,6 +192,13 @@ #include "audio.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Alan Cox , Thomas Sailer (sailer@ife.ee.ethz.ch)" +#define DRIVER_DESC "USB Audio Class driver" + #define AUDIO_DEBUG 1 #define SND_DEV_DSP16 5 @@ -3746,6 +3755,8 @@ static int __init usb_audio_init(void) { usb_register(&usb_audio_driver); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -3758,6 +3769,6 @@ module_init(usb_audio_init); module_exit(usb_audio_cleanup); -MODULE_AUTHOR("Alan Cox , Thomas Sailer (sailer@ife.ee.ethz.ch)"); -MODULE_DESCRIPTION("USB Audio Class driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c --- v2.4.4/linux/drivers/usb/bluetooth.c Mon Mar 19 17:21:54 2001 +++ linux/drivers/usb/bluetooth.c Mon May 21 15:02:06 2001 @@ -5,6 +5,9 @@ * Copyright (c) 2000 Mark Douglas Corner * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B + * + * (08/04/2001) gb + * Identify version on module load. * * (2001/03/10) Version 0.8 gkh * Fixed problem with not unlinking interrupt urb on device close @@ -91,9 +94,12 @@ #define DEBUG #include -/* Module information */ -MODULE_AUTHOR("Greg Kroah-Hartman, Mark Douglas Corner"); -MODULE_DESCRIPTION("USB Bluetooth driver"); +/* + * Version Information + */ +#define DRIVER_VERSION "v0.8" +#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner" +#define DRIVER_DESC "USB Bluetooth driver" /* define this if you have hardware that is not good */ /*#define BTBUGGYHARDWARE */ @@ -1280,6 +1286,9 @@ return -1; } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -1294,4 +1303,7 @@ module_init(usb_bluetooth_init); module_exit(usb_bluetooth_exit); +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- v2.4.4/linux/drivers/usb/dabusb.c Thu Jan 4 13:15:32 2001 +++ linux/drivers/usb/dabusb.c Mon May 21 15:02:06 2001 @@ -43,6 +43,13 @@ #include "dabusb.h" #include "dabfirmware.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.54" +#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" +#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" + /* --------------------------------------------------------------------- */ #define NRDABUSB 4 @@ -829,6 +836,10 @@ return -1; dbg("dabusb_init: driver registered"); + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -841,8 +852,9 @@ /* --------------------------------------------------------------------- */ -MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de"); -MODULE_DESCRIPTION ("DAB-USB Interface Driver for Linux (c)1999"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + MODULE_PARM (buffers, "i"); MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.4.4/linux/drivers/usb/dc2xx.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/usb/dc2xx.c Thu May 24 14:55:51 2001 @@ -46,6 +46,7 @@ * 12 Aug, 2000 .. add some real locking, remove an Oops * 10 Oct, 2000 .. usb_device_id table created. * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter + * 08 Apr, 2001 .. Identify version on module load. gb * * Thanks to: the folk who've provided USB product IDs, sent in * patches, and shared their successes! @@ -71,6 +72,13 @@ #include +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "David Brownell, " +#define DRIVER_DESC "USB Camera Driver for Kodak DC-2xx series cameras" + /* current USB framework handles max of 16 USB devices per driver */ #define MAX_CAMERAS 16 @@ -328,8 +336,9 @@ if (!camera->dev) { minor_data [subminor] = NULL; kfree (camera); - } - up (&camera->sem); + } else + up (&camera->sem); + up (&state_table_mutex); dbg ("close #%d", subminor); @@ -389,7 +398,6 @@ } if (i >= MAX_CAMERAS) { info ("Ignoring additional USB Camera"); - up (&state_table_mutex); goto bye; } @@ -397,7 +405,6 @@ camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL); if (!camera) { err ("no memory!"); - up (&state_table_mutex); goto bye; } @@ -464,13 +471,15 @@ if (!camera->buf) { minor_data [subminor] = NULL; kfree (camera); + camera = NULL; } else camera->dev = NULL; info ("USB Camera #%d disconnected", subminor); usb_dec_dev_use (dev); - up (&camera->sem); + if (camera != NULL) + up (&camera->sem); up (&state_table_mutex); } @@ -490,6 +499,8 @@ { if (usb_register (&camera_driver) < 0) return -1; + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -498,9 +509,9 @@ usb_deregister (&camera_driver); } - -MODULE_AUTHOR("David Brownell, "); -MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras"); - module_init (usb_dc2xx_init); module_exit (usb_dc2xx_cleanup); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c --- v2.4.4/linux/drivers/usb/dsbr100.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/dsbr100.c Mon May 21 15:02:06 2001 @@ -65,6 +65,13 @@ #include #include +/* + * Version Information + */ +#define DRIVER_VERSION "v0.24" +#define DRIVER_AUTHOR "Markus Demleitner " +#define DRIVER_DESC "D-Link DSB-R100 USB radio driver" + #define DSB100_VENDOR 0x04b4 #define DSB100_PRODUCT 0x1002 @@ -100,6 +107,7 @@ }; static int users = 0; +static int radio_nr = -1; static struct usb_device_id usb_dsbr100_table [] = { { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, @@ -330,10 +338,12 @@ { usb_dsbr100_radio.priv = NULL; usb_register(&usb_dsbr100_driver); - if (video_register_device(&usb_dsbr100_radio,VFL_TYPE_RADIO)==-1) { + if (video_register_device(&usb_dsbr100_radio,VFL_TYPE_RADIO,radio_nr)==-1) { warn("couldn't register video device"); return -EINVAL; } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -350,8 +360,8 @@ module_init (dsbr100_init); module_exit (dsbr100_exit); -MODULE_AUTHOR("Markus Demleitner "); -MODULE_DESCRIPTION("D-Link DSB-R100 USB radio driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); /* vi: ts=8 diff -u --recursive --new-file v2.4.4/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.4.4/linux/drivers/usb/hid.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/usb/hid.c Mon May 21 15:02:06 2001 @@ -54,6 +54,13 @@ #define hid_dump_device(c) do { } while (0) #endif +/* + * Version Information + */ +#define DRIVER_VERSION "v1.16" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " +#define DRIVER_DESC "USB HID support drivers" + #define unk KEY_UNKNOWN static unsigned char hid_keyboard[256] = { @@ -1552,6 +1559,8 @@ static int __init hid_init(void) { usb_register(&hid_driver); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -1563,5 +1572,6 @@ module_init(hid_init); module_exit(hid_exit); -MODULE_AUTHOR("Andreas Gal, Vojtech Pavlik "); -MODULE_DESCRIPTION("USB HID support drivers"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c --- v2.4.4/linux/drivers/usb/ibmcam.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/ibmcam.c Thu May 24 14:55:51 2001 @@ -43,9 +43,18 @@ #include "ibmcam.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "http://www.linux-usb.org/ibmcam/" +#define DRIVER_DESC "IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000" + #define ENABLE_HEXDUMP 0 /* Enable if you need it */ static int debug = 0; +static int video_nr = -1; + /* Completion states of the data parser */ typedef enum { scan_Continue, /* Just parse next item */ @@ -159,9 +168,6 @@ MODULE_PARM(init_model2_yb, "i"); MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); -MODULE_AUTHOR ("module author"); -MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); - /* Still mysterious i2c commands */ static const unsigned short unknown_88 = 0x0088; static const unsigned short unknown_89 = 0x0089; @@ -3032,7 +3038,7 @@ usb_ibmcam_configure_video(ibmcam); up (&ibmcam->lock); - if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) { + if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { printk(KERN_ERR "video_register_device failed\n"); ibmcam = NULL; /* Do not free, it's preallocated */ } @@ -3141,6 +3147,8 @@ struct usb_ibmcam *ibmcam = &cams[u]; memset (ibmcam, 0, sizeof(struct usb_ibmcam)); } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return usb_register(&ibmcam_driver); } @@ -3151,5 +3159,8 @@ module_init(usb_ibmcam_init); module_exit(usb_ibmcam_cleanup); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.4.4/linux/drivers/usb/inode.c Fri Mar 2 13:47:21 2001 +++ linux/drivers/usb/inode.c Tue May 22 10:25:36 2001 @@ -43,6 +43,11 @@ /* --------------------------------------------------------------------- */ +/* + * This list of superblocks is still used, + * but since usbdevfs became FS_SINGLE + * there is only one super_block. + */ static LIST_HEAD(superlist); struct special { @@ -159,6 +164,97 @@ iput(inode); } +static int parse_options(struct super_block *s, char *data) +{ + uid_t devuid = 0, busuid = 0, listuid = 0; + gid_t devgid = 0, busgid = 0, listgid = 0; + umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO; + char *curopt = NULL, *value; + + /* parse options */ + if (data) + curopt = strtok(data, ","); + for (; curopt; curopt = strtok(NULL, ",")) { + if ((value = strchr(curopt, '=')) != NULL) + *value++ = 0; + if (!strcmp(curopt, "devuid")) { + if (!value || !value[0]) + return -EINVAL; + devuid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "devgid")) { + if (!value || !value[0]) + return -EINVAL; + devgid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "devmode")) { + if (!value || !value[0]) + return -EINVAL; + devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "busuid")) { + if (!value || !value[0]) + return -EINVAL; + busuid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "busgid")) { + if (!value || !value[0]) + return -EINVAL; + busgid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "busmode")) { + if (!value || !value[0]) + return -EINVAL; + busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "listuid")) { + if (!value || !value[0]) + return -EINVAL; + listuid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "listgid")) { + if (!value || !value[0]) + return -EINVAL; + listgid = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + if (!strcmp(curopt, "listmode")) { + if (!value || !value[0]) + return -EINVAL; + listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; + if (*value) + return -EINVAL; + } + } + + s->u.usbdevfs_sb.devuid = devuid; + s->u.usbdevfs_sb.devgid = devgid; + s->u.usbdevfs_sb.devmode = devmode; + s->u.usbdevfs_sb.busuid = busuid; + s->u.usbdevfs_sb.busgid = busgid; + s->u.usbdevfs_sb.busmode = busmode; + s->u.usbdevfs_sb.listuid = listuid; + s->u.usbdevfs_sb.listgid = listgid; + s->u.usbdevfs_sb.listmode = listmode; + + return 0; +} + static struct usb_bus *usbdevfs_findbus(int busnr) { struct list_head *list; @@ -460,10 +556,47 @@ return 0; } +static int usbdevfs_remount(struct super_block *s, int *flags, char *data) +{ + struct list_head *ilist = s->u.usbdevfs_sb.ilist.next; + struct inode *inode; + int ret; + + if ((ret = parse_options(s, data))) { + printk(KERN_WARNING "usbdevfs: remount parameter error\n"); + return ret; + } + + for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) { + inode = list_entry(ilist, struct inode, u.usbdev_i.slist); + + switch (ITYPE(inode->i_ino)) { + case ISPECIAL : + inode->i_uid = s->u.usbdevfs_sb.listuid; + inode->i_gid = s->u.usbdevfs_sb.listgid; + inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; + break; + case IBUS : + inode->i_uid = s->u.usbdevfs_sb.busuid; + inode->i_gid = s->u.usbdevfs_sb.busgid; + inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR; + break; + case IDEVICE : + inode->i_uid = s->u.usbdevfs_sb.devuid; + inode->i_gid = s->u.usbdevfs_sb.devgid; + inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG; + break; + } + } + + return 0; +} + static struct super_operations usbdevfs_sops = { read_inode: usbdevfs_read_inode, put_super: usbdevfs_put_super, statfs: usbdevfs_statfs, + remount_fs: usbdevfs_remount, }; struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) @@ -472,81 +605,12 @@ struct list_head *blist; struct usb_bus *bus; unsigned int i; - uid_t devuid = 0, busuid = 0, listuid = 0; - gid_t devgid = 0, busgid = 0, listgid = 0; - umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO; - char *curopt = NULL, *value; - /* parse options */ - if (data) - curopt = strtok(data, ","); - for (; curopt; curopt = strtok(NULL, ",")) { - if ((value = strchr(curopt, '=')) != NULL) - *value++ = 0; - if (!strcmp(curopt, "devuid")) { - if (!value || !value[0]) - goto opterr; - devuid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "devgid")) { - if (!value || !value[0]) - goto opterr; - devgid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "devmode")) { - if (!value || !value[0]) - goto opterr; - devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; - if (*value) - goto opterr; - } - if (!strcmp(curopt, "busuid")) { - if (!value || !value[0]) - goto opterr; - busuid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "busgid")) { - if (!value || !value[0]) - goto opterr; - busgid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "busmode")) { - if (!value || !value[0]) - goto opterr; - busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; - if (*value) - goto opterr; - } - if (!strcmp(curopt, "listuid")) { - if (!value || !value[0]) - goto opterr; - listuid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "listgid")) { - if (!value || !value[0]) - goto opterr; - listgid = simple_strtoul(value, &value, 0); - if (*value) - goto opterr; - } - if (!strcmp(curopt, "listmode")) { - if (!value || !value[0]) - goto opterr; - listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; - if (*value) - goto opterr; - } + if (parse_options(s, data)) { + printk(KERN_WARNING "usbdevfs: mount parameter error\n"); + return NULL; } + /* fill superblock */ s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -554,12 +618,6 @@ s->s_op = &usbdevfs_sops; INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist); INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist); - s->u.usbdevfs_sb.devuid = devuid; - s->u.usbdevfs_sb.devgid = devgid; - s->u.usbdevfs_sb.devmode = devmode; - s->u.usbdevfs_sb.busuid = busuid; - s->u.usbdevfs_sb.busgid = busgid; - s->u.usbdevfs_sb.busmode = busmode; root_inode = iget(s, IROOT); if (!root_inode) goto out_no_root; @@ -570,9 +628,9 @@ for (i = 0; i < NRSPECIAL; i++) { if (!(inode = iget(s, IROOT+1+i))) continue; - inode->i_uid = listuid; - inode->i_gid = listgid; - inode->i_mode = listmode | S_IFREG; + inode->i_uid = s->u.usbdevfs_sb.listuid; + inode->i_gid = s->u.usbdevfs_sb.listgid; + inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; special[i].inode = inode; list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes); @@ -590,10 +648,6 @@ printk("usbdevfs_read_super: get root inode failed\n"); iput(root_inode); return NULL; - - opterr: - printk(KERN_WARNING "usbdevfs: mount parameter error\n"); - return NULL; } static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE); @@ -689,8 +743,10 @@ } if ((ret = usb_register(&usbdevfs_driver))) return ret; - if ((ret = register_filesystem(&usbdevice_fs_type))) + if ((ret = register_filesystem(&usbdevice_fs_type))) { usb_deregister(&usbdevfs_driver); + return ret; + } kern_mount(&usbdevice_fs_type); #ifdef CONFIG_PROC_FS /* create mount point for usbdevfs */ diff -u --recursive --new-file v2.4.4/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- v2.4.4/linux/drivers/usb/mdc800.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/mdc800.c Mon May 21 15:02:06 2001 @@ -29,6 +29,9 @@ * mknod /dev/mustek c 180 32 * * The driver supports only one camera. + * + * (08/04/2001) gb + * Identify version on module load. * * version 0.7.5 * Fixed potential SMP races with Spinlocks. @@ -90,8 +93,12 @@ #include -#define VERSION "0.7.5" -#define RELEASE_DATE "(30/10/2000)" +/* + * Version Information + */ +#define DRIVER_VERSION "v0.7.5 (30/10/2000)" +#define DRIVER_AUTHOR "Henning Zabel " +#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera" /* Vendor and Product Information */ #define MDC800_VENDOR_ID 0x055f @@ -925,8 +932,8 @@ if (usb_register (&mdc800_usb_driver) < 0) goto cleanup_on_fail; - info ("Mustek Digital Camera Driver " VERSION " (MDC800)"); - info (RELEASE_DATE " Henning Zabel "); + info (DRIVER_VERSION " " DRIVER_AUTHOR); + info (DRIVER_DESC); return 0; @@ -969,9 +976,9 @@ mdc800=0; } - -MODULE_AUTHOR ("Henning Zabel "); -MODULE_DESCRIPTION ("USB Driver for Mustek MDC800 Digital Camera"); - module_init (usb_mdc800_init); module_exit (usb_mdc800_cleanup); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c --- v2.4.4/linux/drivers/usb/microtek.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/microtek.c Mon May 21 15:02:06 2001 @@ -115,6 +115,7 @@ * 20010311 Remove all timeouts and tidy up generally (john) * 20010320 check return value of scsi_register() * 20010320 Version 0.4.3 + * 20010408 Identify version on module load. */ #include @@ -139,6 +140,13 @@ #include "microtek.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v0.4.3" +#define DRIVER_AUTHOR "John Fremlin , Oliver Neukum " +#define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver" + /* Should we do debugging? */ //#define MTS_DO_DEBUG @@ -1021,6 +1029,9 @@ MTS_DEBUG("driver registered.\n"); } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -1050,5 +1061,6 @@ module_init(microtek_drv_init); module_exit(microtek_drv_exit); -MODULE_AUTHOR("John Fremlin , Oliver Neukum "); -MODULE_DESCRIPTION("Microtek Scanmaker X6 USB scanner driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/net1080.c linux/drivers/usb/net1080.c --- v2.4.4/linux/drivers/usb/net1080.c Thu Jan 4 13:15:32 2001 +++ linux/drivers/usb/net1080.c Mon May 21 15:02:06 2001 @@ -34,6 +34,9 @@ * 01-nov-2000 * usb_device_id table support added by Adam J. Richter . * + * 08-apr-2001 gb + * Identify version on module load. + * *-------------------------------------------------------------------------*/ #include @@ -55,6 +58,13 @@ #endif #include +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "David Brownell " +#define DRIVER_DESC "NetChip 1080 Driver (USB Host-to-Host Link)" + static const struct usb_device_id products [] = { // reference design @@ -1101,6 +1111,9 @@ get_random_bytes (node_id, sizeof node_id); node_id [0] &= 0x7f; + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } module_init (net1080_init); @@ -1111,5 +1124,6 @@ } module_exit (net1080_exit); -MODULE_AUTHOR ("David Brownell "); -MODULE_DESCRIPTION ("NetChip 1080 Driver (USB Host-to-Host Link)"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.4.4/linux/drivers/usb/ov511.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/usb/ov511.c Thu May 24 15:24:37 2001 @@ -30,8 +30,6 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.28"; - #define __NO_VERSION__ #include @@ -51,6 +49,13 @@ #include "ov511.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.28" +#define DRIVER_AUTHOR "Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka " +#define DRIVER_DESC "OV511 USB Camera Driver" + #define OV511_I2C_RETRIES 3 /* Video Size 640 x 480 x 3 bytes for RGB */ @@ -62,6 +67,8 @@ /* PARAMETER VARIABLES: */ static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */ +static int video_nr = -1; + /* 0=no debug messages * 1=init/detection/unload and other significant messages, * 2=some warning messages @@ -146,8 +153,8 @@ MODULE_PARM(dumppix, "i"); MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details"); -MODULE_AUTHOR("Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka "); -MODULE_DESCRIPTION("OV511 USB Camera Driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); static struct usb_driver ov511_driver; @@ -3139,7 +3146,7 @@ init_waitqueue_head(&ov511->wq); - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) < 0) { + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { err("video_register_device failed"); return -EBUSY; } @@ -3419,7 +3426,8 @@ if (usb_register(&ov511_driver) < 0) return -1; - info("ov511 driver version %s registered", version); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.4.4/linux/drivers/usb/pegasus.c Sun Mar 18 19:54:52 2001 +++ linux/drivers/usb/pegasus.c Mon May 21 15:02:06 2001 @@ -50,13 +50,16 @@ #include #include "pegasus.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v0.4.18 2001/03/18 (C) 1999-2000" +#define DRIVER_AUTHOR "Petko Manolov " +#define DRIVER_DESC "ADMtek AN986 Pegasus USB Ethernet driver" #define PEGASUS_USE_INTR #define PEGASUS_WRITE_EEPROM -static const char *version = __FILE__ ": v0.4.18 2001/03/18 (C) 1999-2000 Petko Manolov (petkan@dce.bg)"; - - static int loopback = 0; static int mii_mode = 0; static int multicast_filter_limit = 32; @@ -78,8 +81,8 @@ }; -MODULE_AUTHOR("Petko Manolov "); -MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(loopback, "i"); MODULE_PARM(mii_mode, "i"); MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); @@ -902,7 +905,8 @@ int __init pegasus_init(void) { - info( "%s", version ); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return usb_register( &pegasus_driver ); } diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h --- v2.4.4/linux/drivers/usb/pegasus.h Tue Nov 14 12:57:50 2000 +++ linux/drivers/usb/pegasus.h Mon May 21 17:04:24 2001 @@ -127,7 +127,7 @@ __u32 private; /* LSB is gpio reset value */ }; - +#define VENDOR_3COM 0x0506 #define VENDOR_ACCTON 0x083a #define VENDOR_ADMTEK 0x07a6 #define VENDOR_BILLIONTON 0x08dd @@ -138,13 +138,14 @@ #define VENDOR_LANEED 0x056e #define VENDOR_LINKSYS 0x066b #define VENDOR_MELCO 0x0411 +#define VENDOR_SMARTBRIDGES 0x08d1 #define VENDOR_SMC 0x0707 #define VENDOR_SOHOWARE 0x15e8 - #else /* PEGASUS_DEV */ - +PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", @@ -175,6 +176,8 @@ DEFAULT_GPIO_RESET ) PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "FiberLine USB", VENDOR_DLINK2, 0x4102, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, @@ -189,10 +192,11 @@ LINKSYS_GPIO_RESET ) PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, DEFAULT_GPIO_RESET ) - #endif /* PEGASUS_DEV */ diff -u --recursive --new-file v2.4.4/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c --- v2.4.4/linux/drivers/usb/plusb.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/usb/plusb.c Mon May 21 15:02:06 2001 @@ -140,6 +140,13 @@ #define dev_kfree_skb_any dev_kfree_skb #endif +/* + * Version Information + */ +#define DRIVER_VERSION "v0.5.7" +#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" +#define DRIVER_DESC "PL-2302 USB Interface Driver for Linux (c)2000" + /* Definitions formerly in plusb.h relocated. No need to export them -EZA */ #define _PLUSB_INTPIPE 0x1 @@ -1007,6 +1014,9 @@ dbg("plusb_init: driver registered"); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -1041,8 +1051,8 @@ /* --------------------------------------------------------------------- */ -MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de"); -MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); module_init (plusb_init); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.4.4/linux/drivers/usb/printer.c Fri Mar 2 17:50:22 2001 +++ linux/drivers/usb/printer.c Mon May 21 15:02:06 2001 @@ -50,6 +50,13 @@ #undef DEBUG #include +/* + * Version Information + */ +#define DRIVER_VERSION "v0.8" +#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap" +#define DRIVER_DESC "USB Printer Device Class driver" + #define USBLP_BUF_SIZE 8192 #define DEVICE_ID_SIZE 1024 @@ -655,6 +662,8 @@ { if (usb_register(&usblp_driver)) return -1; + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -666,5 +675,6 @@ module_init(usblp_init); module_exit(usblp_exit); -MODULE_AUTHOR("Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap"); -MODULE_DESCRIPTION("USB Printer Device Class driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-ctrl.c linux/drivers/usb/pwc-ctrl.c --- v2.4.4/linux/drivers/usb/pwc-ctrl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-ctrl.c Fri May 25 09:48:50 2001 @@ -0,0 +1,935 @@ +/* Driver for Philips webcam + Functions that send various control messages to the webcam, including + video modes. + (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + + 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 +*/ + +/* Control functions for the cam; brightness, contrast, video mode, etc. */ + +#ifdef __KERNEL__ +#include +#endif +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-uncompress.h" + +/* Request types: video */ +#define SET_LUM_CTL 0x01 +#define GET_LUM_CTL 0x02 +#define SET_CHROM_CTL 0x03 +#define GET_CHROM_CTL 0x04 +#define SET_STATUS_CTL 0x05 +#define GET_STATUS_CTL 0x06 +#define SET_EP_STREAM_CTL 0x07 +#define GET_EP_STREAM_CTL 0x08 + +/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ +#define AGC_MODE_FORMATTER 0x2000 +#define PRESET_AGC_FORMATTER 0x2100 +#define SHUTTER_MODE_FORMATTER 0x2200 +#define PRESET_SHUTTER_FORMATTER 0x2300 +#define PRESET_CONTOUR_FORMATTER 0x2400 +#define AUTO_CONTOUR_FORMATTER 0x2500 +#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 +#define CONTRAST_FORMATTER 0x2700 +#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 +#define FLICKERLESS_MODE_FORMATTER 0x2900 +#define AE_CONTROL_SPEED 0x2A00 +#define BRIGHTNESS_FORMATTER 0x2B00 +#define GAMMA_FORMATTER 0x2C00 + +/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ +#define WB_MODE_FORMATTER 0x1000 +#define AWB_CONTROL_SPEED_FORMATTER 0x1100 +#define AWB_CONTROL_DELAY_FORMATTER 0x1200 +#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 +#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 +#define COLOUR_MODE_FORMATTER 0x1500 +#define SATURATION_MODE_FORMATTER1 0x1600 +#define SATURATION_MODE_FORMATTER2 0x1700 + +/* Selectors for the Status controls [GS]ET_STATUS_CTL */ +#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 +#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 +#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 +#define READ_AGC_FORMATTER 0x0500 +#define READ_SHUTTER_FORMATTER 0x0600 +#define READ_RED_GAIN_FORMATTER 0x0700 +#define READ_BLUE_GAIN_FORMATTER 0x0800 +#define READ_RAW_Y_MEAN_FORMATTER 0x3100 +#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 +#define MIRROR_IMAGE_FORMATTER 0x3300 +#define LED_FORMATTER 0x3400 + +/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ +#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 + +static char *size2name[PSZ_MAX] = +{ + "subQCIF", + "QSIF", + "QCIF", + "SIF", + "CIF", + "VGA", +}; + +/********/ + +/* Entries for the Nala (645/646) camera; the Nala doesn't have compression + preferences, so you either get compressed or non-compressed streams. + + An alternate value of 0 means this mode is not available at all. + */ + +struct Nala_table_entry { + char alternate; /* USB alternate setting */ + int compressed; /* Compressed yes/no */ + + unsigned char mode[3]; /* precomputed mode table */ +}; + +static struct Nala_table_entry Nala_table[PSZ_MAX][8] = +{ +#include "pwc_nala.h" +}; + +/* This tables contains entries for the 675/680/690 (Timon) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be choosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ +struct Timon_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[13]; /* precomputed mode settings for cam */ +}; + +static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = +{ +#include "pwc_timon.h" +}; + +/* Entries for the Kiara (730/740) camera */ + +struct Kiara_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[12]; /* precomputed mode settings for cam */ +}; + +static struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = +{ +#include "pwc_kiara.h" +}; + + +/****************************************************************************/ + + + + +#if PWC_DEBUG +void pwc_hexdump(void *p, int len) +{ + int i; + unsigned char *s; + char buf[100], *d; + + s = (unsigned char *)p; + d = buf; + *d = '\0'; + Debug("Doing hexdump @ %p, %d bytes.\n", p, len); + for (i = 0; i < len; i++) { + d += sprintf(d, "%02X ", *s++); + if ((i & 0xF) == 0xF) { + Debug("%s\n", buf); + d = buf; + *d = '\0'; + } + } + if ((i & 0xF) != 0) + Debug("%s\n", buf); +} +#endif + +static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) +{ + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, + index, + buf, buflen, HZ); +} + + + +static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) +{ + unsigned char buf[3]; + int ret, fps; + struct Nala_table_entry *pEntry; + int frames2frames[31] = + { /* closest match of framerate */ + 0, 0, 0, 0, 4, /* 0-4 */ + 5, 5, 7, 7, 10, /* 5-9 */ + 10, 10, 12, 12, 15, /* 10-14 */ + 15, 15, 15, 20, 20, /* 15-19 */ + 20, 20, 20, 24, 24, /* 20-24 */ + 24, 24, 24, 24, 24, /* 25-29 */ + 24 /* 30 */ + }; + int frames2table[31] = + { 0, 0, 0, 0, 0, /* 0-4 */ + 1, 1, 1, 2, 2, /* 5-9 */ + 3, 3, 4, 4, 4, /* 10-14 */ + 5, 5, 5, 5, 5, /* 15-19 */ + 6, 6, 6, 6, 7, /* 20-24 */ + 7, 7, 7, 7, 7, /* 25-29 */ + 7 /* 30 */ + }; + + if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) + return -EINVAL; + frames = frames2frames[frames]; + fps = frames2table[frames]; + pEntry = &Nala_table[size][fps]; + if (pEntry->alternate == 0) + return -EINVAL; + + if (pEntry->compressed && pdev->decompressor == NULL) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pEntry->mode, 3); + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); + if (ret < 0) + return ret; + if (pEntry->compressed) + ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data); + if (ret < 0) + return ret; + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->valternate = pEntry->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; + if (pEntry->compressed) { + if (pdev->release < 5) { /* 4 fold compression */ + pdev->vbandlength = 528; + pdev->frame_size /= 4; + } + else { + pdev->vbandlength = 704; + pdev->frame_size /= 3; + } + } + else + pdev->vbandlength = 0; + return 0; +} + + +static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + unsigned char buf[13]; + struct Timon_table_entry *pChoose; + int ret, fps; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + */ + pChoose = NULL; + if (pdev->decompressor == NULL) { +#if PWC_DEBUG + Debug("Trying to find uncompressed mode.\n"); +#endif + pChoose = &Timon_table[size][fps][0]; + } + else { + while (compression <= 3) { + pChoose = &Timon_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pChoose->mode, 13); + if (snapshot) + buf[0] |= 0x80; + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0) + ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data); + if (ret < 0) + return ret; + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pChoose->bandlength > 0) + pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + return 0; +} + + +static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + struct Kiara_table_entry *pChoose; + int fps, ret; + unsigned char buf[12]; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + */ + pChoose = NULL; + if (pdev->decompressor == NULL) { +#if PWC_DEBUG + Debug("Trying to find uncompressed mode.\n"); +#endif + pChoose = &Kiara_table[size][fps][0]; + } + else { + while (compression <= 3) { + pChoose = &Kiara_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + /* usb_control_msg won't take staticly allocated arrays as argument?? */ + memcpy(buf, pChoose->mode, 12); + if (snapshot) + buf[0] |= 0x80; + + /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ + ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0) + ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data); + if (ret < 0) + return ret; + + /* All set and go */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pChoose->bandlength > 0) + pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + pdev->frame_size += (pdev->frame_header_size + pdev->frame_trailer_size); + return 0; +} + + +/** + @pdev: device structure + @width: viewport width + @height: viewport height + @frame: framerate, in fps + @compression: preferred compression ratio + @snapshot: snapshot mode or streaming + */ +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) +{ + int ret, size; + + size = pwc_decode_size(pdev, width, height); + if (size < 0) { + Debug("Could not find suitable size.\n"); + return -ERANGE; + } + ret = -EINVAL; + switch(pdev->type) { + case 645: + case 646: + ret = set_video_mode_Nala(pdev, size, frames); + break; + + case 675: + case 680: + case 690: + ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + break; + + case 730: + case 740: + ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); + break; + } + if (ret < 0) { + if (ret == -ENOENT) + Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); + else { + Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); + return ret; + } + } + /* If the video mode was not supported, we still adjust the view size, + since xawtv (Again! Stupid program...) doesn't care zit about + return values. + */ + pdev->view.x = width; + pdev->view.y = height; + pwc_set_image_buffer_size(pdev); + Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d. Palette = %d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y, pdev->vpalette); + return 0; +} + + +void pwc_set_image_buffer_size(struct pwc_device *pdev) +{ + int factor, i, filler = 0; + + switch(pdev->vpalette) { + case VIDEO_PALETTE_RGB32 | 0x80: + case VIDEO_PALETTE_RGB32: + factor = 16; + filler = 0; + break; + case VIDEO_PALETTE_RGB24 | 0x80: + case VIDEO_PALETTE_RGB24: + factor = 12; + filler = 0; + break; + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_YUV422: + factor = 8; + filler = 128; + break; + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV420P: + factor = 6; + filler = 128; + break; +#if PWC_DEBUG + case VIDEO_PALETTE_RAW: + pdev->image.size = pdev->frame_size; + pdev->view.size = pdev->frame_size; + return; + break; +#endif + default: + factor = 0; + break; + } + + /* Set sizes in bytes */ + pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; + pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; + + pdev->offset.x = (pdev->view.x - pdev->image.x) / 2; + pdev->offset.y = (pdev->view.y - pdev->image.y) / 2; + if (pdev->vpalette == VIDEO_PALETTE_YUV420 || pdev->vpalette == VIDEO_PALETTE_YUV420P) { + /* Align offset, or you'll get some very weird results in + YUV mode... x must be multiple of 4 (to get the Y's in + place), and y even (or you'll mixup U & V). + */ + pdev->offset.x &= 0xFFFC; + pdev->offset.y &= 0xFFFE; + /* This is the offset in the Y area, hence no factor */ + pdev->offset.size = (pdev->offset.y * pdev->view.x + pdev->offset.x); + } + else + pdev->offset.size = (pdev->offset.y * pdev->view.x + pdev->offset.x) * factor / 4; + + /* Set buffers to gray */ + for (i = 0; i < MAX_IMAGES; i++) { + if (pdev->image_ptr[i] != NULL) + memset(pdev->image_ptr[i], filler, pdev->view.size); + } +} + + +#ifdef __KERNEL__ +/* BRIGHTNESS */ + +int pwc_get_brightness(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + BRIGHTNESS_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return buf << 9; +} + +int pwc_set_brightness(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 9) & 0x7f; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + BRIGHTNESS_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +/* CONTRAST */ + +int pwc_get_contrast(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + CONTRAST_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return buf << 10; +} + +int pwc_set_contrast(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3f; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + CONTRAST_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +/* GAMMA */ + +int pwc_get_gamma(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + GAMMA_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return buf << 11; +} + +int pwc_set_gamma(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 11) & 0x1f; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + GAMMA_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + + +/* SATURATION */ + +int pwc_get_saturation(struct pwc_device *pdev) +{ + char buf; + int ret; + + if (pdev->type < 730) + return -1; + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_CHROM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SATURATION_MODE_FORMATTER1, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return 32768 + buf * 327; +} + +int pwc_set_saturation(struct pwc_device *pdev, int value) +{ + char buf; + + if (pdev->type < 730) + return -EINVAL; + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* saturation ranges from -100 to +100 */ + buf = (value - 32768) / 327; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_CHROM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SATURATION_MODE_FORMATTER1, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +/* AGC */ + +static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) +{ + char buf; + int ret; + + if (mode) + buf = 0x0; /* auto */ + else + buf = 0xff; /* fixed */ + + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AGC_MODE_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3F; + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + PRESET_AGC_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + } + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_agc(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AGC_MODE_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + + if (buf != 0) { /* fixed */ + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + PRESET_AGC_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + if (buf > 0x3F) + buf = 0x3F; + *value = (buf << 10); + } + else { /* auto */ + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_STATUS_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + READ_AGC_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + /* Gah... this value ranges from 0x00 ... 0x9F */ + if (buf > 0x9F) + buf = 0x9F; + *value = -(48 + buf * 409); + } + + return 0; +} + +static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) +{ + char buf[2]; + int speed, ret; + + + if (mode) + buf[0] = 0x0; /* auto */ + else + buf[0] = 0xff; /* fixed */ + + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SHUTTER_MODE_FORMATTER, + pdev->vcinterface, + buf, 1, HZ / 2); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + switch(pdev->type) { + case 675: + case 680: + case 690: + /* speed ranges from 0x0 to 0x290 (656) */ + speed = (value / 100); + buf[1] = speed >> 8; + buf[0] = speed & 0xff; + break; + case 730: + case 740: + /* speed seems to range from 0x0 to 0xff */ + buf[1] = 0; + buf[0] = value >> 8; + break; + } + + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + PRESET_SHUTTER_FORMATTER, + pdev->vcinterface, + &buf, 2, HZ / 2); + } + return ret; +} + + +/* POWER */ + +int pwc_camera_power(struct pwc_device *pdev, int power) +{ + char buf; + + if (pdev->type < 675 || pdev->release < 6) + return 0; /* Not supported by Nala or Timon < release 6 */ + + if (power) + buf = 0x00; /* active */ + else + buf = 0xFF; /* power save */ + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_STATUS_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SET_POWER_SAVE_MODE_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + + + +/* private calls */ + +static inline int pwc_restore_user(struct pwc_device *pdev) +{ + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_STATUS_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + RESTORE_USER_DEFAULTS_FORMATTER, + pdev->vcinterface, + NULL, 0, HZ / 2); +} + +static inline int pwc_save_user(struct pwc_device *pdev) +{ + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_STATUS_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SAVE_USER_DEFAULTS_FORMATTER, + pdev->vcinterface, + NULL, 0, HZ / 2); +} + +static inline int pwc_restore_factory(struct pwc_device *pdev) +{ + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_STATUS_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + RESTORE_FACTORY_DEFAULTS_FORMATTER, + pdev->vcinterface, + NULL, 0, HZ / 2); +} + +int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) +{ + switch(cmd) { + case VIDIOCPWCRUSER: + { + if (pwc_restore_user(pdev)) + return -EINVAL; + break; + } + + case VIDIOCPWCSUSER: + { + if (pwc_save_user(pdev)) + return -EINVAL; + break; + } + + case VIDIOCPWCFACTORY: + { + if (pwc_restore_factory(pdev)) + return -EINVAL; + break; + } + + case VIDIOCPWCSCQUAL: + { + int qual, ret; + + if (copy_from_user(&qual, arg, sizeof(int))) + return -EFAULT; + + if (qual < 0 || qual > 3) + return -EINVAL; + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot); + if (ret < 0) + return ret; + pdev->vcompression = qual; + break; + } + + case VIDIOCPWCGCQUAL: + { + if (copy_to_user(arg, &pdev->vcompression, sizeof(int))) + return -EFAULT; + break; + } + + case VIDIOCPWCSAGC: + { + int agc; + + if (copy_from_user(&agc, arg, sizeof(agc))) + return -EFAULT; + else { + if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc)) + return -EINVAL; + } + break; + } + + case VIDIOCPWCGAGC: + { + int agc; + + if (pwc_get_agc(pdev, &agc)) + return -EINVAL; + if (copy_to_user(arg, &agc, sizeof(agc))) + return -EFAULT; + break; + } + + case VIDIOCPWCSSHUTTER: + { + int shutter_speed, ret; + + if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed))) + return -EFAULT; + else { + ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed); + if (ret < 0) + return ret; + } + break; + } + + default: + return -ENOIOCTLCMD; + break; + } + return 0; +} + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c --- v2.4.4/linux/drivers/usb/pwc-if.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-if.c Fri May 25 09:48:50 2001 @@ -0,0 +1,1841 @@ +/* Linux driver for Philips webcam + USB and Video4Linux interface part. + (C) 1999-2001 Nemosoft Unv. + + 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 code forms the interface between the USB layers and the Philips + specific stuff. Some adanved stuff of the driver falls under an + NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and + is thus not distributed in source form. The binary pwcx.o module + contains the code that falls under the NDA. + + In case you're wondering: 'pwc' stands for "Philips WebCam", but + I really didn't want to type 'philips_web_cam' every time (I'm lazy as + any Linux kernel hacker, but I don't like uncomprehensible abbreviations + without explanation). + + Oh yes, convention: to disctinguish between all the various pointers to + device-structures, I use these names for the pointer variables: + udev: struct usb_device * + vdev: struct video_device * + pdev: struct pwc_devive * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-uncompress.h" + +#if !defined(MAP_NR) +#define MAP_NR(a) virt_to_page(a) +#endif + +/* Function prototypes and driver templates */ + +/* hotplug device table support */ +static __devinitdata struct usb_device_id pwc_device_table [] = { + { USB_DEVICE(0x0471, 0x0302) }, + { USB_DEVICE(0x0471, 0x0303) }, + { USB_DEVICE(0x0471, 0x0304) }, + { USB_DEVICE(0x0471, 0x0307) }, + { USB_DEVICE(0x0471, 0x0308) }, + { USB_DEVICE(0x0471, 0x030C) }, + { USB_DEVICE(0x0471, 0x0310) }, + { USB_DEVICE(0x0471, 0x0311) }, + { USB_DEVICE(0x069A, 0x0001) }, + { } +}; +MODULE_DEVICE_TABLE(usb, pwc_device_table); + +static void *usb_pwc_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id); +static void usb_pwc_disconnect(struct usb_device *udev, void *ptr); + +static struct usb_driver pwc_driver = +{ + name: "Philips webcam", /* name */ + id_table: pwc_device_table, + probe: usb_pwc_probe, /* probe() */ + disconnect: usb_pwc_disconnect, /* disconnect() */ +}; + +static int default_size = PSZ_QCIF; +static int default_fps = 10; +static int default_palette = VIDEO_PALETTE_RGB24; /* This is normal for webcams */ +static int default_fbufs = 3; /* Default number of frame buffers */ +static int default_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_trace = TRACE_MODULE | TRACE_FLOW; +static int power_save = 0; +int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ + +static struct semaphore mem_lock; +static void *mem_leak = NULL; /* For delayed kfree()s. See below */ + +static int video_nr = -1; + +/***/ + +static int pwc_video_open(struct video_device *vdev, int mode); +static void pwc_video_close(struct video_device *vdev); +static long pwc_video_read(struct video_device *vdev, char *buf, unsigned long count, int noblock); +static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock); +static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait); +static int pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); +static int pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size); + +static struct video_device pwc_template = { + owner: THIS_MODULE, + name: "Philips Webcam", /* Filled in later */ + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_PWC, /* Let's pretend for now */ + open: pwc_video_open, + close: pwc_video_close, + read: pwc_video_read, + write: pwc_video_write, + poll: pwc_video_poll, + ioctl: pwc_video_ioctl, + mmap: pwc_video_mmap, + initialize: NULL, /* initialize */ + minor: 0 /* minor */ +}; + +/***************************************************************************/ + +/* Okay, this is some magic that I worked out and the reasoning behind it... + + The biggest problem with any USB device is of course: "what to do + when the user unplugs the device while it is in use by an application?" + We have several options: + 1) Curse them with the 7 plagues when they do (requires divine intervention) + 2) Tell them not to (won't work: they'll do it anyway) + 3) Oops the kernel (this will have a negative effect on a user's uptime) + 4) Do something sensible. + + Of course, we go for option 4. + + It happens that this device will be linked to two times, once from + usb_device and once from the video_device in their respective 'private' + pointers. This is done when the device is probed() and all initialization + succeeded. The pwc_device struct links back to both structures. + + When a device is unplugged while in use it will be removed from the + list of known USB devices; I also de-register as a V4L device, but + unfortunately I can't free the memory since the struct is still in use + by the file descriptor. This free-ing is then deferend until the first + opportunity. Crude, but it works. + + A small 'advantage' is that if a user unplugs the cam and plugs it back + in, it should get assigned the same video device minor, but unfortunately + it's non-trivial to re-link the cam back to the video device... (that + would surely be magic! :)) +*/ + +/***************************************************************************/ +/* Private functions */ + +/* Memory management functions, nicked from cpia.c, which nicked them from + bttv.c. So far, I've counted duplication of this code 6 times + (bttv, cpia, ibmcam, ov511, pwc, ieee1394). + */ + +/* 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)); + } + } + } + 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. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + 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); + + mem = vmalloc(size); + if (!mem) + return NULL; + + 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(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + 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(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + vfree(mem); +} + + + +static int pwc_allocate_buffers(struct pwc_device *pdev) +{ + int i; + void *kbuf; + + Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev); + + if (pdev == NULL) + return -ENXIO; + +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("allocate_buffers(): magic failed.\n"); + return -ENXIO; + } +#endif + /* Allocate Isochronuous pipe buffers */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (pdev->sbuf[i].data == NULL) { + kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate iso buffer %d.\n", i); + return -ENOMEM; + } + pdev->sbuf[i].data = kbuf; + memset(kbuf, 0, ISO_BUFFER_SIZE); + } + } + + /* Allocate frame buffer structure */ + if (pdev->fbuf == NULL) { + kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate frame buffer structure.\n"); + return -ENOMEM; + } + pdev->fbuf = kbuf; + memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); + } + /* create frame buffers, and make circular ring */ + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data == NULL) { + kbuf = vmalloc(FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ + if (kbuf == NULL) { + Err("Failed to allocate frame buffer %d.\n", i); + return -ENOMEM; + } + pdev->fbuf[i].data = kbuf; + memset(kbuf, 0, FRAME_SIZE); + } + } + + /* Allocate decompressor buffer space */ + kbuf = vmalloc(FRAME_SIZE); + if (kbuf == NULL) { + Err("Failed to allocate compressed image buffer.\n"); + return -ENOMEM; + } + memset(kbuf, 0, FRAME_SIZE); + pdev->decompress_buffer = kbuf; + + /* Allocate image buffer; double buffer for mmap() */ + kbuf = rvmalloc(default_mbufs * pdev->view_max.size * 4); + if (kbuf == NULL) { + Err("Failed to allocate image buffer(s).\n"); + return -ENOMEM; + } + pdev->image_data = kbuf; + for (i = 0; i < default_mbufs; i++) + pdev->image_ptr[i] = kbuf + (i * pdev->view_max.size * 4); + for (; i < MAX_IMAGES; i++) + pdev->image_ptr[i] = NULL; + + Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); + + return 0; +} + +static void pwc_free_buffers(struct pwc_device *pdev) +{ + int i; + + Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); + + if (pdev == NULL) + return; +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("free_buffers(): magic failed.\n"); + return; + } +#endif + /* Release Iso-pipe buffers */ + Trace(TRACE_MEMORY, "Freeing ISO buffers.\n"); + for (i = 0; i < MAX_ISO_BUFS; i++) + if (pdev->sbuf[i].data != NULL) { + kfree(pdev->sbuf[i].data); + pdev->sbuf[i].data = NULL; + } + /* The same for frame buffers */ + Trace(TRACE_MEMORY, "Freeing frame buffers.\n"); + if (pdev->fbuf != NULL) { + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data != NULL) { + vfree(pdev->fbuf[i].data); + pdev->fbuf[i].data = NULL; + } + } + kfree(pdev->fbuf); + pdev->fbuf = NULL; + } + /* Intermediate decompression buffer */ + Trace(TRACE_MEMORY, "Freeing decompression buffer\n"); + if (pdev->decompress_buffer != NULL) + vfree(pdev->decompress_buffer); + pdev->decompress_buffer = NULL; + + /* Release image buffers */ + Trace(TRACE_MEMORY, "Freeing image buffers\n"); + if (pdev->image_data != NULL) + rvfree(pdev->image_data, default_mbufs * pdev->view_max.size * 4); + pdev->image_data = NULL; + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); +} + +/* The frame & image buffer mess. + + Yes, this is a mess. Well, it used to be simple, but alas... In this + module, 3 buffers schemes are used to get the data from the USB bus to + the user program. The first scheme involves the ISO buffers (called thus + since they transport ISO data from the USB controller), and not really + interesting. Suffices to say the data from this buffer is quickly + gathered in an interrupt handler (pwc_isoc_hanlder) and placed into the + frame buffer. + + The frame buffer is the second scheme, and is the central element here. + It collects the data from a single frame from the camera (hence, the + name). Frames are delimited by the USB camera with a short USB packet, + so that's easy to detect. The frame buffers form a list that is filled + by the camera+USB controller and drained by the user process through + either read() or mmap(). + + The image buffer is the third scheme, in which frames are decompressed + and converted into any of the desired image formats (rgb, bgr, yuv, etc). + For mmap() there is more than one image buffer available. + + The frame buffers provide the image buffering, in case the user process + is a bit slow. This introduces lag and some undesired side-effects. + The problem arises when the frame buffer is full. I used to drop the last + frame, which makes the data in the queue stale very quickly. But dropping + the frame at the head of the queue proved to be a litte bit more difficult. + I tried a circular linked scheme, but this introduced more problems than + it solved. + + Because filling and draining are completely asynchronous processes, this + requires some fiddling with pointers and mutexes. + + Eventually, I came up with a system with 2 lists: an 'empty' frame list + and a 'full' frame list: + * Initially, all frame buffers but one are on the 'empty' list; the one + remaining buffer is our initial fill frame. + * If a frame is needed for filling, we take it from the 'empty' list, + unless that list is empty, in which case we take the buffer at the + head of the 'full' list. + * When our fill buffer has been filled, it is appended to the 'full' + list. + * If a frame is needed by read() or mmap(), it is taken from the head of + the 'full' list, handled, and then appended to the 'empty' list. If no + buffer is present on the 'full' list, we wait. + The advantage is that the buffer that is currently being decompressed/ + converted, is on neither list, and thus not in our way (any other scheme + I tried had the problem of old data lingering in the queue). + + Whatever strategy you choose, it always remains a tradeoff: with more + frame buffers the chances of a missed frame are reduced. On the other + hand, on slower machines it introduces lag because the queue will + always be full. + */ + +/** + \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. + */ +static inline int pwc_next_fill_frame(struct pwc_device *pdev) +{ + int ret, flags; + + ret = 0; + spin_lock_irqsave(&pdev->ptrlock, flags); + if (pdev->fill_frame != NULL) { + /* append to 'full' list */ + if (pdev->full_frames == NULL) { + pdev->full_frames = pdev->fill_frame; + pdev->full_frames_tail = pdev->full_frames; + } + else { + pdev->full_frames_tail->next = pdev->fill_frame; + pdev->full_frames_tail = pdev->fill_frame; + } + } + if (pdev->empty_frames != NULL) { + /* We have empty frames available. That's easy */ + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + } + else { + /* Hmm. Take it from the full list */ +#if PWC_DEBUG + /* sanity check */ + if (pdev->full_frames == NULL) { + Err("Neither empty or full frames available!\n"); + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return -EINVAL; + } +#endif + pdev->fill_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + ret = 1; + } + pdev->fill_frame->next = NULL; +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); + pdev->fill_frame->sequence = pdev->sequence++; +#endif + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + + +/** + \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. + + If the image_used[] buffer is cleared too mmap()/VIDIOCSYNC will run into trouble. + */ +static void pwc_reset_buffers(struct pwc_device *pdev) +{ + int i, flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + pdev->full_frames = NULL; + pdev->full_frames_tail = NULL; + for (i = 0; i < default_fbufs; i++) { + pdev->fbuf[i].filled = 0; + if (i > 0) + pdev->fbuf[i].next = &pdev->fbuf[i - 1]; + else + pdev->fbuf->next = NULL; + } + pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; + pdev->empty_frames_tail = pdev->fbuf; + pdev->read_frame = NULL; + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + + pdev->image_read_pos = 0; + pdev->fill_image = 0; + spin_unlock_irqrestore(&pdev->ptrlock, flags); +} + + +/** + \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. + */ +static int pwc_handle_frame(struct pwc_device *pdev) +{ + int ret = 0, flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + /* First grab our read_frame; this is removed from all lists, so + we can release the lock after this without problems */ + if (pdev->read_frame != NULL) { + /* This can't theoretically happen */ + Err("Huh? Read frame still in use?\n"); + } + else { + if (pdev->full_frames == NULL) { + Err("Woops. No frames ready.\n"); + } + else { + pdev->read_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + pdev->read_frame->next = NULL; + } + + if (pdev->read_frame != NULL) { +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); +#endif + /* Decompression is a lenghty process, so it's outside of the lock. + This gives the isoc_handler the opportunity to fill more frames + in the mean time. + */ + spin_unlock_irqrestore(&pdev->ptrlock, flags); + ret = pwc_decompress(pdev); + spin_lock_irqsave(&pdev->ptrlock, flags); + + /* We're done with read_buffer, tack it to the end of the empty buffer list */ + if (pdev->empty_frames == NULL) { + pdev->empty_frames = pdev->read_frame; + pdev->empty_frames_tail = pdev->empty_frames; + } + else { + pdev->empty_frames_tail->next = pdev->read_frame; + pdev->empty_frames_tail = pdev->read_frame; + } + pdev->read_frame = NULL; + } + } + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + +/** + \brief Advance pointers of image buffer (after each user request) +*/ +static inline void pwc_next_image(struct pwc_device *pdev) +{ + pdev->image_used[pdev->fill_image] = 0; + pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; +} + +static int pwc_set_palette(struct pwc_device *pdev, int pal) +{ + if ( + pal == VIDEO_PALETTE_YUV420 +#if PWC_DEBUG + || pal == VIDEO_PALETTE_RAW +#endif + ) { + pdev->vpalette = pal; + pwc_set_image_buffer_size(pdev); + return 0; + } + return -1; +} + + + +/* This gets called for the Isochronous pipe (video). This is done in + * interrupt time, so it has to be fast, not crash, and not stall. Neat. + */ +static void pwc_isoc_handler(purb_t urb) +{ + struct pwc_device *pdev; + int i, fst, flen; + int awake; + struct pwc_frame_buf *fbuf; + unsigned char *fillptr, *iso_buf; + + pdev = (struct pwc_device *)urb->context; + if (pdev == NULL) { + Err("isoc_handler() called with NULL device?!\n"); + return; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("isoc_handler() called with bad magic!\n"); + return; + } +#endif + if (urb->status == -ENOENT || urb->status == -ECONNRESET) { + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n"); + return; + } + if (urb->status != -EINPROGRESS && urb->status != 0) { + Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d.\n", urb->status); + return; + } + + fbuf = pdev->fill_frame; + if (fbuf == NULL) { + Err("pwc_isoc_handler without valid fill frame.\n"); + if (waitqueue_active(&pdev->frameq)) + wake_up_interruptible(&pdev->frameq); + if (waitqueue_active(&pdev->pollq)) + wake_up_interruptible(&pdev->pollq); + return; + } + fillptr = fbuf->data + fbuf->filled; + awake = 0; + + /* vsync: 0 = don't copy data + 1 = sync-hunt + 2 = synched + */ + /* Compact data */ + for (i = 0; i < urb->number_of_packets; i++) { + fst = urb->iso_frame_desc[i].status; + flen = urb->iso_frame_desc[i].actual_length; + iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (fst == 0) { + if (flen > 0) { /* if valid data... */ + if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ + pdev->vsync = 2; + + /* ...copy data to frame buffer, if possible */ + if (flen + fbuf->filled > pdev->frame_size) { + Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_size = %d).\n", flen, pdev->frame_size); + pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ + pdev->vframes_error++; + } + else { + memmove(fillptr, iso_buf, flen); + fillptr += flen; + } + } + fbuf->filled += flen; + } /* ..flen > 0 */ + + if (flen < pdev->vlast_packet_size) { + /* Shorter packet... We probably have the end of an image-frame; + wake up read() process and let select()/poll() do something. + Decompression is done in user time over there. + */ + if (pdev->vsync == 2) { + /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus + frames on the USB wire after an exposure change. This conditition is + however detected in the cam and a bit is set in the header. + */ + if (pdev->type == 730) { + unsigned char *ptr = (unsigned char *)fbuf->data; + + if (ptr[1] == 1 && ptr[0] & 0x10) { +#if PWC_DEBUG + Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); +#endif + pdev->drop_frames = 2; + pdev->vframes_error++; + } + /* Sometimes the trailer of the 730 is still sent as a 4 byte packet + after a short frame; this condition is filtered out specifically. A 4 byte + frame doesn't make sense anyway. + So we get either this sequence: + drop_bit set -> 4 byte frame -> short frame -> good frame + Or this one: + drop_bit set -> short frame -> good frame + So we drop either 3 or 2 frames in all! + */ + if (fbuf->filled == 4) + pdev->drop_frames++; + } + + /* In case we were instructed to drop the frame, do so silently. + The buffer pointers are not updated either (but the counters are reset below). + */ + if (pdev->drop_frames) + pdev->drop_frames--; + else { + /* Check for underflow first */ + if (fbuf->filled < pdev->frame_size) { + Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); + pdev->vframes_error++; + } + else { + /* Send only once per EOF */ + awake = 1; /* delay wake_ups */ + + /* Find our next frame to fill. This will always succeed, since we + * nick a frame from either empty or full list, but if we had to + * take it from the full list, it means a frame got dropped. + */ + if (pwc_next_fill_frame(pdev)) { + pdev->vframes_dumped++; + if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { + if (pdev->vframes_dumped < 20) + Info("Dumping frame %d.\n", pdev->vframe_count); + if (pdev->vframes_dumped == 20) + Info("Dumping frame %d (last message).\n", pdev->vframe_count); + } + } + fbuf = pdev->fill_frame; + } + } /* !drop_frames */ + pdev->vframe_count++; + } + fbuf->filled = 0; + fillptr = fbuf->data; + pdev->vsync = 1; + } /* .. flen < last_packet_size */ + pdev->vlast_packet_size = flen; + } /* ..status == 0 */ + } + if (awake) { + if (waitqueue_active(&pdev->frameq)) + wake_up_interruptible(&pdev->frameq); + if (waitqueue_active(&pdev->pollq)) + wake_up_interruptible(&pdev->pollq); + } +} + + +static int pwc_isoc_init(struct pwc_device *pdev) +{ + struct usb_device *udev; + purb_t urb; + int i, j, ret; + + struct usb_interface_descriptor *idesc; + int cur_alt; + + if (pdev == NULL) + return -EFAULT; + if (pdev->iso_init) + return 0; + pdev->vsync = 0; + udev = pdev->udev; + + /* Get the current alternate interface, adjust packet size */ + if (!udev->actconfig) + return -EFAULT; + cur_alt = udev->actconfig->interface[0].act_altsetting; + idesc = &udev->actconfig->interface[0].altsetting[cur_alt]; + if (!idesc) + return -EFAULT; + + /* Search video endpoint */ + pdev->vmax_packet_size = -1; + for (i = 0; i < idesc->bNumEndpoints; i++) + if ((idesc->endpoint[i].bEndpointAddress & 0xF) == pdev->vendpoint) { + pdev->vmax_packet_size = idesc->endpoint[i].wMaxPacketSize; + break; + } + + if (pdev->vmax_packet_size < 0) { + Err("Failed to find packet size for video endpoint in current alternate setting.\n"); + return -ENFILE; /* Odd error, that should be noticable */ + } + + ret = 0; + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC); + if (urb == NULL) { + Err("Failed to allocate urb %d\n", i); + ret = -ENOMEM; + break; + } + pdev->sbuf[i].urb = urb; + } + if (ret) { + /* De-allocate in reverse order */ + while (i >= 0) { + if (pdev->sbuf[i].urb != NULL) + usb_free_urb(pdev->sbuf[i].urb); + i--; + } + return ret; + } + + + /* init URB structure */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = pdev->sbuf[i].urb; + + urb->next = pdev->sbuf[(i + 1) % MAX_ISO_BUFS].urb; + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = pdev->sbuf[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = pwc_isoc_handler; + urb->context = pdev; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; + } + } + + /* link */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + ret = usb_submit_urb(pdev->sbuf[i].urb); + if (ret) + Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); + } + + /* data should stream in now */ + pdev->iso_init = 1; + return 0; +} + +static void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + int i; + + if (pdev == NULL) + return; + if (!pdev->iso_init) + return; + /* Stop camera, but only if we are sure the camera is still there */ + if (!pdev->unplugged) + usb_set_interface(pdev->udev, 0, 0); + for (i = MAX_ISO_BUFS - 1; i >= 0; i--) { + pdev->sbuf[i].urb->next = NULL; + usb_unlink_urb(pdev->sbuf[i].urb); + usb_free_urb(pdev->sbuf[i].urb); + pdev->sbuf[i].urb = NULL; + } + pdev->iso_init = 0; +} + +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) +{ + int ret; + + /* Stop isoc stuff */ + pwc_isoc_cleanup(pdev); + /* Reset parameters */ + pwc_reset_buffers(pdev); + /* Try to set video mode... */ + ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); + if (ret) /* That failed... restore old mode (we know that worked) */ + ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + else /* Set (new) alternate interface */ + ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (!ret) + ret = pwc_isoc_init(pdev); + pdev->drop_frames = 1; /* try to avoid garbage during switch */ + return ret; +} + + +static inline void set_mem_leak(void *ptr) +{ + down(&mem_lock); + if (mem_leak != NULL) + Err("Memleak: overwriting mem_leak pointer!\n"); + Trace(TRACE_MEMORY, "Setting mem_leak to 0x%p.\n", ptr); + mem_leak = ptr; + up(&mem_lock); +} + +static inline void free_mem_leak(void) +{ + down(&mem_lock); + if (mem_leak != NULL) { + Trace(TRACE_MEMORY, "Freeing mem_leak ptr 0x%p.\n", mem_leak); + kfree(mem_leak); + mem_leak = NULL; + } + up(&mem_lock); +} + + +/***************************************************************************/ +/* Video4Linux functions */ + +static int pwc_video_open(struct video_device *vdev, int mode) +{ + int i; + struct pwc_device *pdev; + + Trace(TRACE_OPEN, "video_open called(0x%p, 0%o).\n", vdev, mode); + + if (vdev == NULL) + BUG(); + pdev = (struct pwc_device *)vdev->priv; + if (pdev == NULL) + BUG(); + + down(&pdev->modlock); + if (!pdev->usb_init) { + Trace(TRACE_OPEN, "Doing first time initialization.\n"); + /* Reset camera */ + if (usb_set_interface(pdev->udev, 0, 0)) + Info("Failed to set alternate interface to 0.\n"); + pdev->usb_init = 1; + } + else { + /* Turn on camera */ + if (power_save) { + i = pwc_camera_power(pdev, 1); + if (i < 0) + Info("Failed to restore power to the camera! (%d)\n", i); + } + } + + /* So far, so good. Allocate memory. */ + i = pwc_allocate_buffers(pdev); + if (i < 0) { + Trace(TRACE_OPEN, "Failed to allocate memory.\n"); + up(&pdev->modlock); + return i; + } + + /* Reset buffers & parameters */ + pwc_reset_buffers(pdev); + for (i = 0; i < default_mbufs; i++) + pdev->image_used[i] = 0; + pdev->vframe_count = 0; + pdev->vframes_dumped = 0; + pdev->vframes_error = 0; + pdev->vpalette = default_palette; +#if PWC_DEBUG + pdev->sequence = 0; +#endif + + /* Find our decompressor, if any */ + pdev->decompressor = pwc_find_decompressor(pdev->type); +#if PWC_DEBUG + Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor); +#endif + + /* Set some defaults */ + pdev->vsnapshot = 0; + if (pdev->type == 730 || pdev->type == 740) + pdev->vsize = PSZ_QSIF; + else + pdev->vsize = PSZ_QCIF; + pdev->vframes = 10; + + /* Start iso pipe for video; first try user-supplied size/fps, if + that fails try QCIF/10 or QSIF/10 (a reasonable default), + then give up + */ + i = pwc_set_video_mode(pdev, pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y, default_fps, pdev->vcompression, 0); + if (i) { + Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); + if (pdev->type == 730 || pdev->type == 740) + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); + else + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); + } + if (i) { + Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); + up(&pdev->modlock); + return i; + } + i = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (i) { + Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i); + up(&pdev->modlock); + return -EINVAL; + } + i = pwc_isoc_init(pdev); + if (i) { + Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); + MOD_DEC_USE_COUNT; + up(&pdev->modlock); + return i; + } + + pdev->vopen++; + /* lock decompressor; this has a small race condition, since we + could in theory unload pwcx.o between pwc_find_decompressor() + above and this call. I doubt it's ever going to be a problem. + */ + if (pdev->decompressor != NULL) + pdev->decompressor->lock(); + up(&pdev->modlock); + Trace(TRACE_OPEN, "video_open() returning 0.\n"); + return 0; +} + +/* Note that all cleanup is done in the reverse order as in _open */ +static void pwc_video_close(struct video_device *vdev) +{ + struct pwc_device *pdev; + int i; + + Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev); + + pdev = (struct pwc_device *)vdev->priv; + if (pdev->vopen == 0) + Info("video_close() called on closed device?\n"); + + /* Free isoc URBs */ + pwc_isoc_cleanup(pdev); + + /* Dump statistics, but only if a reasonable amount of frames were + processed (to prevent endless log-entries in case of snap-shot + programs) + */ + if (pdev->vframe_count > 20) + Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); + + if (pdev->unplugged) { + /* The device was unplugged or some other error occured */ + /* We unregister the video_device */ + Trace(TRACE_OPEN, "Delayed video device unregistered.\n"); + video_unregister_device(pdev->vdev); + } + else { + /* Normal close: stop isochronuous and interrupt endpoint */ + Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n"); + usb_set_interface(pdev->udev, 0, 0); + + /* Turn off LED by powering down camera */ + if (power_save) { + i = pwc_camera_power(pdev, 0); + if (i < 0) + Err("Failed to power down camera (%d)\n", i); + } + } + + pdev->vopen = 0; + pwc_free_buffers(pdev); + if (pdev->decompressor != NULL) { + pdev->decompressor->exit(&pdev->decompress_data); + pdev->decompressor->unlock(); + } + pdev->decompressor = NULL; + + /* wake up _disconnect() routine */ + if (pdev->unplugged) + wake_up(&pdev->remove_ok); +} + +/* + * FIXME: what about two parallel reads ???? + */ + +static long pwc_video_read(struct video_device *vdev, char *buf, unsigned long count, int noblock) +{ + struct pwc_device *pdev; + + Trace(TRACE_READ, "video_read(0x%p, %p, %ld, %d) called.\n", vdev, buf, count, noblock); + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + if (pdev->unplugged) { + Debug("pwc_video_read: Device got unplugged (1).\n"); + return -EPIPE; /* unplugged device! */ + } + + /* In case we're doing partial reads, we don't have to wait for a frame */ + if (pdev->image_read_pos == 0) { + /* See if a frame is completed, process that */ + if (noblock && pdev->full_frames == NULL) + return -EAGAIN; + while (pdev->full_frames == NULL) { + interruptible_sleep_on(&pdev->frameq); + if (pdev->unplugged) { + Debug("pwc_video_read: Device got unplugged (2).\n"); + return -EPIPE; + } + if (signal_pending(current)) + return -EINTR; + } + + /* Decompress & convert now */ + if (pwc_handle_frame(pdev)) + return -EFAULT; + } + + Trace(TRACE_READ, "Copying data to user space.\n"); + /* copy bytes to user space; we allow for partial reads */ + if (count + pdev->image_read_pos > pdev->view.size) + count = pdev->view.size - pdev->image_read_pos; + if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) + return -EFAULT; + pdev->image_read_pos += count; + if (pdev->image_read_pos >= pdev->view.size) { /* All data has been read */ + pdev->image_read_pos = 0; + pwc_next_image(pdev); + } + return count; +} + + +static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait) +{ + struct pwc_device *pdev; + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + poll_wait(file, &pdev->pollq, wait); + if (pdev->unplugged) { + Debug("pwc_video_poll: Device got unplugged.\n"); + return POLLERR; + } + if (pdev->full_frames != NULL) /* we have frames waiting */ + return (POLLIN | POLLRDNORM); + + return 0; +} + +static int pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct pwc_device *pdev; + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + switch (cmd) { + /* Query cabapilities */ + case VIDIOCGCAP: + { + struct video_capability caps; + + strcpy(caps.name, vdev->name); + caps.type = VID_TYPE_CAPTURE; + caps.channels = 1; + caps.audios = 1; + caps.minwidth = pdev->view_min.x; + caps.minheight = pdev->view_min.y; + caps.maxwidth = pdev->view_max.x; + caps.maxheight = pdev->view_max.y; + if (copy_to_user(arg, &caps, sizeof(caps))) + return -EFAULT; + break; + } + + /* Channel functions (simulate 1 channel) */ + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Webcam"); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + + case VIDIOCSCHAN: + { + /* The spec says the argument is an integer, but + the bttv driver uses a video_channel arg, which + makes sense becasue it also has the norm flag. + */ + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v.channel != 0) + return -EINVAL; + + return 0; + } + + + /* Picture functions; contrast etc. */ + case VIDIOCGPICT: + { + struct video_picture p; + int val; + + p.colour = 0x8000; + p.hue = 0x8000; + val = pwc_get_brightness(pdev); + if (val >= 0) + p.brightness = val; + else + p.brightness = 0xffff; + val = pwc_get_contrast(pdev); + if (val >= 0) + p.contrast = val; + else + p.contrast = 0xffff; + /* Gamma, Whiteness, what's the difference? :) */ + val = pwc_get_gamma(pdev); + if (val >= 0) + p.whiteness = val; + else + p.whiteness = 0xffff; + val = pwc_get_saturation(pdev); + if (val >= 0) + p.colour = val; + else + p.colour = 0xffff; + p.depth = 24; + p.palette = pdev->vpalette; + p.hue = 0xFFFF; /* N/A */ + + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + break; + } + + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + + /* + * FIXME: Suppose we are mid read + */ + pwc_set_brightness(pdev, p.brightness); + pwc_set_contrast(pdev, p.contrast); + pwc_set_gamma(pdev, p.whiteness); + pwc_set_saturation(pdev, p.colour); + if (p.palette && p.palette != pdev->vpalette) { + if (pwc_set_palette(pdev, p.palette) < 0) + return -EINVAL; + } + break; + } + + /* Window/size parameters */ + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.width = pdev->view.x; + vw.height = pdev->view.y; + vw.chromakey = 0; + vw.flags = (pdev->vframes << PWC_FPS_SHIFT) | + (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + break; + } + + case VIDIOCSWIN: + { + struct video_window vw; + int fps, snapshot, ret; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + +/* + size = pwc_decode_size(pdev, vw.width, vw.height); + if (size < 0) + return -EINVAL; +*/ + fps = (vw.flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; + snapshot = vw.flags & PWC_FPS_SNAPSHOT; + if (fps == 0) + fps = pdev->vframes; + if (pdev->view.x == vw.width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) + return 0; + ret = pwc_try_video_mode(pdev, vw.width, vw.height, fps, pdev->vcompression, snapshot); + if (ret) + return ret; + break; + } + + /* We don't have overlay support (yet) */ + case VIDIOCGFBUF: + { + struct video_buffer vb; + + vb.base = NULL; + vb.height = 0; + vb.width = 0; + vb.depth = 0; + vb.bytesperline = 0; + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + break; + } + + /* mmap() functions */ + case VIDIOCGMBUF: + { + /* Tell the user program how much memory is needed for a mmap() */ + struct video_mbuf vm; + int i; + + memset(&vm, 0, sizeof(vm)); + vm.size = default_mbufs * pdev->view_max.size * 4; + vm.frames = default_mbufs; /* double buffering should be enough */ + for (i = 0; i < default_mbufs; i++) + vm.offsets[i] = i * pdev->view_max.size * 4; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + break; + } + + case VIDIOCMCAPTURE: + { + /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ + struct video_mmap vm; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) + return -EFAULT; + Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm.width, vm.height, vm.frame, vm.format); + if (vm.frame < 0 || vm.frame >= default_mbufs) + return -EINVAL; + + /* xawtv is nasty. It probes the available palettes + by setting a very small image size and trying + various palettes... The driver doesn't support + such small images, so I'm working around it. + */ + if (vm.format && vm.format != pdev->vpalette) + if (pwc_set_palette(pdev, vm.format) < 0) + return -EINVAL; + + if ((vm.width != pdev->view.x || vm.height != pdev->view.y) && + (vm.width >= pdev->view_min.x && vm.height >= pdev->view_min.y)) { + int ret; + + Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); +/* + size = pwc_decode_size(pdev, vm.width, vm.height); + if (size < 0) + return -EINVAL; +*/ + ret = pwc_try_video_mode(pdev, vm.width, vm.height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (ret) + return ret; + } /* ... size mismatch */ + + /* FIXME: should we lock here? */ + if (pdev->image_used[vm.frame]) + return -EBUSY; /* buffer wasn't available. Bummer */ + pdev->image_used[vm.frame] = 1; + + /* Okay, we're done here. In the SYNC call we wait until a + frame comes available, then expand image into the given + buffer. + In contrast to the CPiA cam the Philips cams deliver a + constant stream, almost like a grabber card. Also, + we have separate buffers for the rawdata and the image, + meaning we can nearly always expand into the requested buffer. + */ + Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); + break; + } + + case VIDIOCSYNC: + { + /* The doc says: "Whenever a buffer is used it should + call VIDIOCSYNC to free this frame up and continue." + + The only odd thing about this whole procedure is + that MCAPTURE flags the buffer as "in use", and + SYNC immediately unmarks it, while it isn't + after SYNC that you know that the buffer actually + got filled! So you better not start a CAPTURE in + the same frame immediately (use double buffering). + This is not a problem for this cam, since it has + extra intermediate buffers, but a hardware + grabber card will then overwrite the buffer + you're working on. + */ + int mbuf, ret; + + if (copy_from_user((void *)&mbuf, arg, sizeof(int))) + return -EFAULT; + + Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", mbuf); + + if (mbuf < 0 || mbuf >= default_mbufs) + return -EINVAL; + /* check if this buffer was requested anyway */ + if (pdev->image_used[mbuf] == 0) + return -EINVAL; + + /* We (re)use the frame-waitqueue here. That may + conflict with read(), but any programmer that uses + read() and mmap() simultaneously should be given + a job at Micro$oft. As janitor. + + FIXME: needs auditing for safety. + */ + while (pdev->full_frames == NULL) { + interruptible_sleep_on(&pdev->frameq); + if (pdev->unplugged) { + Debug("VIDIOCSYNC: Device got unplugged.\n"); + return -EPIPE; + } + if (signal_pending(current)) + return -EINTR; + } + /* The frame is ready. Expand in the image buffer + requested by the user. I don't care if you + mmap() 5 buffers and request data in this order: + buffer 4 2 3 0 1 2 3 0 4 3 1 . . . + Grabber hardware may not be so forgiving. + */ + Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); + pdev->fill_image = mbuf; /* tell in which buffer we want the image to be expanded */ + /* Decompress, etc */ + ret = pwc_handle_frame(pdev); + pdev->image_used[mbuf] = 0; + if (ret) + return -EFAULT; + break; + } + + default: + return pwc_ioctl(pdev, cmd, arg); + } /* ..switch */ + return 0; +} + +static int pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size) +{ + struct pwc_device *pdev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + Trace(TRACE_READ, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size); + pdev = vdev->priv; + + /* FIXME - audit mmap during a read */ + + pos = (unsigned long)pdev->image_data; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +/***************************************************************************/ +/* USB functions */ + +/* This function gets called when a new device is plugged in or the usb core + * is loaded. + */ + +static void *usb_pwc_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct pwc_device *pdev = NULL; + struct video_device *vdev; + struct usb_config_descriptor *config; + struct usb_interface *iface; + int vendor_id, product_id, type_id; + int i; + + free_mem_leak(); + + /* Check if we can handle this device */ + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", udev->descriptor.idVendor, udev->descriptor.idProduct, ifnum); + + /* the interfaces are probed one by one. We are only interested in the + video interface (0) now. + Interface 1 is the Audio Control, and interface 2 Audio itself. + */ + if (ifnum > 0) + return NULL; + + vendor_id = udev->descriptor.idVendor; + product_id = udev->descriptor.idProduct; + + + if (vendor_id == 0x0471) { + switch (product_id) { + case 0x0302: + Info("Philips PCA645VC USB webcam detected.\n"); + type_id = 645; + break; + case 0x0303: + Info("Philips PCA646VC USB webcam detected.\n"); + type_id = 646; + break; + case 0x0304: + Info("Askey VC010 type 2 USB webcam detected.\n"); + type_id = 646; + break; + case 0x0307: + Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + type_id = 675; + break; + case 0x0308: + Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + type_id = 680; + break; + case 0x030C: + Info("Philips PCVC690K (Vesta Scanner) USB webcam detected.\n"); + type_id = 690; + break; + case 0x0310: + Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + type_id = 730; + break; + case 0x0311: + Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + type_id = 740; + break; + default: + return NULL; + break; + } + } + else if (vendor_id == 0x069A) { + switch(product_id) { + case 0x0001: + Info("Askey VC010 type 1 USB webcam detected.\n"); + type_id = 645; + break; + default: + return NULL; + break; + } + } + else return NULL; /* Not Philips or Askey, for sure. */ + + if (udev->descriptor.bNumConfigurations > 1) + Info("Warning: more than 1 configuration available.\n"); + + config = udev->actconfig; + iface = &config->interface[0]; + + /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ + pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); + if (pdev == NULL) { + Err("Oops, could not allocate memory for pwc_device.\n"); + return NULL; + } + memset(pdev, 0, sizeof(struct pwc_device)); + pdev->type = type_id; + pwc_construct(pdev); + + init_MUTEX(&pdev->modlock); + pdev->ptrlock = SPIN_LOCK_UNLOCKED; + + pdev->udev = udev; + init_waitqueue_head(&pdev->frameq); + init_waitqueue_head(&pdev->pollq); + init_waitqueue_head(&pdev->remove_ok); + pdev->vcompression = pwc_preferred_compression; + + /* Now hook it up to the video subsystem */ + vdev = kmalloc(sizeof(struct video_device), GFP_KERNEL); + if (vdev == NULL) { + Err("Oops, could not allocate memory for video_device.\n"); + return NULL; + } + memcpy(vdev, &pwc_template, sizeof(pwc_template)); + sprintf(vdev->name, "Philips %d webcam", pdev->type); + SET_MODULE_OWNER(vdev); + pdev->vdev = vdev; + vdev->priv = pdev; + + pdev->release = udev->descriptor.bcdDevice; + Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); + + i = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr); + if (i < 0) { + Err("Failed to register as video device (%d).\n", i); + return NULL; + } + else { + Trace(TRACE_PROBE, "Registered video struct at 0x%p.\n", vdev); + Info("Registered as /dev/video%d.\n", vdev->minor & 0x3F); + } + +#if 0 + /* Shut down camera now (some people like the LED off) */ + if (power_save) { + Trace(TRACE_PROBE, "Powering down camera"); + i = pwc_camera_power(pdev, 0); + if (i < 0) + Info("Failed to power-down the camera (%d)\n", i); + } +#endif + + Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); + return pdev; +} + +/* The user janked out the cable... */ +static void usb_pwc_disconnect(struct usb_device *udev, void *ptr) +{ + struct pwc_device *pdev; + + free_mem_leak(); + + pdev = (struct pwc_device *)ptr; + if (pdev == NULL) { + Err("pwc_disconnect() Called without private pointer.\n"); + return; + } + if (pdev->udev == NULL) { + Err("pwc_disconnect() already called for %p\n", pdev); + return; + } + if (pdev->udev != udev) { + Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); + return; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); + return; + } +#endif + + pdev->unplugged = 1; + if (pdev->vdev != NULL) { + if (pdev->vopen) { + Info("Disconnected while device/video is open!\n"); + + /* Wake up any processes that might be waiting for + a frame, let them return an error condition + */ + wake_up(&pdev->frameq); + wake_up(&pdev->pollq); + + /* Wait until we get a 'go' from _close(). This + had a gigantic race condition, since we kfree() + stuff here, but we have to wait until close() + is finished. */ + + Trace(TRACE_PROBE, "Sleeping on remove_ok.\n"); + sleep_on(&pdev->remove_ok); + Trace(TRACE_PROBE, "Done sleeping.\n"); + set_mem_leak(pdev->vdev); + pdev->vdev = NULL; + } + else { + /* Normal disconnect; remove from available devices */ + Trace(TRACE_PROBE, "Unregistering video device normally.\n"); + video_unregister_device(pdev->vdev); + kfree(pdev->vdev); + pdev->vdev = NULL; + } + } + pdev->udev = NULL; + kfree(pdev); +} + + + +/* + * Initialization code & module stuff + */ + +static char *size = NULL; +static int fps = 0; +static char *palette = NULL; +static int fbufs = 0; +static int mbufs = 0; +static int trace = -1; +static int compression = -1; + +MODULE_PARM(video_nr, "i"); +MODULE_PARM(size, "s"); +MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); +MODULE_PARM(fps, "i"); +MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); +MODULE_PARM(palette, "s"); +MODULE_PARM_DESC(palette, "Initial colour format of images. One of rgb24, bgr24, rgb32, bgr32, yuyv, yuv420, yuv420p"); +MODULE_PARM(fbufs, "i"); +MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); +MODULE_PARM(mbufs, "i"); +MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); +MODULE_PARM(trace, "i"); +MODULE_PARM_DESC(trace, "For debugging purposes"); +MODULE_PARM(power_save, "i"); +MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); +MODULE_PARM(compression, "i"); +MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); + +MODULE_DESCRIPTION("Philips USB webcam driver"); +MODULE_AUTHOR("Nemosoft Unv. "); + +static int __init usb_pwc_init(void) +{ + int s; + char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; + + Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740 webcam module version " PWC_VERSION " loaded.\n"); + Info("Also supports Askey VC010 cam.\n"); + + if (fps) { + if (fps < 5 || fps > 30) { + Err("Framerate out of bounds (5-30).\n"); + return -EINVAL; + } + default_fps = fps; + Info("Default framerate set to %d.\n", default_fps); + } + + if (size) { + /* string; try matching with array */ + for (s = 0; s < PSZ_MAX; s++) { + if (!strcmp(sizenames[s], size)) { /* Found! */ + default_size = s; + break; + } + } + if (s == PSZ_MAX) { + Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); + return -EINVAL; + } + Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); + } + if (palette) { + /* Determine default palette */ + if (!strcmp(palette, "yuv420")) + default_palette = VIDEO_PALETTE_YUV420; + else { + Err("Palette not recognized: try palette=yuv420.\n"); + return -EINVAL; + } + Info("Default palette set to %d.\n", default_palette); + } + if (mbufs) { + if (mbufs < 1 || mbufs > MAX_IMAGES) { + Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); + return -EINVAL; + } + default_mbufs = mbufs; + Info("Number of image buffers set to %d.\n", default_mbufs); + } + if (fbufs) { + if (fbufs < 2 || fbufs > MAX_FRAMES) { + Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); + return -EINVAL; + } + default_fbufs = fbufs; + Info("Number of frame buffers set to %d.\n", default_fbufs); + } + if (trace >= 0) { + Info("Trace options: 0x%04x\n", trace); + pwc_trace = trace; + } + if (compression >= 0) { + if (compression > 3) { + Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); + return -EINVAL; + } + pwc_preferred_compression = compression; + Info("Preferred compression set to %d.\n", pwc_preferred_compression); + } + if (power_save) + Info("Enabling power save on open/close.\n"); + + init_MUTEX(&mem_lock); + Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); + return usb_register(&pwc_driver); +} + +static void __exit usb_pwc_exit(void) +{ + free_mem_leak(); + Trace(TRACE_MODULE, "Deregistering driver.\n"); + usb_deregister(&pwc_driver); + Info("Philips webcam module removed.\n"); +} + +module_init(usb_pwc_init); +module_exit(usb_pwc_exit); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-ioctl.h linux/drivers/usb/pwc-ioctl.h --- v2.4.4/linux/drivers/usb/pwc-ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-ioctl.h Tue May 22 10:25:36 2001 @@ -0,0 +1,75 @@ +/* (C) 2001 Nemosoft Unv. webcam@smcc.demon.nl + + 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 +*/ + +#ifndef PWC_IOCTL_H +#define PWC_IOCTL_H + +/* These are private ioctl() commands, specific for the Philips webcams. + They contain functions not found in other webcams, and settings not + specified in the Video4Linux API. + + The #define names are built up like follows: + VIDIOC VIDeo IOCtl prefix + PWC Philps WebCam + G optional: Get + S optional: Set + ... the function + */ + + + + +/* The frame rate is encoded in the video_window.flags parameter using + the upper 16 bits, since some flags are defined nowadays. The following + defines provide a mask and shift to filter out this value. + + In 'Snapshot' mode the camera freezes its automatic exposure and colour + balance controls. + */ +#define PWC_FPS_SHIFT 16 +#define PWC_FPS_MASK 0x00FF0000 +#define PWC_FPS_FRMASK 0x003F0000 +#define PWC_FPS_SNAPSHOT 0x00400000 + + + /* Restore user settings */ +#define VIDIOCPWCRUSER _IO('v', 192) + /* Save user settings */ +#define VIDIOCPWCSUSER _IO('v', 193) + /* Restore factory settings */ +#define VIDIOCPWCFACTORY _IO('v', 194) + + /* You can manipulate the compression factor. A compression preference of 0 + means use uncompressed modes when available; 1 is low compression, 2 is + medium and 3 is high compression preferred. Of course, the higher the + compression, the lower the bandwidth used but more chance of artefacts + in the image. The driver automatically chooses a higher compression when + the preferred mode is not available. + */ + /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ +#define VIDIOCPWCSCQUAL _IOW('v', 195, int) + /* Get preferred compression quality */ +#define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ +#define VIDIOCPWCSAGC _IOW('v', 200, int) + /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCGAGC _IOR('v', 200, int) + /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-misc.c linux/drivers/usb/pwc-misc.c --- v2.4.4/linux/drivers/usb/pwc-misc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-misc.c Tue May 22 10:25:36 2001 @@ -0,0 +1,101 @@ +/* Linux driver for Philips webcam + Various miscellaneous functions and tables. + (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + + 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 "pwc.h" + +struct pwc_coord pwc_image_sizes[PSZ_MAX] = +{ + { 128, 96, 0 }, + { 160, 120, 0 }, + { 176, 144, 0 }, + { 320, 240, 0 }, + { 352, 288, 0 }, + { 640, 480, 0 }, +}; + +/* x,y -> PSZ_ */ +int pwc_decode_size(struct pwc_device *pdev, int width, int height) +{ + int i, find; + + /* Make sure we don't go beyond our max size */ + if (width > pdev->view_max.x || height > pdev->view_max.y) + return -1; + /* Find the largest size supported by the camera that fits into the + requested size. + */ + find = -1; + for (i = 0; i < PSZ_MAX; i++) { + if (pdev->image_mask & (1 << i)) { + if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) + find = i; + } + } + return find; +} + +/* initialize variables depending on type */ +void pwc_construct(struct pwc_device *pdev) +{ + switch(pdev->type) { + case 645: + case 646: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + pdev->view_max.x = 352; + pdev->view_max.y = 288; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; + pdev->vcinterface = 2; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 675: + case 680: + case 690: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; + pdev->vcinterface = 3; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 730: + case 740: + pdev->view_min.x = 160; + pdev->view_min.y = 120; + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; + pdev->vcinterface = 3; + pdev->vendpoint = 5; + pdev->frame_header_size = TOUCAM_HEADER_SIZE; + pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; + break; + } + pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; + pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; +} + + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-uncompress.c linux/drivers/usb/pwc-uncompress.c --- v2.4.4/linux/drivers/usb/pwc-uncompress.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-uncompress.c Fri May 25 09:48:50 2001 @@ -0,0 +1,157 @@ +/* Linux driver for Philips webcam + Decompression frontend. + (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + + 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 is where the decompression routines register and unregister + themselves. It also has a decompressor wrapper function. +*/ + +#include "pwc.h" +#include "pwc-uncompress.h" + + +/* This contains a list of all registered decompressors */ +static LIST_HEAD(pwc_decompressor_list); + +/* Should the pwc_decompress structure ever change, we increase the + version number so that we don't get nasty surprises, or can + dynamicly adjust our structure. + */ +const int pwc_decompressor_version = PWC_MAJOR; + +/* Add decompressor to list, ignoring duplicates */ +void pwc_register_decompressor(struct pwc_decompressor *pwcd) +{ + if (pwc_find_decompressor(pwcd->type) == NULL) { + Debug("Adding decompressor for model %d.\n", pwcd->type); + list_add_tail(&pwcd->pwcd_list, &pwc_decompressor_list); + } +} + +/* Remove decompressor from list */ +void pwc_unregister_decompressor(int type) +{ + struct pwc_decompressor *find; + + find = pwc_find_decompressor(type); + if (find != NULL) { + Debug("Removing decompressor for model %d.\n", type); + list_del(&find->pwcd_list); + } +} + +/* Find decompressor in list */ +struct pwc_decompressor *pwc_find_decompressor(int type) +{ + struct list_head *tmp; + struct pwc_decompressor *pwcd; + + list_for_each(tmp, &pwc_decompressor_list) { + pwcd = list_entry(tmp, struct pwc_decompressor, pwcd_list); + if (pwcd->type == type) + return pwcd; + } + return NULL; +} + + + +int pwc_decompress(struct pwc_device *pdev) +{ + struct pwc_frame_buf *fbuf; + int n, l, c, w; + void *yuv, *image, *dst; + + if (pdev == NULL) + return -EFAULT; +#if defined(__KERNEL__) && defined(PWC_MAGIC) + if (pdev->magic != PWC_MAGIC) { + Err("pwc_decompress(): magic failed.\n"); + return -EFAULT; + } +#endif + + fbuf = pdev->read_frame; + if (fbuf == NULL) + return -EFAULT; + image = pdev->image_ptr[pdev->fill_image]; + if (!image) + return -EFAULT; + +#if PWC_DEBUG + /* This is a quickie */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) { + memcpy(image, fbuf->data, pdev->frame_size); + return 0; + } +#endif + + /* Compressed formats are decompressed in decompress_buffer, then + * transformed into the desired format + */ + yuv = pdev->decompress_buffer; + n = 0; + if (pdev->vbandlength == 0) { /* uncompressed */ + yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ + } + else { + if (pdev->decompressor) + n = pdev->decompressor->decompress(pdev->decompress_data, pdev->image.x, pdev->image.y, pdev->vbandlength, yuv, fbuf->data + pdev->frame_header_size, 0); + else + n = -ENXIO; /* No such device or address: missing decompressor */ + } + if (n < 0) { + Err("Error in decompression engine: %d\n", n); + return n; + } + + /* At this point 'yuv' always points to the uncompressed, non-scaled YUV420I data */ + if (pdev->image.x == pdev->view.x && pdev->image.y == pdev->view.y) { + /* Sizes matches; make it quick */ + switch(pdev->vpalette) { + case VIDEO_PALETTE_YUV420: + memcpy(image, yuv, pdev->image.size); + break; + } + } + else { + /* Size mismatch; use viewport conversion routines */ + switch(pdev->vpalette) { + case VIDEO_PALETTE_YUV420: + dst = image + pdev->offset.size; + w = pdev->view.x * 6; + c = pdev->image.x * 6; + for (l = 0; l < pdev->image.y; l++) { + memcpy(dst, yuv, c); + dst += w; + yuv += c; + } + break; + } + } + return 0; +} + +/* Make sure these functions are available for the decompressor plugin + both when this code is compiled into the kernel or as as module. + */ + +EXPORT_SYMBOL_NOVERS(pwc_decompressor_version); +EXPORT_SYMBOL(pwc_register_decompressor); +EXPORT_SYMBOL(pwc_unregister_decompressor); +EXPORT_SYMBOL(pwc_find_decompressor); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc-uncompress.h linux/drivers/usb/pwc-uncompress.h --- v2.4.4/linux/drivers/usb/pwc-uncompress.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc-uncompress.h Tue May 22 10:25:36 2001 @@ -0,0 +1,67 @@ +/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + + 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 +*/ + +#ifndef PWC_DEC_H +#define PWC_DEC_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The decompressor structure. + Every type of decompressor registers itself with the main module. + When a device is opened, it looks up the correct compressor, and + uses that when a compressed video mode is requested. + */ +struct pwc_decompressor +{ + int type; /* type of camera (645, 646, etc) */ + int (* init)(int release, void *buffer, void **data); /* Initialization routine; should be called after each set_video_mode */ + void (* exit)(void **data); /* Cleanup routine */ + int (* decompress)(void *data, int width, int height, int bandlength, void *dst, void *src, int planar); /* The decompression routine itself */ + void (* lock)(void); /* make sure module cannot be unloaded */ + void (* unlock)(void); /* release lock on module */ + + struct list_head pwcd_list; +}; + + +/* Our structure version number. Is set to the version number major */ +extern const int pwc_decompressor_version; + +/* Adds decompressor to list, based on its 'type' field (which matches the 'type' field in pwc_device; ignores any double requests */ +extern void pwc_register_decompressor(struct pwc_decompressor *pwcd); +/* Removes decompressor, based on the type number */ +extern void pwc_unregister_decompressor(int type); +/* Returns pointer to decompressor struct, or NULL if it doesn't exist */ +extern struct pwc_decompressor *pwc_find_decompressor(int type); + +#ifdef CONFIG_USB_PWCX +/* If the decompressor is compiled in, we must call these manually */ +extern int usb_pwcx_init(void); +extern void usb_pwcx_exit(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc.h linux/drivers/usb/pwc.h --- v2.4.4/linux/drivers/usb/pwc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc.h Fri May 25 09:48:50 2001 @@ -0,0 +1,289 @@ +/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + + 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 +*/ + +#ifndef PWC_H +#define PWC_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Defines and structures for the Philips webcam */ +/* Used for checking memory corruption/pointer validation */ +#define PWC_MAGIC 0x89DC10ABUL +#undef PWC_MAGIC + +/* Debugging info on/off */ +#define PWC_DEBUG 0 + +#define TRACE_MODULE 0x0001 +#define TRACE_PROBE 0x0002 +#define TRACE_OPEN 0x0004 +#define TRACE_READ 0x0008 +#define TRACE_MEMORY 0x0010 +#define TRACE_FLOW 0x0020 +#define TRACE_SIZE 0x0040 +#define TRACE_SEQUENCE 0x1000 + +#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) +#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) +#define Info(A...) printk(KERN_INFO PWC_NAME " " A) +#define Err(A...) printk(KERN_ERR PWC_NAME " " A) + + +/* Defines for ToUCam cameras */ +#define TOUCAM_HEADER_SIZE 8 +#define TOUCAM_TRAILER_SIZE 4 + +/* Version block */ +#define PWC_MAJOR 7 +#define PWC_MINOR 1 +#define PWC_RELEASE "7.1" + +#if defined(CONFIG_ARM) + #define PWC_PROCESSOR "ARM" +#endif +#if defined(CONFIG_M686) + #define PWC_PROCESSOR "PPro" +#endif +#if !defined(PWC_PROCESSOR) + #define PWC_PROCESSOR "P5" +#endif + +#if defined(__SMP__) || defined(CONFIG_SMP) +#define PWC_SMP "(SMP)" +#else +#define PWC_SMP "(UP)" +#endif + +#define PWC_VERSION PWC_RELEASE " " PWC_PROCESSOR " " PWC_SMP +#define PWC_NAME "pwc" + +/* Turn certain features on/off */ +#define PWC_INT_PIPE 0 + +/* Ignore errors in the first N frames, to allow for startup delays */ +#define FRAME_LOWMARK 5 + +/* Size and number of buffers for the ISO pipe. */ +#define MAX_ISO_BUFS 2 +#define ISO_FRAMES_PER_DESC 10 +#define ISO_MAX_FRAME_SIZE 960 +#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + +/* Frame buffers: contains compressed or uncompressed video data. */ +#define MAX_FRAMES 5 +/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ +#define FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) + +/* Absolute maximum number of buffers available for mmap() */ +#define MAX_IMAGES 4 + +struct pwc_coord +{ + int x, y; /* guess what */ + int size; /* size, or offset */ +}; + +/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ +struct pwc_iso_buf +{ + void *data; + int length; + int read; + purb_t urb; +}; + +/* intermediate buffers with raw data from the USB cam */ +struct pwc_frame_buf +{ + void *data; + volatile int filled; /* number of bytes filled */ + struct pwc_frame_buf *next; /* list */ +#if PWC_DEBUG + int sequence; /* Sequence number */ +#endif +}; + +struct pwc_device +{ +#ifdef PWC_MAGIC + int magic; +#endif + /* Pointer to our usb_device */ + struct usb_device *udev; + + int type; /* type of cam (645, 646, 675, 680, 690) */ + int release; /* release number */ + int unplugged; /* set when the plug is pulled */ + int usb_init; /* set when the cam has been initialized over USB */ + + /*** Video data ***/ + int vopen; /* flag */ + struct video_device *vdev; + int vendpoint; /* video isoc endpoint */ + int vcinterface; /* video control interface */ + int valternate; /* alternate interface needed */ + int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vpalette; /* YUV, RGB24, RGB32, etc */ + int vframe_count; /* received frames */ + int vframes_dumped; /* counter for dumped frames */ + int vframes_error; /* frames received in error */ + int vmax_packet_size; /* USB maxpacket size */ + int vlast_packet_size; /* for frame synchronisation */ + int vcompression; /* desired compression factor */ + int vbandlength; /* compressed band length; 0 is uncompressed */ + char vsnapshot; /* snapshot mode */ + char vsync; /* used by isoc handler */ + + /* The image acquisition requires 3 to 5 steps: + 1. data is gathered in short packets from the USB controller + 2. data is synchronized and packed into a frame buffer + 3. in case data is compressed, decompress it into a separate buffer + 4. data is optionally converted to RGB/YUV + 5. data is transfered to the user process + + Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... + We have in effect a back-to-back-double-buffer system. + */ + /* 1: isoc */ + struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; + char iso_init; + + /* 2: frame */ + struct pwc_frame_buf *fbuf; + struct pwc_frame_buf *empty_frames, *empty_frames_tail; + struct pwc_frame_buf *full_frames, *full_frames_tail; + struct pwc_frame_buf *read_frame; + struct pwc_frame_buf *fill_frame; + int frame_size; + int frame_header_size, frame_trailer_size; + int drop_frames; +#if PWC_DEBUG + int sequence; /* Debugging aid */ +#endif + + /* 3: decompression */ + struct pwc_decompressor *decompressor; /* function block with decompression routines */ + void *decompress_data; /* private data for decompression engine */ + void *decompress_buffer; /* decompressed data */ + + /* 4: image */ + /* We have an 'image' and a 'view', where 'image' is the fixed-size image + as delivered by the camera, and 'view' is the size requested by the + program. The camera image is centered in this viewport, laced with + a gray or black border. view_min <= image <= view <= view_max; + */ + int image_mask; /* bitmask of supported sizes */ + struct pwc_coord view_min, view_max; /* minimum and maximum sizes */ + struct pwc_coord image, view; /* image and viewport size */ + struct pwc_coord offset; /* offset within the viewport */ + + void *image_data; /* total buffer, which is subdivided into ... */ + void *image_ptr[MAX_IMAGES]; /* ...several images... */ + int fill_image; /* ...which are rotated. */ + int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ + int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ + + /* Kernel specific structures. These were once moved to the end + of the structure and padded with bytes after I found out + some of these have different sizes in different kernel versions. + But since this is now a source release, I don't have this problem + anymore. + + Fortunately none of these structures are needed in the pwcx module. + */ + struct semaphore modlock; /* to prevent races in video_open(), etc */ + spinlock_t ptrlock; /* for manipulating the buffer pointers */ + + /*** Misc. data ***/ + wait_queue_head_t frameq; /* When waiting for a frame to finish... */ + wait_queue_head_t pollq; /* poll() has it's own waitqueue */ + wait_queue_head_t remove_ok; /* When we got hot unplugged, we have to avoid a few race conditions */ +#if PWC_INT_PIPE + void *usb_int_handler; /* for the interrupt endpoint */ +#endif +}; + +/* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables */ +extern int pwc_trace; +extern int pwc_preferred_compression; + +/** functions in pwc-if.c */ +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); + +/** Functions in pwc-misc.c */ +/* sizes in pixels */ +extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; + +int pwc_decode_size(struct pwc_device *pdev, int width, int height); +void pwc_construct(struct pwc_device *pdev); + +/** Functions in pwc-ctrl.c */ +/* Request a certain video mode. Returns < 0 if not possible */ +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); +/* Calculate the number of bytes per image (not frame) */ +extern void pwc_set_image_buffer_size(struct pwc_device *pdev); + +/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ +extern int pwc_get_brightness(struct pwc_device *pdev); +extern int pwc_set_brightness(struct pwc_device *pdev, int value); +extern int pwc_get_contrast(struct pwc_device *pdev); +extern int pwc_set_contrast(struct pwc_device *pdev, int value); +extern int pwc_get_gamma(struct pwc_device *pdev); +extern int pwc_set_gamma(struct pwc_device *pdev, int value); +extern int pwc_get_saturation(struct pwc_device *pdev); +extern int pwc_set_saturation(struct pwc_device *pdev, int value); + +/* Power down or up the camera; not supported by all models */ +extern int pwc_camera_power(struct pwc_device *pdev, int power); + +/* Private ioctl()s; see pwc-ioctl.h */ +extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); + + +/** pwc-uncompress.c */ +/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ +extern int pwc_decompress(struct pwc_device *pdev); + +#ifdef __cplusplus +} +#endif + + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc_kiara.h linux/drivers/usb/pwc_kiara.h --- v2.4.4/linux/drivers/usb/pwc_kiara.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc_kiara.h Fri May 25 09:48:50 2001 @@ -0,0 +1,270 @@ + /* SQCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 20 fps */ + { + {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, + {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, + {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, + {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, + {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, + }, + /* 30 fps */ + { + {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, + {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, + {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, + {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, + {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, + {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, + {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, + {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, + {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, + {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, + {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, + {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, + {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, + {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, + {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, + {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc_nala.h linux/drivers/usb/pwc_nala.h --- v2.4.4/linux/drivers/usb/pwc_nala.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc_nala.h Fri May 25 09:48:50 2001 @@ -0,0 +1,66 @@ + /* SQCIF */ + { + {0, 0, {0x04, 0x01, 0x03}}, + {8, 0, {0x05, 0x01, 0x03}}, + {7, 0, {0x08, 0x01, 0x03}}, + {7, 0, {0x0A, 0x01, 0x03}}, + {6, 0, {0x0C, 0x01, 0x03}}, + {5, 0, {0x0F, 0x01, 0x03}}, + {4, 0, {0x14, 0x01, 0x03}}, + {3, 0, {0x18, 0x01, 0x03}}, + }, + /* QSIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* QCIF */ + { + {0, 0, {0x04, 0x01, 0x02}}, + {8, 0, {0x05, 0x01, 0x02}}, + {7, 0, {0x08, 0x01, 0x02}}, + {6, 0, {0x0A, 0x01, 0x02}}, + {5, 0, {0x0C, 0x01, 0x02}}, + {4, 0, {0x0F, 0x01, 0x02}}, + {1, 0, {0x14, 0x01, 0x02}}, + {1, 0, {0x18, 0x01, 0x02}}, + }, + /* SIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* CIF */ + { + {4, 0, {0x04, 0x01, 0x01}}, + {7, 1, {0x05, 0x03, 0x01}}, + {6, 1, {0x08, 0x03, 0x01}}, + {4, 1, {0x0A, 0x03, 0x01}}, + {3, 1, {0x0C, 0x03, 0x01}}, + {2, 1, {0x0F, 0x03, 0x01}}, + {0}, + {0}, + }, + /* VGA */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, diff -u --recursive --new-file v2.4.4/linux/drivers/usb/pwc_timon.h linux/drivers/usb/pwc_timon.h --- v2.4.4/linux/drivers/usb/pwc_timon.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/pwc_timon.h Fri May 25 09:48:50 2001 @@ -0,0 +1,270 @@ + /* SQCIF */ + { + /* 5 fps */ + { + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + }, + /* 15 fps */ + { + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + }, + /* 25 fps */ + { + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + }, + /* 30 fps */ + { + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, + {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, + {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, + {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, + {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, + {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, + {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, + {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, + {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, + {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, + {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, + {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, + {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, + {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, + {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, + {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, + {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, + {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, + {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, + {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, + {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, + {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, + {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, + {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, + {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, + {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, + {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, + {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, + {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, + {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, + {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, + {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, + {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, + }, + /* 25 fps */ + { + {0, }, + {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, + {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, + {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, + {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, + {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, + {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, + {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, + {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, + {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, diff -u --recursive --new-file v2.4.4/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c --- v2.4.4/linux/drivers/usb/rio500.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/rio500.c Mon May 21 15:02:06 2001 @@ -24,6 +24,7 @@ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). * * */ + #include #include #include @@ -40,6 +41,13 @@ #include "rio500_usb.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Cesar Miquel " +#define DRIVER_DESC "USB Rio 500 driver" + #define RIO_MINOR 64 /* stall/wait timeout for rio */ @@ -484,7 +492,9 @@ if (usb_register(&rio_driver) < 0) return -1; - info("USB Rio support registered."); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -502,5 +512,6 @@ module_init(usb_rio_init); module_exit(usb_rio_cleanup); -MODULE_AUTHOR("Cesar Miquel "); -MODULE_DESCRIPTION("USB Rio 500 driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + diff -u --recursive --new-file v2.4.4/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.4.4/linux/drivers/usb/scanner.h Fri Mar 2 17:50:22 2001 +++ linux/drivers/usb/scanner.h Thu May 24 15:14:08 2001 @@ -120,8 +120,9 @@ { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/ { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */ { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */ - { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */ { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */ + { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */ + { USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */ /* Umax */ { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c --- v2.4.4/linux/drivers/usb/serial/belkin_sa.c Fri Apr 6 15:51:50 2001 +++ linux/drivers/usb/serial/belkin_sa.c Mon May 21 15:02:06 2001 @@ -23,6 +23,9 @@ * framework in, but haven't analyzed the "tty_flip" interface yet. * -- Add support for flush commands * -- Add everything that is missing :) + * + * 08-Apr-2001 gb + * - Identify version on module load. * * 12-Mar-2001 gkh * - Added support for the GoHubs GO-COM232 device which is the same as the @@ -79,6 +82,13 @@ #include "usb-serial.h" #include "belkin_sa.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "William Greathouse " +#define DRIVER_DESC "USB Belkin Serial converter driver" + /* function prototypes for a Belkin USB Serial Adapter F5U103 */ static int belkin_sa_startup (struct usb_serial *serial); static void belkin_sa_shutdown (struct usb_serial *serial); @@ -590,6 +600,8 @@ usb_serial_register (&belkin_old_device); usb_serial_register (&peracom_device); usb_serial_register (&gocom232_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -606,7 +618,8 @@ module_init (belkin_sa_init); module_exit (belkin_sa_exit); -MODULE_DESCRIPTION("USB Belkin Serial converter driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.4/linux/drivers/usb/serial/digi_acceleport.c Fri Apr 6 15:51:50 2001 +++ linux/drivers/usb/serial/digi_acceleport.c Mon May 21 15:02:06 2001 @@ -13,6 +13,9 @@ * * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) +* +* (04/08/2001) gb +* Identify version on module load. * * (11/01/2000) Adam J. Richter * usb_device_id table support @@ -254,6 +257,13 @@ /* Defines */ +/* + * Version Information + */ +#define DRIVER_VERSION "v1.80.1.2" +#define DRIVER_AUTHOR "Peter Berger , Al Borchers " +#define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver" + /* port output buffer length -- must be <= transfer buffer length - 2 */ /* so we can be sure to send the full buffer in one urb */ #define DIGI_OUT_BUF_SIZE 8 @@ -2068,6 +2078,8 @@ { usb_serial_register (&digi_acceleport_2_device); usb_serial_register (&digi_acceleport_4_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -2083,8 +2095,8 @@ module_exit(digi_exit); -MODULE_AUTHOR("Peter Berger , Al Borchers "); -MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c --- v2.4.4/linux/drivers/usb/serial/empeg.c Fri Apr 6 15:51:51 2001 +++ linux/drivers/usb/serial/empeg.c Mon May 21 15:02:06 2001 @@ -13,6 +13,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (04/08/2001) gb + * Identify version on module load. + * * (01/22/2001) gb * Added write_room() and chars_in_buffer() support. * @@ -65,6 +68,13 @@ #include "usb-serial.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Gary Brubaker " +#define DRIVER_DESC "USB Empeg Mark I/II Driver" + #define EMPEG_VENDOR_ID 0x084f #define EMPEG_PRODUCT_ID 0x0001 @@ -670,6 +680,9 @@ } } + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -704,8 +717,8 @@ module_init(empeg_init); module_exit(empeg_exit); -MODULE_AUTHOR("Gary Brubaker "); -MODULE_DESCRIPTION("USB Empeg Mark I/II Driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.4/linux/drivers/usb/serial/ftdi_sio.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/usb/serial/ftdi_sio.c Thu May 24 14:55:51 2001 @@ -14,7 +14,22 @@ * * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info * and extra documentation + * + * (23/May/2001) Bill Ryder + * Added runtime debug patch (thanx Tyson D Sawyer). + * Cleaned up comments for 8U232 + * Added parity, framing and overrun error handling + * Added receive break handling. + * + * (04/08/2001) gb + * Identify version on module load. * + * (18/March/2001) Bill Ryder + * (Not released) + * Added send break handling. (requires kernel patch too) + * Fixed 8U232AM hardware RTS/CTS etc status reporting. + * Added flipbuf fix copied from generic device + * * (12/3/2000) Bill Ryder * Added support for 8U232AM device. * Moved PID and VIDs into header file only. @@ -90,14 +105,24 @@ #include "ftdi_sio.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.1.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder " +#define DRIVER_DESC "USB FTDI RS232 Converters Driver" + static __devinitdata struct usb_device_id id_table_sio [] = { { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { } /* Terminating entry */ }; -/* THe 8U232AM has the same API as the sio - but it can support MUCH - higher baudrates (921600 at 48MHz/230400 at 12MHz - so .. it's baudrate setting codes are different */ +/* THe 8U232AM has the same API as the sio except for: + - it can support MUCH higher baudrates (921600 at 48MHz/230400 + at 12MHz so .. it's baudrate setting codes are different + - it has a two byte status code. + - it returns characters very 16ms (the FTDI does it every 40ms) + */ static __devinitdata struct usb_device_id id_table_8U232AM [] = { @@ -117,9 +142,7 @@ struct ftdi_private { ftdi_type_t ftdi_type; - char last_status_byte; /* device sends this every 40ms when open */ - - + __u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */ }; /* function prototypes for a FTDI serial converter */ static int ftdi_sio_startup (struct usb_serial *serial); @@ -132,6 +155,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb); static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old); static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); +static void ftdi_sio_break_ctl (struct usb_serial_port *port, int break_state ); /* Should rename most ftdi_sio's to ftdi_ now since there are two devices which share common code */ @@ -153,6 +177,7 @@ write_bulk_callback: ftdi_sio_write_bulk_callback, ioctl: ftdi_sio_ioctl, set_termios: ftdi_sio_set_termios, + break_ctl: ftdi_sio_break_ctl, startup: ftdi_sio_startup, shutdown: ftdi_sio_shutdown, }; @@ -174,6 +199,7 @@ write_bulk_callback: ftdi_sio_write_bulk_callback, ioctl: ftdi_sio_ioctl, set_termios: ftdi_sio_set_termios, + break_ctl: ftdi_sio_break_ctl, startup: ftdi_8U232AM_startup, shutdown: ftdi_sio_shutdown, }; @@ -227,7 +253,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); return -ENOMEM; } @@ -245,7 +271,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); return -ENOMEM; } @@ -291,7 +317,8 @@ spin_unlock_irqrestore (&port->port_lock, flags); - /* do not allow a task to be queued to deliver received data */ + /* This will push the characters through immediately rather + than queue a task to deliver them */ port->tty->low_latency = 1; /* No error checking for this (will get errors later anyway) */ @@ -422,7 +449,7 @@ unsigned char *first_byte = port->write_urb->transfer_buffer; /* Was seeing a race here, got a read callback, then write callback before - hitting interruptible_sleep_on - so wrapping in a wait_queue */ + hitting interuptible_sleep_on - so wrapping in a wait_queue */ add_wait_queue(&port->write_wait, &wait); set_current_state (TASK_INTERRUPTIBLE); @@ -520,9 +547,9 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) { /* ftdi_sio_serial_buld_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct ftdi_private *priv = (struct ftdi_private *)port->private; struct usb_serial *serial; struct tty_struct *tty = port->tty ; + char error_flag; unsigned char *data = urb->transfer_buffer; const int data_offset = 2; @@ -549,23 +576,76 @@ if (urb->actual_length > 2) { usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); } else { - dbg("Just status"); + dbg("Just status 0o%03o0o%03o",data[0],data[1]); } - priv->last_status_byte = data[0]; /* this has modem control lines */ /* TO DO -- check for hung up line and handle appropriately: */ /* send hangup */ /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ /* if CD is dropped and the line is not CLOCAL then we should hangup */ - + /* Handle errors and break */ + error_flag = TTY_NORMAL; + /* Although the device uses a bitmask and hence can have multiple */ + /* errors on a packet - the order here sets the priority the */ + /* error is returned to the tty layer */ + + if ( data[1] & FTDI_RS_OE ) { + error_flag = TTY_OVERRUN; + dbg("OVERRRUN error"); + } + if ( data[1] & FTDI_RS_BI ) { + error_flag = TTY_BREAK; + dbg("BREAK received"); + } + if ( data[1] & FTDI_RS_PE ) { + error_flag = TTY_PARITY; + dbg("PARITY error"); + } + if ( data[1] & FTDI_RS_FE ) { + error_flag = TTY_FRAME; + dbg("FRAMING error"); + } if (urb->actual_length > data_offset) { + for (i = data_offset ; i < urb->actual_length ; ++i) { - tty_insert_flip_char(tty, data[i], 0); - } + /* have to make sure we don't overflow the buffer + with tty_insert_flip_char's */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* Note that the error flag is duplicated for + every character received since we don't know + which character it applied to */ + tty_insert_flip_char(tty, data[i], error_flag); + } tty_flip_buffer_push(tty); + + + } + +#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW + /* if a parity error is detected you get status packets forever + until a character is sent without a parity error. + This doesn't work well since the application receives a never + ending stream of bad data - even though new data hasn't been sent. + Therefore I (bill) have taken this out. + However - this might make sense for framing errors and so on + so I am leaving the code in for now. + */ + else { + if (error_flag != TTY_NORMAL){ + dbg("error_flag is not normal"); + /* In this case it is just status - if that is an error send a bad character */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + tty_insert_flip_char(tty, 0xff, error_flag); + tty_flip_buffer_push(tty); + } } +#endif /* Continue trying to always read */ FILL_BULK_URB(urb, serial->dev, @@ -627,6 +707,38 @@ return(urb_value); } +static void ftdi_sio_break_ctl( struct usb_serial_port *port, int break_state ) +{ + struct usb_serial *serial = port->serial; + struct ftdi_private *priv = (struct ftdi_private *)port->private; + __u16 urb_value = 0; + char buf[1]; + + /* break_state = -1 to turn on break, and 0 to turn off break */ + /* see drivers/char/tty_io.c to see it used */ + /* last_set_data_urb_value NEVER has the break bit set in it */ + + if (break_state) { + urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; + } else { + urb_value = priv->last_set_data_urb_value; + } + + + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + urb_value , 0, + buf, 0, WDR_TIMEOUT) < 0) { + err(__FUNCTION__ " FAILED to enable/disable break state (state was %d)",break_state); + } + + dbg(__FUNCTION__ " break state is %d - urb is %d",break_state, urb_value); + +} + + + /* As I understand this - old_termios contains the original termios settings */ /* and tty->termios contains the new setting to be used */ /* */ @@ -670,6 +782,11 @@ err("CSIZE was set but not CS5-CS8"); } } + + /* This is needed by the break command since it uses the same command - but is + * or'ed with this value */ + priv->last_set_data_urb_value = urb_value; + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, @@ -743,7 +860,7 @@ struct usb_serial *serial = port->serial; struct ftdi_private *priv = (struct ftdi_private *)port->private; __u16 urb_value=0; /* Will hold the new flags */ - char buf[1]; + char buf[2]; int ret, mask; dbg(__FUNCTION__ " cmd 0x%04x", cmd); @@ -753,12 +870,7 @@ case TIOCMGET: dbg(__FUNCTION__ " TIOCMGET"); - /* The MODEM_STATUS_REQUEST works for the sio but not the 232 */ if (priv->ftdi_type == sio){ - /* TO DECIDE - use the 40ms status packets or not? */ - /* PRO: No need to send urb */ - /* CON: Could be 40ms out of date */ - /* Request the status from the device */ if ((ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -771,8 +883,18 @@ return(ret); } } else { - /* This gets updated every 40ms - so just copy it in */ - buf[0] = priv->last_status_byte; + /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same + format as the data returned from the in point */ + if ((ret = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, + 0, 0, + buf, 2, WDR_TIMEOUT)) < 0 ) { + err(__FUNCTION__ " Could not get modem status of device - err: %d", + ret); + return(ret); + } } return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | @@ -863,6 +985,8 @@ dbg(__FUNCTION__); usb_serial_register (&ftdi_sio_device); usb_serial_register (&ftdi_8U232AM_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -878,8 +1002,8 @@ module_init(ftdi_sio_init); module_exit(ftdi_sio_exit); -MODULE_AUTHOR("Greg Kroah-Hartman , Bill Ryder "); -MODULE_DESCRIPTION("USB FTDI RS232 converters driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/ftdi_sio.h linux/drivers/usb/serial/ftdi_sio.h --- v2.4.4/linux/drivers/usb/serial/ftdi_sio.h Tue Dec 5 23:15:12 2000 +++ linux/drivers/usb/serial/ftdi_sio.h Thu May 24 14:55:51 2001 @@ -146,7 +146,7 @@ #define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 ) #define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 ) #define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 ) - +#define FTDI_SIO_SET_BREAK (0x1 << 14) /* FTDI_SIO_SET_DATA */ /* @@ -170,7 +170,10 @@ * 0 = 1 * 1 = 1.5 * 2 = 2 - * B14..15 Reserved + * B14 + * 1 = TX ON (break) + * 0 = TX OFF (normal state) + * B15 Reserved * */ @@ -434,6 +437,17 @@ * B6 Transmitter Empty (TEMT) * B7 Error in RCVR FIFO * + */ +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1<<1) +#define FTDI_RS_PE (1<<2) +#define FTDI_RS_FE (1<<3) +#define FTDI_RS_BI (1<<4) +#define FTDI_RS_THRE (1<<5) +#define FTDI_RS_TEMT (1<<6) +#define FTDI_RS_FIFO (1<<7) + +/* * OUT Endpoint * * This device reserves the first bytes of data on this endpoint contain the length diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c --- v2.4.4/linux/drivers/usb/serial/io_edgeport.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/usb/serial/io_edgeport.c Mon May 21 15:02:06 2001 @@ -24,6 +24,9 @@ * Edgeport/8i * * Version history: + * + * (04/08/2001) gb + * - Identify version on module load. * * 2.0 2001_03_05 greg kroah-hartman * - reworked entire driver to fit properly in with the other usb-serial @@ -254,6 +257,13 @@ #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ +/* + * Version Information + */ +#define DRIVER_VERSION "v2.0.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman and David Iacovelli" +#define DRIVER_DESC "Edgeport USB Serial Driver" + /* First, the latest boot code - for first generation edgeports */ #define IMAGE_ARRAY_NAME BootCodeImage_GEN1 #define IMAGE_VERSION_NAME BootCodeImageVersion_GEN1 @@ -275,13 +285,6 @@ #include "io_fw_down2.h" /* Define array OperationalCodeImage[] */ -/* Module information */ -MODULE_AUTHOR("Greg Kroah-Hartman and David Iacovelli"); -MODULE_DESCRIPTION("Edgeport USB Serial Driver"); - -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - #define MAX_NAME_LEN 64 @@ -3034,7 +3037,8 @@ usb_serial_register (&edgeport_16dual_device); usb_serial_register (&edgeport_compat_id_device); usb_serial_register (&edgeport_8i_device); - + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -3066,4 +3070,11 @@ module_init(edgeport_init); module_exit(edgeport_exit); + +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- v2.4.4/linux/drivers/usb/serial/keyspan.c Thu Apr 12 12:16:36 2001 +++ linux/drivers/usb/serial/keyspan.c Mon May 21 15:02:06 2001 @@ -28,6 +28,9 @@ open source projects. Change History + (04/08/2001) gb + Identify version on module load. + (11/01/2000) Adam J. Richter usb_device_id table support. @@ -74,6 +77,13 @@ #include "usb-serial.h" #include "keyspan.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Hugh Blemings " +#define DRIVER_DESC "Keyspan USB to Serial Converter Driver" + #define INSTAT_BUFLEN 32 #define GLOCONT_BUFLEN 64 @@ -166,6 +176,10 @@ usb_serial_register (&keyspan_usa28_device); usb_serial_register (&keyspan_usa28x_device); usb_serial_register (&keyspan_usa49w_device); + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -1287,7 +1301,21 @@ msg.setPrescaler = 0xff; } - msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1; + msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; + switch (p_priv->cflag & CSIZE) { + case CS5: + msg.lcr |= USA_DATABITS_5; + break; + case CS6: + msg.lcr |= USA_DATABITS_6; + break; + case CS7: + msg.lcr |= USA_DATABITS_7; + break; + case CS8: + msg.lcr |= USA_DATABITS_8; + break; + } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ msg.lcr |= (p_priv->cflag & PARODD)? @@ -1480,7 +1508,21 @@ //msg.setPrescaler = 0xff; } - msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1; + msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; + switch (p_priv->cflag & CSIZE) { + case CS5: + msg.lcr |= USA_DATABITS_5; + break; + case CS6: + msg.lcr |= USA_DATABITS_6; + break; + case CS7: + msg.lcr |= USA_DATABITS_7; + break; + case CS8: + msg.lcr |= USA_DATABITS_8; + break; + } if (p_priv->cflag & PARENB) { /* note USA_PARITY_NONE == 0 */ msg.lcr |= (p_priv->cflag & PARODD)? @@ -1673,6 +1715,9 @@ kfree(port->private); } } + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c --- v2.4.4/linux/drivers/usb/serial/keyspan_pda.c Fri Apr 6 15:51:51 2001 +++ linux/drivers/usb/serial/keyspan_pda.c Mon May 21 15:02:06 2001 @@ -12,6 +12,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (04/08/2001) gb + * Identify version on module load. + * * (11/01/2000) Adam J. Richter * usb_device_id table support * @@ -85,6 +88,13 @@ #include "keyspan_pda_fw.h" #include "usb-serial.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Brian Warner " +#define DRIVER_DESC "USB Keyspan PDA Converter driver" + struct keyspan_pda_private { int tx_room; int tx_throttled; @@ -807,6 +817,8 @@ { usb_serial_register (&keyspan_pda_fake_device); usb_serial_register (&keyspan_pda_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -821,8 +833,8 @@ module_init(keyspan_pda_init); module_exit(keyspan_pda_exit); -MODULE_AUTHOR("Brian Warner "); -MODULE_DESCRIPTION("USB Keyspan PDA Converter driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/keyspan_pda_fw.h linux/drivers/usb/serial/keyspan_pda_fw.h --- v2.4.4/linux/drivers/usb/serial/keyspan_pda_fw.h Fri Mar 10 13:19:34 2000 +++ linux/drivers/usb/serial/keyspan_pda_fw.h Sat May 19 17:47:55 2001 @@ -1,9 +1,15 @@ /* - * keyspan_pda_fw.h + * USB Keyspan PDA Firmware + * + * Copyright (c) 1999, 2000 Brian Warner + * + * 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. * * Generated from keyspan_pda.s by ezusb_convert.pl - * This file is presumed to be under the same copyright as the source file - * from which it was derived. + * */ static const struct ezusb_hex_record keyspan_pda_firmware[] = { diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c --- v2.4.4/linux/drivers/usb/serial/mct_u232.c Fri Apr 6 15:51:52 2001 +++ linux/drivers/usb/serial/mct_u232.c Thu May 24 14:55:51 2001 @@ -24,6 +24,17 @@ * Basic tests have been performed with minicom/zmodem transfers and * modem dialing under Linux 2.4.0-test10 (for me it works fine). * + * 04-May-2001 Stelian Pop + * - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes + * instead of the device reported 32 (using 32 bytes causes many data + * loss, Windows driver uses 16 too). + * + * 02-May-2001 Stelian Pop + * - Fixed the baud calculation for Sitecom U232-P25 model + * + * 08-Apr-2001 gb + * - Identify version on module load. + * * 06-Jan-2001 Cornel Ciocirlan * - Added support for Sitecom U232-P25 model (Product Id 0x0230) * - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200) @@ -66,6 +77,13 @@ /* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Wolfgang Grandegger " +#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" + +/* * Some not properly written applications do not handle the return code of * write() correctly. This can result in character losses. A work-a-round * can be compiled in with the following definition. This work-a-round @@ -218,11 +236,31 @@ #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) { + if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID) { + switch (value) { + case 300: return 0x01; + case 600: return 0x02; /* this one not tested */ + case 1200: return 0x03; + case 2400: return 0x04; + case 4800: return 0x06; + case 9600: return 0x08; + case 19200: return 0x09; + case 38400: return 0x0a; + case 57600: return 0x0b; + case 115200: return 0x0c; + default: return -1; /* normally not reached */ + } + } + else + return MCT_U232_BAUD_RATE(value); +} + static int mct_u232_set_baud_rate(struct usb_serial *serial, int value) { unsigned int divisor; int rc; - divisor = MCT_U232_BAUD_RATE(value); + divisor = mct_u232_calculate_baud_rate(serial, value); rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_BAUD_RATE_REQUEST, MCT_U232_SET_REQUEST_TYPE, @@ -230,7 +268,7 @@ WDR_TIMEOUT); if (rc < 0) err("Set BAUD RATE %d failed (error = %d)", value, rc); - dbg("set_baud_rate: 0x%x", divisor); + dbg("set_baud_rate: value: %d, divisor: 0x%x", value, divisor); return rc; } /* mct_u232_set_baud_rate */ @@ -367,6 +405,14 @@ if (!port->active) { port->active = 1; + /* Compensate for a hardware bug: although the Sitecom U232-P25 + * device reports a maximum output packet size of 32 bytes, + * it seems to be able to accept only 16 bytes (and that's what + * SniffUSB says too...) + */ + if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID) + port->bulk_out_size = 16; + /* Do a defined restart: the normal serial device seems to * always turn on DTR and RTS here, so do the same. I'm not * sure if this is really necessary. But it should not harm @@ -824,7 +870,8 @@ usb_serial_register (&mct_u232_device); usb_serial_register (&mct_u232_sitecom_device); usb_serial_register (&mct_u232_du_h3sp_device); - + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -840,8 +887,8 @@ module_init (mct_u232_init); module_exit(mct_u232_exit); -MODULE_AUTHOR("Wolfgang Grandegger "); -MODULE_DESCRIPTION("Magic Control Technology USB-RS232 converter driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); #ifdef FIX_WRITE_RETURN_CODE_PROBLEM MODULE_PARM(write_blocking, "i"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c --- v2.4.4/linux/drivers/usb/serial/omninet.c Fri Apr 6 15:51:52 2001 +++ linux/drivers/usb/serial/omninet.c Mon May 21 15:02:06 2001 @@ -9,6 +9,9 @@ * See Documentation/usb/usb-serial.txt for more information on using this driver * * Please report both successes and troubles to the author at omninet@kroah.com + * + * (04/08/2001) gb + * Identify version on module load. * * (11/01/2000) Adam J. Richter * usb_device_id table support @@ -54,6 +57,13 @@ #include "usb-serial.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Anonymous" +#define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" + #define ZYXEL_VENDOR_ID 0x0586 #define ZYXEL_OMNINET_ID 0x1000 @@ -396,6 +406,8 @@ static int __init omninet_init (void) { usb_serial_register (&zyxel_omninet_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -408,6 +420,9 @@ module_init(omninet_init); module_exit(omninet_exit); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.4/linux/drivers/usb/serial/usbserial.c Fri Apr 6 15:51:52 2001 +++ linux/drivers/usb/serial/usbserial.c Mon May 21 15:02:06 2001 @@ -14,6 +14,9 @@ * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (04/08/2001) gb + * Identify version on module load. * * 2001_02_05 gkh * Fixed buffer overflows bug with the generic serial driver. Thanks to @@ -282,14 +285,12 @@ #include "usb-serial.h" - -/* Module information */ -MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); -MODULE_DESCRIPTION("USB Serial Driver"); - -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/" +#define DRIVER_DESC "USB Serial Driver" #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -309,11 +310,6 @@ #ifdef CONFIG_USB_SERIAL_GENERIC static __u16 vendor = 0x05f9; static __u16 product = 0xffff; -MODULE_PARM(vendor, "i"); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -MODULE_PARM(product, "i"); -MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ @@ -1398,8 +1394,10 @@ err("usb_register failed for the usb-serial driver. Error number %d", result); return -1; } - - + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -1463,4 +1461,18 @@ EXPORT_SYMBOL(ezusb_writememory); EXPORT_SYMBOL(ezusb_set_reset); #endif + + +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +MODULE_PARM(vendor, "i"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); + +MODULE_PARM(product, "i"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.4/linux/drivers/usb/serial/visor.c Fri Apr 6 15:51:52 2001 +++ linux/drivers/usb/serial/visor.c Mon May 21 15:02:06 2001 @@ -10,6 +10,9 @@ * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (04/08/2001) gb + * Identify version on module load. * * (01/21/2000) gkh * Added write_room and chars_in_buffer, as they were previously using the @@ -103,6 +106,13 @@ #include "usb-serial.h" #include "visor.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "USB HandSpring Visor driver" + #define MIN(a,b) (((a)<(b))?(a):(b)) /* function prototypes for a handspring visor */ @@ -653,7 +663,10 @@ continue; } } - + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; } @@ -686,8 +699,8 @@ module_init(visor_init); module_exit(visor_exit); -MODULE_AUTHOR("Greg Kroah-Hartman "); -MODULE_DESCRIPTION("USB HandSpring Visor driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c --- v2.4.4/linux/drivers/usb/serial/whiteheat.c Fri Apr 6 15:51:52 2001 +++ linux/drivers/usb/serial/whiteheat.c Mon May 21 15:02:06 2001 @@ -10,6 +10,9 @@ * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (04/08/2001) gb + * Identify version on module load. * * 2001_Mar_19 gkh * Fixed MOD_INC and MOD_DEC logic, the ability to open a port more @@ -79,6 +82,13 @@ #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ #include "whiteheat.h" /* WhiteHEAT specific commands */ +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" + #define CONNECT_TECH_VENDOR_ID 0x0710 #define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 #define CONNECT_TECH_WHITE_HEAT_ID 0x8001 @@ -616,6 +626,8 @@ { usb_serial_register (&whiteheat_fake_device); usb_serial_register (&whiteheat_device); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } @@ -630,8 +642,8 @@ module_init(whiteheat_init); module_exit(whiteheat_exit); -MODULE_AUTHOR("Greg Kroah-Hartman "); -MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c --- v2.4.4/linux/drivers/usb/storage/dpcm.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/dpcm.c Sat Apr 28 11:28:08 2001 @@ -10,7 +10,7 @@ * (c) 2000 Brian Webb (webbb@earthlink.net) * * This device contains both a CompactFlash card reader, which - * usest the Control/Bulk w/o Interrupt protocol and + * uses the Control/Bulk w/o Interrupt protocol and * a SmartMedia card reader that uses the same protocol * as the SDDR09. * diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h --- v2.4.4/linux/drivers/usb/storage/unusual_devs.h Fri Apr 27 15:49:28 2001 +++ linux/drivers/usb/storage/unusual_devs.h Fri May 25 18:02:43 2001 @@ -79,6 +79,12 @@ "CameraMate (DPCM_USB)", US_SC_SCSI, US_PR_DPCM_USB, NULL, US_FL_START_STOP ), + +UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, + "SCM Microsystems Inc", + "eUSB SmartMedia / CompactFlash Adapter", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP ), #endif UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0200, diff -u --recursive --new-file v2.4.4/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h --- v2.4.4/linux/drivers/usb/uhci-debug.h Fri Apr 27 15:50:01 2001 +++ linux/drivers/usb/uhci-debug.h Fri May 25 18:03:15 2001 @@ -9,6 +9,7 @@ * (C) Copyright 1999-2001 Johannes Erdfelt */ +#include #include #include #include diff -u --recursive --new-file v2.4.4/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.4.4/linux/drivers/usb/uhci.c Wed Apr 25 14:10:49 2001 +++ linux/drivers/usb/uhci.c Mon May 21 15:02:06 2001 @@ -57,6 +57,15 @@ #include + +/* + * Version Information + */ +#define DRIVER_VERSION "" +#define DRIVER_AUTHOR "Linus 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 @@ -644,21 +653,23 @@ urb->hcpriv = urbp; - if (urb->transfer_buffer_length) { - urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : - PCI_DMA_TODEVICE); - if (!urbp->transfer_buffer_dma_handle) - return NULL; - } - - if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { - urbp->setup_packet_dma_handle = pci_map_single(uhci->dev, - urb->setup_packet, sizeof(devrequest), - PCI_DMA_TODEVICE); - if (!urbp->setup_packet_dma_handle) - return NULL; + if (urb->dev != uhci->rh.dev) { + if (urb->transfer_buffer_length) { + urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev, + urb->transfer_buffer, urb->transfer_buffer_length, + usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : + PCI_DMA_TODEVICE); + if (!urbp->transfer_buffer_dma_handle) + return NULL; + } + + if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { + urbp->setup_packet_dma_handle = pci_map_single(uhci->dev, + urb->setup_packet, sizeof(devrequest), + PCI_DMA_TODEVICE); + if (!urbp->setup_packet_dma_handle) + return NULL; + } } return urbp; @@ -722,11 +733,11 @@ uhci_free_td(uhci, td); } - if (urb->setup_packet) + if (urbp->setup_packet_dma_handle) pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length) + 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); @@ -2247,12 +2258,12 @@ if (!killed) urb->status = status; - if (urb->transfer_buffer_length) + 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) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) + if (urbp->setup_packet_dma_handle) pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); @@ -2910,6 +2921,7 @@ release_uhci(uhci); } +#ifdef CONFIG_PM static void uhci_pci_suspend(struct pci_dev *dev) { reset_hc((struct uhci *) dev->driver_data); @@ -2920,6 +2932,7 @@ reset_hc((struct uhci *) dev->driver_data); start_hc((struct uhci *) dev->driver_data); } +#endif static const struct pci_device_id __devinitdata uhci_pci_ids[] = { { @@ -2977,6 +2990,9 @@ if (retval) goto init_failed; + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; init_failed: @@ -3016,6 +3032,6 @@ module_init(uhci_hcd_init); module_exit(uhci_hcd_cleanup); -MODULE_AUTHOR("Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"); -MODULE_DESCRIPTION("USB Universal Host Controller Interface driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.4/linux/drivers/usb/usb-ohci.c Wed Apr 25 14:10:49 2001 +++ linux/drivers/usb/usb-ohci.c Tue May 22 13:55:49 2001 @@ -12,6 +12,7 @@ * * History: * + * 2001/04/08 Identify version on module load gb * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam); pci_map_single (db) * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) @@ -85,6 +86,13 @@ #endif +/* + * Version Information + */ +#define DRIVER_VERSION "v5.2" +#define DRIVER_AUTHOR "Roman Weissgaerber , David Brownell" +#define DRIVER_DESC "USB OHCI Host Controller Driver" + /* For initializing controller (mask in an HCFS mode too) */ #define OHCI_CONTROL_INIT \ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE @@ -597,12 +605,14 @@ urb_priv->length = size; urb_priv->ed = ed; - /* allocate the TDs */ + /* allocate the TDs (updating hash chains) */ + spin_lock_irqsave (&usb_ed_lock, flags); for (i = 0; i < size; i++) { - urb_priv->td[i] = td_alloc (ohci, mem_flags); + urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC); if (!urb_priv->td[i]) { urb_priv->length = i; urb_free_priv (ohci, urb_priv); + spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); return -ENOMEM; } @@ -610,6 +620,7 @@ if (ed->state == ED_NEW || (ed->state & ED_DEL)) { urb_free_priv (ohci, urb_priv); + spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); return -EINVAL; } @@ -631,6 +642,7 @@ } if (bustime < 0) { urb_free_priv (ohci, urb_priv); + spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); return bustime; } @@ -640,7 +652,6 @@ #endif } - spin_lock_irqsave (&usb_ed_lock, flags); urb->actual_length = 0; urb->hcpriv = urb_priv; urb->status = USB_ST_URB_PENDING; @@ -1182,7 +1193,7 @@ if (ed->state == ED_NEW) { ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */ /* dummy td; end of td list for ed */ - td = td_alloc (ohci, mem_flags); + td = td_alloc (ohci, SLAB_ATOMIC); /* hash the ed for later reverse mapping */ if (!td || !hash_add_ed (ohci, (ed_t *)ed)) { /* out of memory */ @@ -2248,6 +2259,7 @@ // Count and limit the retries though; either hardware or // software errors can go forever... #endif + hc_reset (ohci); } if (ints & OHCI_INTR_WDH) { @@ -2261,6 +2273,7 @@ writel (OHCI_INTR_SO, ®s->intrenable); } + // FIXME: this assumes SOF (1/ms) interrupts don't get lost... if (ints & OHCI_INTR_SF) { unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1; writel (OHCI_INTR_SF, ®s->intrdisable); @@ -2504,6 +2517,11 @@ if (pci_enable_device(dev) < 0) return -ENODEV; + + if (!dev->irq) { + err("found OHCI device with no IRQ assigned. check BIOS settings!"); + return -ENODEV; + } /* we read its hardware registers as memory */ mem_resource = pci_resource_start(dev, 0); @@ -2756,6 +2774,8 @@ #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier (&ohci_sleep_notifier); #endif + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return ret; } @@ -2773,5 +2793,5 @@ module_exit (ohci_hcd_cleanup); -MODULE_AUTHOR ("Roman Weissgaerber , David Brownell"); -MODULE_DESCRIPTION ("USB OHCI Host Controller Driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h --- v2.4.4/linux/drivers/usb/usb-ohci.h Wed Apr 25 14:10:49 2001 +++ linux/drivers/usb/usb-ohci.h Sun May 20 12:11:39 2001 @@ -29,6 +29,7 @@ /* Not Access */ USB_ST_NORESPONSE }; +#include /* ED States */ diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb-uhci-debug.h linux/drivers/usb/usb-uhci-debug.h --- v2.4.4/linux/drivers/usb/usb-uhci-debug.h Sat Jul 8 19:38:16 2000 +++ linux/drivers/usb/usb-uhci-debug.h Wed May 16 10:31:27 2001 @@ -5,7 +5,7 @@ dbg("qh has not QH_TYPE"); return; } - dbg("QH @ %p/%08lX:", qh, virt_to_bus (qh)); + dbg("QH @ %p/%08X:", qh, qh->dma_addr); if (qh->hw.qh.head & UHCI_PTR_TERM) dbg(" Head Terminate"); @@ -23,6 +23,7 @@ } #endif +#if 0 static void uhci_show_td (puhci_desc_t td) { char *spid; @@ -42,8 +43,8 @@ break; } - warn(" TD @ %p/%08lX, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x", - td, virt_to_bus (td), + warn(" TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x", + td, td->dma_addr, td->hw.td.info >> 21, ((td->hw.td.info >> 19) & 1), (td->hw.td.info >> 15) & 15, @@ -74,10 +75,15 @@ td->hw.td.link & ~UHCI_PTR_BITS, (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first")); } +#endif + #ifdef DEBUG static void __attribute__((__unused__)) uhci_show_td_queue (puhci_desc_t td) { - //dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td)); + //dbg("uhci_show_td_queue %p (%08lX):", td, td->dma_addr); +#if 1 + return; +#else while (1) { uhci_show_td (td); if (td->hw.td.link & UHCI_PTR_TERM) @@ -89,13 +95,19 @@ break; } } +#endif } static void __attribute__((__unused__)) uhci_show_queue (puhci_desc_t qh) { +#if 0 uhci_desc_t *start_qh=qh; +#endif dbg("uhci_show_queue %p:", qh); +#if 1 + return; +#else while (1) { uhci_show_qh (qh); @@ -117,6 +129,7 @@ break; } } +#endif } static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status) diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.4/linux/drivers/usb/usb-uhci.c Fri Apr 27 15:13:07 2001 +++ linux/drivers/usb/usb-uhci.c Mon May 21 15:02:06 2001 @@ -58,6 +58,13 @@ #include "usb-uhci.h" #include "usb-uhci-debug.h" +/* + * Version Information + */ +#define DRIVER_VERSION "v1.251" +#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" +#define DRIVER_DESC "USB Universal Host Controller Interface driver" + #undef DEBUG #undef dbg #define dbg(format, arg...) do {} while (0) @@ -75,7 +82,6 @@ #define async_dbg dbg //err #ifdef DEBUG_SLAB - static kmem_cache_t *uhci_desc_kmem; static kmem_cache_t *urb_priv_kmem; #endif @@ -128,17 +134,17 @@ { if (!list_empty(&s->urb_unlinked)) { - s->td1ms->hw.td.status |= TD_CTRL_IOC; + s->td1ms->hw.td.status |= cpu_to_le32(TD_CTRL_IOC); } else { - s->td1ms->hw.td.status &= ~TD_CTRL_IOC; + s->td1ms->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC); } if (s->timeout_urbs) { - s->td32ms->hw.td.status |= TD_CTRL_IOC; + s->td32ms->hw.td.status |= cpu_to_le32(TD_CTRL_IOC); } else { - s->td32ms->hw.td.status &= ~TD_CTRL_IOC; + s->td32ms->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC); } wmb(); @@ -153,7 +159,7 @@ return; spin_lock_irqsave (&s->qh_lock, flags); - s->chain_end->hw.qh.head&=~UHCI_PTR_TERM; + s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM); mb(); s->loop_usage++; ((urb_priv_t*)urb->hcpriv)->use_loop=1; @@ -172,7 +178,7 @@ s->loop_usage--; if (!s->loop_usage) { - s->chain_end->hw.qh.head|=UHCI_PTR_TERM; + s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM); mb(); } ((urb_priv_t*)urb->hcpriv)->use_loop=0; @@ -226,17 +232,16 @@ } /*-------------------------------------------------------------------*/ -_static int alloc_td (uhci_desc_t ** new, int flags) +_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags) { -#ifdef DEBUG_SLAB - *new= kmem_cache_alloc(uhci_desc_kmem, SLAB_FLAG); -#else - *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), KMALLOC_FLAG); -#endif + dma_addr_t dma_handle; + + *new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle); if (!*new) return -ENOMEM; - memset (*new, 0, sizeof (uhci_desc_t)); - (*new)->hw.td.link = UHCI_PTR_TERM | (flags & UHCI_PTR_BITS); // last by default + memset (*new, 0, sizeof (uhci_desc_t)); + (*new)->dma_addr = dma_handle; + (*new)->hw.td.link = cpu_to_le32(UHCI_PTR_TERM | (flags & UHCI_PTR_BITS)); // last by default (*new)->type = TD_TYPE; mb(); INIT_LIST_HEAD (&(*new)->vertical); @@ -252,7 +257,7 @@ spin_lock_irqsave (&s->td_lock, xxx); - td->hw.td.link = virt_to_bus (qh) | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH; + td->hw.td.link = cpu_to_le32(qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH); mb(); spin_unlock_irqrestore (&s->td_lock, xxx); @@ -272,11 +277,11 @@ if (qh == prev ) { // virgin qh without any tds - qh->hw.qh.element = virt_to_bus (new) | UHCI_PTR_TERM; + qh->hw.qh.element = cpu_to_le32(new->dma_addr | UHCI_PTR_TERM); } else { // already tds inserted, implicitely remove TERM bit of prev - prev->hw.td.link = virt_to_bus (new) | (flags & UHCI_PTR_DEPTH); + prev->hw.td.link = cpu_to_le32(new->dma_addr | (flags & UHCI_PTR_DEPTH)); } mb(); spin_unlock_irqrestore (&s->td_lock, xxx); @@ -295,7 +300,7 @@ next = list_entry (td->horizontal.next, uhci_desc_t, horizontal); list_add (&new->horizontal, &td->horizontal); new->hw.td.link = td->hw.td.link; - td->hw.td.link = virt_to_bus (new); + td->hw.td.link = cpu_to_le32(new->dma_addr); mb(); spin_unlock_irqrestore (&s->td_lock, flags); @@ -340,29 +345,24 @@ } /*-------------------------------------------------------------------*/ -_static int delete_desc (uhci_desc_t *element) +_static int delete_desc (uhci_t *s, uhci_desc_t *element) { -#ifdef DEBUG_SLAB - kmem_cache_free(uhci_desc_kmem, element); -#else - kfree (element); -#endif + pci_pool_free(s->desc_pool, element, element->dma_addr); return 0; } /*-------------------------------------------------------------------*/ // Allocates qh element -_static int alloc_qh (uhci_desc_t ** new) +_static int alloc_qh (uhci_t *s, uhci_desc_t ** new) { -#ifdef DEBUG_SLAB - *new= kmem_cache_alloc(uhci_desc_kmem, SLAB_FLAG); -#else - *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), KMALLOC_FLAG); -#endif + dma_addr_t dma_handle; + + *new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle); if (!*new) return -ENOMEM; memset (*new, 0, sizeof (uhci_desc_t)); - (*new)->hw.qh.head = UHCI_PTR_TERM; - (*new)->hw.qh.element = UHCI_PTR_TERM; + (*new)->dma_addr = dma_handle; + (*new)->hw.qh.head = cpu_to_le32(UHCI_PTR_TERM); + (*new)->hw.qh.element = cpu_to_le32(UHCI_PTR_TERM); (*new)->type = QH_TYPE; mb(); @@ -387,16 +387,16 @@ // (OLD) (POS) -> (OLD) (NEW) (POS) old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal); list_add_tail (&new->horizontal, &pos->horizontal); - new->hw.qh.head = MAKE_QH_ADDR (pos) ; - if (!(old->hw.qh.head & UHCI_PTR_TERM)) - old->hw.qh.head = MAKE_QH_ADDR (new) ; + new->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (pos)) ; + if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM))) + old->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (new)) ; } else { // (POS) (OLD) -> (POS) (NEW) (OLD) old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal); list_add (&new->horizontal, &pos->horizontal); - new->hw.qh.head = MAKE_QH_ADDR (old); - pos->hw.qh.head = MAKE_QH_ADDR (new) ; + new->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (old)); + pos->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (new)) ; } mb (); @@ -418,7 +418,7 @@ prev->hw.qh.head = element->hw.qh.head; dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, - list_entry (element->horizontal.next, uhci_desc_t, horizontal),element->hw.qh.head &~15); + list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15); list_del(&element->horizontal); @@ -439,15 +439,15 @@ td = list_entry (p, uhci_desc_t, vertical); dbg("unlink td @ %p",td); unlink_td (s, td, 0); // no physical unlink - delete_desc (td); + delete_desc (s, td); } - delete_desc (qh); + delete_desc (s, qh); return 0; } /*-------------------------------------------------------------------*/ -_static void clean_td_chain (uhci_desc_t *td) +_static void clean_td_chain (uhci_t *s, uhci_desc_t *td) { struct list_head *p; uhci_desc_t *td1; @@ -457,18 +457,18 @@ while ((p = td->horizontal.next) != &td->horizontal) { td1 = list_entry (p, uhci_desc_t, horizontal); - delete_desc (td1); + delete_desc (s, td1); } - delete_desc (td); + delete_desc (s, td); } /*-------------------------------------------------------------------*/ _static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer) { - td->hw.td.status = status; - td->hw.td.info = info; - td->hw.td.buffer = buffer; + td->hw.td.status = cpu_to_le32(status); + td->hw.td.info = cpu_to_le32(info); + td->hw.td.buffer = cpu_to_le32(buffer); } /*-------------------------------------------------------------------*/ // Removes ALL qhs in chain (paranoia!) @@ -485,24 +485,25 @@ if (s->td32ms) { unlink_td(s,s->td32ms,1); - delete_desc(s->td32ms); + delete_desc(s, s->td32ms); } for (n = 0; n < 8; n++) { td = s->int_chain[n]; - clean_td_chain (td); + clean_td_chain (s, td); } if (s->iso_td) { for (n = 0; n < 1024; n++) { td = s->iso_td[n]; - clean_td_chain (td); + clean_td_chain (s, td); } kfree (s->iso_td); } if (s->framelist) - free_page ((unsigned long) s->framelist); + pci_free_consistent(s->uhci_pci, PAGE_SIZE, + s->framelist, s->framelist_dma); if (s->control_chain) { // completed init_skel? @@ -519,14 +520,20 @@ } else { if (s->ls_control_chain) - delete_desc (s->ls_control_chain); + delete_desc (s, s->ls_control_chain); if (s->control_chain) - delete_desc(s->control_chain); + delete_desc(s, s->control_chain); if (s->bulk_chain) - delete_desc (s->bulk_chain); + delete_desc (s, s->bulk_chain); if (s->chain_end) - delete_desc (s->chain_end); + delete_desc (s, s->chain_end); + } + + if (s->desc_pool) { + pci_pool_destroy(s->desc_pool); + s->desc_pool = NULL; } + dbg("cleanup_skel finished"); } /*-------------------------------------------------------------------*/ @@ -539,13 +546,22 @@ dbg("init_skel"); - s->framelist = (__u32 *) get_free_page (GFP_KERNEL); + s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE, + &s->framelist_dma); if (!s->framelist) return -ENOMEM; memset (s->framelist, 0, 4096); + dbg("creating descriptor pci_pool"); + + s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci, + sizeof(uhci_desc_t), 16, 0, + GFP_DMA | GFP_ATOMIC); + if (!s->desc_pool) + goto init_skel_cleanup; + dbg("allocating iso desc pointer list"); s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL); @@ -560,33 +576,33 @@ dbg("allocating iso descs"); for (n = 0; n < 1024; n++) { // allocate skeleton iso/irq-tds - ret = alloc_td (&td, 0); + ret = alloc_td (s, &td, 0); if (ret) goto init_skel_cleanup; s->iso_td[n] = td; - s->framelist[n] = ((__u32) virt_to_bus (td)); + s->framelist[n] = cpu_to_le32((__u32) td->dma_addr); } dbg("allocating qh: chain_end"); - ret = alloc_qh (&qh); + ret = alloc_qh (s, &qh); if (ret) goto init_skel_cleanup; s->chain_end = qh; - ret = alloc_td (&td, 0); + ret = alloc_td (s, &td, 0); if (ret) goto init_skel_cleanup; fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand) insert_td (s, qh, td, 0); - qh->hw.qh.element &= ~UHCI_PTR_TERM; // remove TERM bit + qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit s->td1ms=td; dbg("allocating qh: bulk_chain"); - ret = alloc_qh (&qh); + ret = alloc_qh (s, &qh); if (ret) goto init_skel_cleanup; @@ -594,7 +610,7 @@ s->bulk_chain = qh; dbg("allocating qh: control_chain"); - ret = alloc_qh (&qh); + ret = alloc_qh (s, &qh); if (ret) goto init_skel_cleanup; @@ -603,11 +619,11 @@ #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH // disabled reclamation loop - s->chain_end->hw.qh.head=virt_to_bus(s->control_chain) | UHCI_PTR_QH | UHCI_PTR_TERM; + s->chain_end->hw.qh.head = cpu_to_le32(s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM); #endif dbg("allocating qh: ls_control_chain"); - ret = alloc_qh (&qh); + ret = alloc_qh (s, &qh); if (ret) goto init_skel_cleanup; @@ -622,15 +638,15 @@ for (n = 0; n < 8; n++) { uhci_desc_t *td; - alloc_td (&td, 0); + alloc_td (s, &td, 0); if (!td) goto init_skel_cleanup; s->int_chain[n] = td; if (n == 0) { - s->int_chain[0]->hw.td.link = virt_to_bus (s->ls_control_chain) | UHCI_PTR_QH; + s->int_chain[0]->hw.td.link = cpu_to_le32(s->ls_control_chain->dma_addr | UHCI_PTR_QH); } else { - s->int_chain[n]->hw.td.link = virt_to_bus (s->int_chain[0]); + s->int_chain[n]->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr); } } @@ -639,16 +655,17 @@ for (n = 0; n < 1024; n++) { // link all iso-tds to the interrupt chains int m, o; - dbg("framelist[%i]=%x",n,s->framelist[n]); + dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n])); if ((n&127)==127) - ((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]); + ((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr); else for (o = 1, m = 2; m <= 128; o++, m += m) if ((n & (m - 1)) == ((m - 1) / 2)) - ((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]); + ((uhci_desc_t*) s->iso_td[n])->hw.td.link = + cpu_to_le32(s->int_chain[o]->dma_addr); } - ret = alloc_td (&td, 0); + ret = alloc_td (s, &td, 0); if (ret) goto init_skel_cleanup; @@ -689,12 +706,12 @@ } dbg("uhci_submit_control start"); - alloc_qh (&qh); // alloc qh for this request + alloc_qh (s, &qh); // alloc qh for this request if (!qh) return -ENOMEM; - alloc_td (&td, UHCI_PTR_DEPTH * depth_first); // get td for setup stage + alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first); // get td for setup stage if (!td) { delete_qh (s, qh); @@ -709,7 +726,7 @@ (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); /* Build the TD for the control request, try forever, 8 bytes of data */ - fill_td (td, status, destination | (7 << 21), virt_to_bus (urb->setup_packet)); + fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma); insert_td (s, qh, td, 0); // queue 'setup stage'-td in qh #if 0 @@ -732,19 +749,18 @@ while (len > 0) { int pktsze = len; - alloc_td (&td, UHCI_PTR_DEPTH * depth_first); - if (!td) { - delete_qh (s, qh); - return -ENOMEM; - } + alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first); + if (!td) + goto fail_unmap_enomem; if (pktsze > maxsze) pktsze = maxsze; destination ^= 1 << TD_TOKEN_TOGGLE; // toggle DATA0/1 + // Status, pktsze bytes of data fill_td (td, status, destination | ((pktsze - 1) << 21), - virt_to_bus (data)); // Status, pktsze bytes of data + urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer)); insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first); // queue 'data stage'-td in qh @@ -764,12 +780,11 @@ destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ - alloc_td (&td, UHCI_PTR_DEPTH); + alloc_td (s, &td, UHCI_PTR_DEPTH); - if (!td) { - delete_qh (s, qh); - return -ENOMEM; - } + if (!td) + goto fail_unmap_enomem; + status &=~TD_CTRL_SPD; /* no limit on errors on final packet , 0 bytes of data */ @@ -783,7 +798,7 @@ urb->status = -EINPROGRESS; queue_urb (s, urb); // queue before inserting in desc chain - qh->hw.qh.element &= ~UHCI_PTR_TERM; + qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); //uhci_show_queue(qh); /* Start it up... put low speed first */ @@ -794,6 +809,10 @@ dbg("uhci_submit_control end"); return 0; + +fail_unmap_enomem: + delete_qh(s, qh); + return -ENOMEM; } /*-------------------------------------------------------------------*/ // For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh) @@ -829,15 +848,15 @@ upriv = (urb_priv_t*)urb->hcpriv; if (!bulk_urb) { - alloc_qh (&qh); // get qh for this request + alloc_qh (s, &qh); // get qh for this request if (!qh) return -ENOMEM; if (urb->transfer_flags & USB_QUEUE_BULK) { - alloc_qh(&nqh); // placeholder for clean unlink + alloc_qh(s, &nqh); // placeholder for clean unlink if (!nqh) { - delete_desc (qh); + delete_desc (s, qh); return -ENOMEM; } upriv->next_qh = nqh; @@ -853,17 +872,17 @@ } if (urb->transfer_flags & USB_QUEUE_BULK) { - alloc_qh (&bqh); // "bottom" QH, + alloc_qh (s, &bqh); // "bottom" QH, if (!bqh) { if (!bulk_urb) { - delete_desc(qh); - delete_desc(nqh); + delete_desc(s, qh); + delete_desc(s, nqh); } return -ENOMEM; } - bqh->hw.qh.element = UHCI_PTR_TERM; - bqh->hw.qh.head = virt_to_bus(nqh) | UHCI_PTR_QH; // element + bqh->hw.qh.element = cpu_to_le32(UHCI_PTR_TERM); + bqh->hw.qh.head = cpu_to_le32(nqh->dma_addr | UHCI_PTR_QH); // element upriv->bottom_qh = bqh; } queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh); @@ -882,7 +901,7 @@ do { // TBD: Really allow zero-length packets? int pktsze = len; - alloc_td (&td, UHCI_PTR_DEPTH * depth_first); + alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first); if (!td) { delete_qh (s, qh); @@ -896,7 +915,8 @@ info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); - fill_td (td, status, info, virt_to_bus (data)); + fill_td (td, status, info, + urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer)); data += pktsze; len -= pktsze; @@ -904,7 +924,7 @@ last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET))); if (last) - td->hw.td.status |= TD_CTRL_IOC; // last one generates INT + td->hw.td.status |= cpu_to_le32(TD_CTRL_IOC); // last one generates INT insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first); if (!first_td) @@ -925,9 +945,9 @@ queue_urb_unlocked (s, urb); if (urb->transfer_flags & USB_QUEUE_BULK) - qh->hw.qh.element = virt_to_bus (first_td); + qh->hw.qh.element = cpu_to_le32(first_td->dma_addr); else - qh->hw.qh.element &= ~UHCI_PTR_TERM; // arm QH + qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // arm QH if (!bulk_urb) { // new bulk queue if (urb->transfer_flags & USB_QUEUE_BULK) { @@ -964,7 +984,7 @@ while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) { td = list_entry (p, uhci_desc_t, desc_list); list_del (p); - delete_desc (td); + delete_desc (s, td); } } /*-------------------------------------------------------------------*/ @@ -996,7 +1016,7 @@ spin_lock_irqsave (&s->qh_lock, flags); prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list); prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical); - prevtd->hw.td.link = virt_to_bus(priv->bottom_qh) | UHCI_PTR_QH; // skip current qh + prevtd->hw.td.link = cpu_to_le32(priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh mb(); queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd); spin_unlock_irqrestore (&s->qh_lock, flags); @@ -1039,7 +1059,7 @@ if (!priv->prev_queued_urb) { // top QH prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal); - prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH; + prevqh->hw.qh.head = cpu_to_le32(bqh->dma_addr | UHCI_PTR_QH); list_del (&qh->horizontal); // remove this qh form horizontal chain list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain } @@ -1052,7 +1072,7 @@ ppriv->bottom_qh = bnqh; ppriv->next_queued_urb = nurb; prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list); - prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH; + prevqh->hw.qh.head = cpu_to_le32(bqh->dma_addr | UHCI_PTR_QH); } mb(); @@ -1083,6 +1103,38 @@ } } } + +_static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv) +{ + if (urb_priv->setup_packet_dma) + pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma, + sizeof(devrequest), PCI_DMA_TODEVICE); + + if (urb_priv->transfer_buffer_dma) + pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma, + urb->transfer_buffer_length, + usb_pipein(urb->pipe) ? + PCI_DMA_FROMDEVICE : + PCI_DMA_TODEVICE); +} + +_static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv) +{ + if (urb_priv->setup_packet_dma) { + pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma, + sizeof(devrequest), PCI_DMA_TODEVICE); + urb_priv->setup_packet_dma = 0; + } + if (urb_priv->transfer_buffer_dma) { + pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma, + urb->transfer_buffer_length, + usb_pipein(urb->pipe) ? + PCI_DMA_FROMDEVICE : + PCI_DMA_TODEVICE); + urb_priv->transfer_buffer_dma = 0; + } +} + /*-------------------------------------------------------------------*/ // unlinks an urb by dequeuing its qh, waits some frames and forgets it _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb) @@ -1133,6 +1185,8 @@ uhci_wait_ms(1); } + uhci_urb_dma_unmap(s, urb, urb->hcpriv); + #ifdef DEBUG_SLAB kmem_cache_free (urb_priv_kmem, urb->hcpriv); #else @@ -1210,6 +1264,7 @@ urb_priv = urb->hcpriv; list_del (&urb->urb_list); + uhci_urb_dma_sync(s, urb, urb_priv); if (urb->complete) { spin_unlock(&s->urb_list_lock); urb->dev = NULL; @@ -1226,6 +1281,8 @@ break; } + uhci_urb_dma_unmap(s, urb, urb_priv); + usb_dec_dev_use (dev); #ifdef DEBUG_SLAB kmem_cache_free (urb_priv_kmem, urb_priv); @@ -1452,7 +1509,7 @@ if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe))) return -EINVAL; - ret = alloc_td (&td, UHCI_PTR_DEPTH); + ret = alloc_td (s, &td, UHCI_PTR_DEPTH); if (ret) return -ENOMEM; @@ -1466,7 +1523,7 @@ info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); - fill_td (td, status, info, virt_to_bus (urb->transfer_buffer)); + fill_td (td, status, info, urb_priv->transfer_buffer_dma); list_add_tail (&td->desc_list, &urb_priv->desc_list); urb->status = -EINPROGRESS; @@ -1524,14 +1581,14 @@ } else #endif - ret = alloc_td (&td, UHCI_PTR_DEPTH); + ret = alloc_td (s, &td, UHCI_PTR_DEPTH); if (ret) { int i; // Cleanup allocated TDs for (i = 0; i < n; n++) if (tdm[i]) - delete_desc(tdm[i]); + delete_desc(s, tdm[i]); kfree (tdm); goto err; } @@ -1554,7 +1611,7 @@ status |= TD_CTRL_IOC; fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21), - virt_to_bus (urb->transfer_buffer + urb->iso_frame_desc[n].offset)); + urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset); list_add_tail (&td->desc_list, &urb_priv->desc_list); if (n == last) { @@ -1663,6 +1720,22 @@ urb_priv->bottom_qh = NULL; urb_priv->next_qh = NULL; + if (usb_pipetype (urb->pipe) == PIPE_CONTROL) + urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet, + sizeof(devrequest), PCI_DMA_TODEVICE); + else + urb_priv->setup_packet_dma = 0; + + if (urb->transfer_buffer_length) + urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci, + urb->transfer_buffer, + urb->transfer_buffer_length, + usb_pipein(urb->pipe) ? + PCI_DMA_FROMDEVICE : + PCI_DMA_TODEVICE); + else + urb_priv->transfer_buffer_dma = 0; + if (usb_pipetype (urb->pipe) == PIPE_BULK) { if (queued_urb) { @@ -1724,6 +1797,7 @@ dbg("submit_urb: scheduled with ret: %d", ret); if (ret != 0) { + uhci_urb_dma_unmap(s, urb, urb_priv); usb_dec_dev_use (urb->dev); #ifdef DEBUG_SLAB kmem_cache_free(urb_priv_kmem, urb_priv); @@ -2277,7 +2351,7 @@ */ if (urb_priv->flags && - ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) + ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) ||(!(last_desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))))) goto transfer_finished; urb->actual_length=0; @@ -2285,15 +2359,15 @@ for (; p != &qh->vertical; p = p->next) { desc = list_entry (p, uhci_desc_t, vertical); - if (desc->hw.td.status & TD_CTRL_ACTIVE) { // do not process active TDs + if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) { // do not process active TDs if (mode==2) // if called from async_unlink uhci_clean_transfer(s, urb, qh, mode); return ret; } - actual_length = (desc->hw.td.status + 1) & 0x7ff; // extract transfer parameters from TD - maxlength = (((desc->hw.td.info >> 21) & 0x7ff) + 1) & 0x7ff; - status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); + actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff; // extract transfer parameters from TD + maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff; + status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe)); if (status == -EPIPE) { // see if EP is stalled // set up stalled condition @@ -2307,7 +2381,7 @@ urb->error_count++; break; } - else if ((desc->hw.td.info & 0xff) != USB_PID_SETUP) + else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP) urb->actual_length += actual_length; // got less data than requested @@ -2320,9 +2394,9 @@ // short read during control-IN: re-start status stage if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) { - if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) { + if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) { - qh->hw.qh.element = virt_to_bus (last_desc); // re-trigger status stage + qh->hw.qh.element = cpu_to_le32(last_desc->dma_addr); // re-trigger status stage dbg("short packet during control transfer, retrigger status stage @ %p",last_desc); //uhci_show_td (desc); //uhci_show_td (last_desc); @@ -2331,14 +2405,14 @@ } } // all other cases: short read is OK - data_toggle = uhci_toggle (desc->hw.td.info); + data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info)); break; } else if (status) goto is_error; - data_toggle = uhci_toggle (desc->hw.td.info); - queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle); + data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info)); + queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle); } @@ -2375,20 +2449,20 @@ { desc = list_entry (p, uhci_desc_t, desc_list); - if (desc->hw.td.status & TD_CTRL_ACTIVE) { + if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) { // do not process active TDs - //dbg("TD ACT Status @%p %08x",desc,desc->hw.td.status); + //dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status)); break; } - if (!desc->hw.td.status & TD_CTRL_IOC) { + if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) { // do not process one-shot TDs, no recycling break; } // extract transfer parameters from TD - actual_length = (desc->hw.td.status + 1) & 0x7ff; - status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); + actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff; + status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe)); // see if EP is stalled if (status == -EPIPE) { @@ -2406,6 +2480,7 @@ urb->actual_length = actual_length; recycle: + uhci_urb_dma_sync(s, urb, urb->hcpriv); if (urb->complete) { //dbg("process_interrupt: calling completion, status %i",status); urb->status = status; @@ -2428,23 +2503,23 @@ // Recycle INT-TD if interval!=0, else mark TD as one-shot if (urb->interval) { - desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE); + desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE)); if (status==0) { ((urb_priv_t*)urb->hcpriv)->started=jiffies; - desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); } else { - desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); } - desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | - (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); + desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27)); mb(); } else { uhci_unlink_urb_async(s, urb); - desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD + desc->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC); // inactivate TD } } } @@ -2462,23 +2537,23 @@ uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); dbg("urb contains iso request"); - if ((desc->hw.td.status & TD_CTRL_ACTIVE) && !mode) + if ((desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) && !mode) return -EXDEV; // last TD not finished urb->error_count = 0; urb->actual_length = 0; urb->status = 0; dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s), - urb->number_of_packets,mode,desc->hw.td.status); + urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status)); for (i = 0; p != &urb_priv->desc_list; i++) { desc = list_entry (p, uhci_desc_t, desc_list); //uhci_show_td(desc); - if (desc->hw.td.status & TD_CTRL_ACTIVE) { + if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) { // means we have completed the last TD, but not the TDs before - desc->hw.td.status &= ~TD_CTRL_ACTIVE; - dbg("TD still active (%x)- grrr. paranoia!", desc->hw.td.status); + desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE); + dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status)); ret = -EXDEV; urb->iso_frame_desc[i].status = ret; unlink_td (s, desc, 1); @@ -2495,15 +2570,8 @@ goto err; } - if (urb->iso_frame_desc[i].offset + urb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) { - // Hm, something really weird is going on - dbg("Pointer Paranoia: %p!=%p", urb->iso_frame_desc[i].offset + urb->transfer_buffer, bus_to_virt (desc->hw.td.buffer)); - ret = -EINVAL; - urb->iso_frame_desc[i].status = ret; - goto err; - } - urb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff; - urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); + urb->iso_frame_desc[i].actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff; + urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe)); urb->actual_length += urb->iso_frame_desc[i].actual_length; err: @@ -2513,11 +2581,11 @@ urb->status = urb->iso_frame_desc[i].status; } dbg("process_iso: %i: len:%d %08x status:%x", - i, urb->iso_frame_desc[i].actual_length, desc->hw.td.status,urb->iso_frame_desc[i].status); + i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status); list_del (p); p = p->next; - delete_desc (desc); + delete_desc (s, desc); } dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length); @@ -2552,6 +2620,7 @@ } if (urb->status != -EINPROGRESS) { + urb_priv_t *urb_priv; struct usb_device *usb_dev; usb_dev=urb->dev; @@ -2567,10 +2636,14 @@ dbg("dequeued urb: %p", urb); dequeue_urb (s, urb); + urb_priv = urb->hcpriv; + + uhci_urb_dma_unmap(s, urb, urb_priv); + #ifdef DEBUG_SLAB - kmem_cache_free(urb_priv_kmem, urb->hcpriv); + kmem_cache_free(urb_priv_kmem, urb_priv); #else - kfree (urb->hcpriv); + kfree (urb_priv); #endif if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) { // process_interrupt does completion on its own @@ -2769,7 +2842,7 @@ /* Start at frame 0 */ outw (0, io_addr + USBFRNUM); - outl (virt_to_bus (s->framelist), io_addr + USBFLBASEADD); + outl (s->framelist_dma, io_addr + USBFLBASEADD); /* Run and mark it configured with a 64-byte max packet */ outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); @@ -2823,6 +2896,7 @@ return 0; } +#ifdef CONFIG_PM _static void uhci_pci_suspend (struct pci_dev *dev) { @@ -2834,7 +2908,7 @@ { start_hc((uhci_t *) dev->driver_data); } - +#endif _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { @@ -3012,19 +3086,10 @@ int retval; #ifdef DEBUG_SLAB - - uhci_desc_kmem = kmem_cache_create("uhci_desc", sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - - if(!uhci_desc_kmem) { - err("kmem_cache_create for uhci_desc failed (out of memory)"); - return -ENOMEM; - } - urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!urb_priv_kmem) { err("kmem_cache_create for urb_priv_t failed (out of memory)"); - kmem_cache_destroy(uhci_desc_kmem); return -ENOMEM; } #endif @@ -3040,11 +3105,12 @@ if (retval < 0 ) { if (kmem_cache_destroy(urb_priv_kmem)) err("urb_priv_kmem remained"); - if (kmem_cache_destroy(uhci_desc_kmem)) - err("uhci_desc_kmem remained"); } #endif + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return retval; } @@ -3053,9 +3119,6 @@ pci_unregister_driver (&uhci_pci_driver); #ifdef DEBUG_SLAB - if(kmem_cache_destroy(uhci_desc_kmem)) - err("uhci_desc_kmem remained"); - if(kmem_cache_destroy(urb_priv_kmem)) err("urb_priv_kmem remained"); #endif @@ -3065,6 +3128,6 @@ module_exit (uhci_hcd_cleanup); -MODULE_AUTHOR("Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"); -MODULE_DESCRIPTION("USB Universal Host Controller Interface driver"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb-uhci.h linux/drivers/usb/usb-uhci.h --- v2.4.4/linux/drivers/usb/usb-uhci.h Mon May 15 12:05:15 2000 +++ linux/drivers/usb/usb-uhci.h Wed May 16 10:31:27 2001 @@ -146,6 +146,7 @@ uhci_qh_t qh; } hw; uhci_desc_type_t type; + dma_addr_t dma_addr; struct list_head horizontal; struct list_head vertical; struct list_head desc_list; @@ -154,6 +155,8 @@ typedef struct { struct list_head desc_list; // list pointer to all corresponding TDs/QHs associated with this request + dma_addr_t setup_packet_dma; + dma_addr_t transfer_buffer_dma; unsigned long started; urb_t *next_queued_urb; // next queued urb for this EP urb_t *prev_queued_urb; @@ -195,6 +198,7 @@ struct usb_bus *bus; // our bus __u32 *framelist; + dma_addr_t framelist_dma; uhci_desc_t **iso_td; uhci_desc_t *int_chain[8]; uhci_desc_t *ls_control_chain; @@ -213,11 +217,12 @@ long timeout_check; int timeout_urbs; struct pci_dev *uhci_pci; + struct pci_pool *desc_pool; } uhci_t, *puhci_t; -#define MAKE_TD_ADDR(a) (virt_to_bus(a)&~UHCI_PTR_QH) -#define MAKE_QH_ADDR(a) (virt_to_bus(a)|UHCI_PTR_QH) +#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH) +#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH) #define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM)) /* ------------------------------------------------------------------------------------ diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.4/linux/drivers/usb/usb.c Wed Apr 25 14:10:47 2001 +++ linux/drivers/usb/usb.c Sat Apr 28 11:28:09 2001 @@ -569,7 +569,7 @@ * The most specific match specifiers use device descriptor * data. These are commonly used with product-specific matches; * the USB_DEVICE macro lets you provide vendor and product IDs, - * and you can also matche against ranges of product revisions. + * and you can also match against ranges of product revisions. * These are widely used for devices with application or vendor * specific bDeviceClass values. * diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c --- v2.4.4/linux/drivers/usb/usbkbd.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/usbkbd.c Mon May 21 15:02:06 2001 @@ -35,8 +35,15 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("USB HID Boot Protocol keyboard driver"); +/* + * Version Information + */ +#define DRIVER_VERSION "" +#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_DESC "USB HID Boot Protocol keyboard driver" + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); static unsigned char usb_kbd_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, @@ -273,6 +280,8 @@ static int __init usb_kbd_init(void) { usb_register(&usb_kbd_driver); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c --- v2.4.4/linux/drivers/usb/usbmouse.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/usbmouse.c Mon May 21 15:02:06 2001 @@ -35,8 +35,15 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("USB HID Boot Protocol mouse driver"); +/* + * Version Information + */ +#define DRIVER_VERSION "v1.6" +#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_DESC "USB HID Boot Protocol mouse driver" + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); struct usb_mouse { signed char data[8]; @@ -187,6 +194,8 @@ static int __init usb_mouse_init(void) { usb_register(&usb_mouse_driver); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c --- v2.4.4/linux/drivers/usb/uss720.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/usb/uss720.c Mon May 21 15:02:06 2001 @@ -33,6 +33,7 @@ * 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable * 0.5 20.09.99 usb_control_msg wrapper used * Nov01.00 usb_device_table support by Adam J. Richter + * 08.04.01 Identify version on module load. gb * */ @@ -44,6 +45,13 @@ #include #include +/* + * Version Information + */ +#define DRIVER_VERSION "v0.5" +#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch" +#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" + /* --------------------------------------------------------------------- */ struct parport_uss720_private { @@ -643,16 +651,16 @@ /* --------------------------------------------------------------------- */ -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch"); -MODULE_DESCRIPTION("USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"); +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); static int __init uss720_init(void) { if (usb_register(&uss720_driver) < 0) return -1; - printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.4 registered.\n" - KERN_INFO "uss720: (C) 1999 by Thomas Sailer, \n"); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/usb/wacom.c linux/drivers/usb/wacom.c --- v2.4.4/linux/drivers/usb/wacom.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/wacom.c Mon May 21 15:02:06 2001 @@ -28,6 +28,7 @@ * v1.12 (de) - Add support for two more inking pen IDs * v1.14 (vp) - Use new USB device id probing scheme. * Fix Wacom Graphire mouse wheel + * (gb) - Identify version on module load. */ /* @@ -57,8 +58,15 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("USB Wacom Graphire and Wacom Intuos tablet driver"); +/* + * Version Information + */ +#define DRIVER_VERSION "v1.14" +#define DRIVER_AUTHOR "Vojtech Pavlik " +#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); /* * Wacom Graphire packet: @@ -407,6 +415,8 @@ static int __init wacom_init(void) { usb_register(&wacom_driver); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/video/aty.h linux/drivers/video/aty.h --- v2.4.4/linux/drivers/video/aty.h Sun Sep 17 09:48:04 2000 +++ linux/drivers/video/aty.h Wed May 16 10:31:23 2001 @@ -738,6 +738,7 @@ #define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ #define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ #define LT_CHIP_ID 0x4c54 /* RAGE LT */ +#define XL_CHIP_ID 0x4752 /* RAGE (XL) */ #define GT_CHIP_ID 0x4754 /* RAGE (GT) */ #define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */ #define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */ diff -u --recursive --new-file v2.4.4/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.4.4/linux/drivers/video/atyfb.c Thu Apr 12 12:10:25 2001 +++ linux/drivers/video/atyfb.c Wed May 16 10:31:23 2001 @@ -561,6 +561,7 @@ { 0x4c49, 0x4c49, "3D RAGE LT PRO" }, { 0x4c50, 0x4c50, "3D RAGE LT PRO" }, { 0x4c54, 0x4c54, "3D RAGE LT" }, + { 0x4752, 0x4752, "3D RAGE (XL)" }, { 0x4754, 0x4754, "3D RAGE (GT)" }, { 0x4755, 0x4755, "3D RAGE II+ (GTB)" }, { 0x4756, 0x4756, "3D RAGE IIC (PCI)" }, @@ -722,7 +723,7 @@ if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID || Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || - Gx == LM_CHIP_ID || Gx == LN_CHIP_ID) + Gx == LM_CHIP_ID || Gx == LN_CHIP_ID || Gx == XL_CHIP_ID) reset_GTC_3D_engine(info); /* Reset engine, enable, and clear any engine errors */ @@ -2209,10 +2210,14 @@ if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || Gx == ET_CHIP_ID || ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { - if (info->ram_type >= SDRAM) - aty_st_pll(DLL_CNTL, 0xa6, info); - else - aty_st_pll(DLL_CNTL, 0xa0, info); + if (Gx == XL_CHIP_ID) { + aty_st_pll(DLL_CNTL, 0x80, info); + } else { + if (info->ram_type >= SDRAM) + aty_st_pll(DLL_CNTL, 0xa6, info); + else + aty_st_pll(DLL_CNTL, 0xa0, info); + } aty_st_pll(VFC_CNTL, 0x1b, info); aty_st_le32(DSP_CONFIG, pll->dsp_config, info); aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info); @@ -2334,6 +2339,7 @@ (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) || (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) || + (Gx == XL_CHIP_ID) || (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM)) pll->pll_gen_cntl = 0x04; else @@ -3214,7 +3220,7 @@ if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || - Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID) + Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == XL_CHIP_ID) tmp |= 0x2; aty_st_8(DAC_CNTL, tmp, info); aty_st_8(DAC_MASK, 0xff, info); @@ -3367,6 +3373,9 @@ /* RAGE PRO or LT PRO */ pll = 230; mclk = 100; + } else if (Gx == XL_CHIP_ID) { + pll = 230; + mclk = 120; } else if (Gx == LG_CHIP_ID) { /* Rage LT */ pll = 230; @@ -3801,34 +3810,36 @@ j++; } - /* - * Fix PROMs idea of MEM_CNTL settings... - */ - mem = aty_ld_le32(MEM_CNTL, info); - chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); - if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && - !((chip_id >> 24) & 1)) { - switch (mem & 0x0f) { - case 3: - mem = (mem & ~(0x0f)) | 2; - break; - case 7: - mem = (mem & ~(0x0f)) | 3; - break; - case 9: - mem = (mem & ~(0x0f)) | 4; - break; - case 11: - mem = (mem & ~(0x0f)) | 5; - break; - default: - break; - } - if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) - mem &= ~(0x00700000); + if (pdev->device != XL_CHIP_ID) { + /* + * Fix PROMs idea of MEM_CNTL settings... + */ + mem = aty_ld_le32(MEM_CNTL, info); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && + !((chip_id >> 24) & 1)) { + switch (mem & 0x0f) { + case 3: + mem = (mem & ~(0x0f)) | 2; + break; + case 7: + mem = (mem & ~(0x0f)) | 3; + break; + case 9: + mem = (mem & ~(0x0f)) | 4; + break; + case 11: + mem = (mem & ~(0x0f)) | 5; + break; + default: + break; + } + if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) + mem &= ~(0x00700000); + } + mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ + aty_st_le32(MEM_CNTL, mem, info); } - mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ - aty_st_le32(MEM_CNTL, mem, info); /* * If this is the console device, we will set default video @@ -3850,7 +3861,7 @@ if (node == pcp->prom_node) { struct fb_var_screeninfo *var = &default_var; - unsigned int N, P, Q, M, T; + unsigned int N, P, Q, M, T, R; u32 v_total, h_total; struct crtc crtc; u8 pll_regs[16]; @@ -3891,7 +3902,7 @@ N = pll_regs[7 + (clock_cntl & 3)]; /* - * PLL Post Devider P (Dependant on CLOCK_CNTL): + * PLL Post Divider P (Dependant on CLOCK_CNTL): */ P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); @@ -3907,13 +3918,17 @@ * Q = ------- * 2 * R * - * where R is XTALIN (= 14318 kHz). + * where R is XTALIN (= 14318 or 29498 kHz). */ - T = 2 * Q * 14318 / M; + if (pdev->device == XL_CHIP_ID) + R = 29498; + else + R = 14318; + + T = 2 * Q * R / M; default_var.pixclock = 1000000000 / T; } - #else /* __sparc__ */ info->ati_regbase_phys = 0x7ff000 + addr; @@ -4297,7 +4312,8 @@ if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || - Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID) + Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID || + Gx == XL_CHIP_ID) i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ aty_st_8(DAC_CNTL, i, info); aty_st_8(DAC_MASK, 0xff, info); diff -u --recursive --new-file v2.4.4/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c --- v2.4.4/linux/drivers/video/chipsfb.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/chipsfb.c Sat May 19 18:14:38 2001 @@ -29,17 +29,19 @@ #include #include #include +#include + #ifdef CONFIG_FB_COMPAT_XPMAC #include -#endif -#include -#include #include +#endif #ifdef CONFIG_PMAC_BACKLIGHT #include #endif +#ifdef CONFIG_PMAC_PBOOK #include #include +#endif #include