diff -u --recursive --new-file v2.1.111/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.111/linux/Documentation/Configure.help Sun Jul 26 11:57:14 1998 +++ linux/Documentation/Configure.help Sun Jul 26 23:40:27 1998 @@ -1488,6 +1488,76 @@ If you want to play with it, say Y here and to the driver for your graphics board, below. If unsure, say N. +Acorn VIDC support +CONFIG_FB_ACORN + This is the frame buffer device driver for the Acorn VIDC graphics + chipset. + +Apollo frame buffer device +CONFIG_FB_APOLLO + This is the frame buffer device driver for the monochrome graphics + hardware found in some Apollo workstations. + +Amiga native chipset support +CONFIG_FB_AMIGA + This is the frame buffer device driver for the builtin graphics + chipset found in Amigas. + +Amiga OCS chipset support +CONFIG_FB_AMIGA_OCS + This enables support for the original Agnus and Denise video chips, + found in the Amiga 1000 and most A500's and A2000's. If you intend + to run Linux on any of these systems, say Y; otherwise say N. + +Amiga ECS chipset support +CONFIG_FB_AMIGA_ECS + This enables support for the Enhanced Chip Set, found in later + A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If + you intend to run Linux on any of these systems, say Y; otherwise + say N. + +Amiga AGA chipset support +CONFIG_FB_AMIGA_AGA + This enables support for the Advanced Graphics Architecture (also + known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T + and CD32. If you intend to run Linux on any of these systems, say Y; + otherwise say N. + +Amiga CyberVision support +CONFIG_FB_CYBER + This enables support for the Cybervision 64 graphics card from Phase5. + Please note that its use is not all that intuitive (i.e. if you have + any questions, be sure to ask!). Say N unless you have a Cybervision + 64 or plan to get one before you next recompile the kernel. + Please note that this driver DOES NOT support the Cybervision 64 3D + card, as they use incompatible video chips. + +Amiga CyberVision3D support (EXPERIMENTAL) +CONFIG_FB_VIRGE + This enables support for the Cybervision 64/3D graphics card from Phase5. + Please note that its use is not all that intuitive (i.e. if you have + any questions, be sure to ask!). Say N unless you have a Cybervision + 64/3D or plan to get one before you next recompile the kernel. + Please note that this driver DOES NOT support the older Cybervision 64 + card, as they use incompatible video chips. + +Amiga RetinaZ3 support (EXPERIMENTAL) +CONFIG_FB_RETINAZ3 + This enables support for the Retina Z3 graphics card. Say N unless you + have a Retina Z3 or plan to get one before you next recompile the kernel. + +Amiga CLgen driver (EXPERIMENTAL) +CONFIG_FB_CLGEN + This enables support for Cirrus Logic GD542x/543x based boards on Amiga: + SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. Say N + unless you have such a graphics board or plan to get one before you next + recompile the kernel. + +Atari native chipset support +CONFIG_FB_ATARI + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. + Open Firmware frame buffer device support CONFIG_FB_OF Say Y if you want support with Open Firmware for your graphics board. @@ -1500,6 +1570,31 @@ CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. +PowerMac "control" frame buffer device support +CONFIG_FB_CONTROL + This driver supports a frame buffer for the graphics adapter in the + Power Macintosh 7300 and others. + +PowerMac "platinum" frame buffer device support +CONFIG_FB_PLATINUM + This driver supports a frame buffer for the "platinum" graphics adapter + in some Power Macintoshes. + +Chips 65550 display support +CONFIG_FB_CT65550 + This is the frame buffer device driver for the Chips & Technologies + 65550 graphics chip in PowerBooks. + +Mac frame buffer device +CONFIG_FB_MAC + This is the frame buffer device driver for the graphics hardware in + m68k Macintoshes. + +HP300 frame buffer device +CONFIG_FB_HP300 + This is the frame buffer device driver for the Topcat graphics + hardware found in HP300 workstations. + VGA chipset support (text only) CONFIG_FB_VGA This is the frame buffer device driver for generic VGA chips. This @@ -1530,38 +1625,143 @@ If unsure, say N. -### -### Somebody please explain the following options -### -# Virtual Frame Buffer support (ONLY FOR TESTING!) -# CONFIG_FB_VIRTUAL -# -# Advanced low level driver options -# CONFIG_FBCON_ADVANCED -# -# Monochrome support -# CONFIG_FBCON_MFB -# -# 2 bpp packed pixels support -# CONFIG_FBCON_CFB2 -# -# 4 bpp packed pixels support -# CONFIG_FBCON_CFB4 -# -# 8 bpp packed pixels support -# CONFIG_FBCON_CFB8 -# -# 16 bpp packed pixels support -# CONFIG_FBCON_CFB16 -# -# 24 bpp packed pixels support -# CONFIG_FBCON_CFB24 -# -# 32 bpp packed pixels support -# CONFIG_FBCON_CFB32 -# -# VGA characters/attributes support -# CONFIG_FBCON_VGA +SBUS and UPA framebuffers +CONFIG_FB_SBUS + Say Y if you want support for SBUS or UPA based frame buffer device. + +Creator/Creator3D support +CONFIG_FB_CREATOR + This is the frame buffer device driver for the Creator and Creator3D + graphics boards. + +CGsix (GX,TurboGX) support +CONFIG_FB_CGSIX + This is the frame buffer device driver for the CGsix (GX, TurboGX) + frame buffer. + +BWtwo support +CONFIG_FB_BWTWO + This is the frame buffer device driver for the BWtwo frame buffer. + +CGthree support +CONFIG_FB_CGTHREE + This is the frame buffer device driver for the CGthree frame buffer. + +TCX (SS4/SS5 only) support +CONFIG_FB_TCX + This is the frame buffer device driver for the TCX 24/8bit frame buffer. + +Virtual Frame Buffer support (ONLY FOR TESTING!) +CONFIG_FB_VIRTUAL + This is a `virtual' frame buffer device. It operates on a chunk of + unswapable kernel memory instead of on the memory of a graphics board. + This means you cannot see any output sent to this frame buffer device, + while it does consume precious memory. The main use of this frame + buffer device is testing and debugging the frame buffer subsystem. Do + NOT enable it for normal systems! To protect the innocent, it has to + be enabled explicitly on boot time using the kernel option `video=vfb:'. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called vfb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +Advanced low level driver options +CONFIG_FBCON_ADVANCED + The frame buffer console uses character drawing routines that are + tailored to the specific organization of pixels in the memory of your + graphics hardware. These are called the low level frame buffer console + drivers. Note that they are used for text console output only; they are + NOT needed for graphical applications. + + If you do not enable this option, the needed low level drivers are + automatically enabled, depending on what frame buffer devices you + selected. This is recommended for most users. + + If you enable this option, you have more fine-grained control over which + low level drivers are enabled. You can e.g. leave out low level drivers + for color depths you do not intend to use for text consoles. + + Low level frame buffer console drivers can be modules ( = code which + can be inserted and removed from the running kernel whenever you want). + The modules will be called fbcon-*.o. If you want to compile (some of) + them as modules, read Documentation/modules.txt. + + If unsure, say N. + +Monochrome support +CONFIG_FBCON_MFB + This is the low level frame buffer console driver for monochrome + (2 colors) packed pixels. + +2 bpp packed pixels support +CONFIG_FBCON_CFB2 + This is the low level frame buffer console driver for 2 bits per pixel + (4 colors) packed pixels. + +4 bpp packed pixels support +CONFIG_FBCON_CFB4 + This is the low level frame buffer console driver for 4 bits per pixel + (16 colors) packed pixels. + +8 bpp packed pixels support +CONFIG_FBCON_CFB8 + This is the low level frame buffer console driver for 8 bits per pixel + (256 colors) packed pixels. + +16 bpp packed pixels support +CONFIG_FBCON_CFB16 + This is the low level frame buffer console driver for 15 or 16 bits + per pixel (32K or 64K colors, also known as `hicolor') packed pixels. + +24 bpp packed pixels support +CONFIG_FBCON_CFB24 + This is the low level frame buffer console driver for 24 bits per + pixel (16M colors, also known as `truecolor') packed pixels. It is + NOT for `sparse' 32 bits per pixel mode. + +32 bpp packed pixels support +CONFIG_FBCON_CFB32 + This is the low level frame buffer console driver for 32 bits per pixel + (16M colors, also known as `truecolor') sparse packed pixels. + +Amiga bitplanes support +CONFIG_FBCON_AFB + This is the low level frame buffer console driver for 1 to 8 bitplanes + (2 to 256 colors) on Amiga. + +Amiga interleaved bitplanes support +CONFIG_FBCON_ILBM + This is the low level frame buffer console driver for 1 to 8 + interleaved bitplanes (2 to 256 colors) on Amiga. + +Atari interleaved bitplanes (2 planes) support +CONFIG_FBCON_IPLAN2P2 + This is the low level frame buffer console driver for 2 interleaved + bitplanes (4 colors) on Atari. + +Atari interleaved bitplanes (4 planes) support +CONFIG_FBCON_IPLAN2P4 + This is the low level frame buffer console driver for 4 interleaved + bitplanes (16 colors) on Atari. + +Atari interleaved bitplanes (8 planes) support +CONFIG_FBCON_IPLAN2P8 + This is the low level frame buffer console driver for 8 interleaved + bitplanes (256 colors) on Atari. + +Mac variable bpp packed pixels support +CONFIG_FBCON_MAC + This is the low level frame buffer console driver for 1/2/4/8/16/32 + bits per pixel packed pixels on Mac. It supports variable fontwidths + for low resolution screens. + +VGA characters/attributes support +CONFIG_FBCON_VGA + This is the low level frame buffer console driver for VGA text mode, as + used by vgafb. Parallel-port support CONFIG_PARPORT @@ -5783,18 +5983,6 @@ The module will be called isp16.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Preload dcache -CONFIG_DCACHE_PRELOAD - Preloading will create dcache entries when a directory is scanned - (e.g. because the ls command was used) for the *first* time. This - should speed up successive lookups of information about files in - that directory, but can also consume large amounts of memory. - - Please report speedups (or slowdowns due to the memory usage if they - occur) to schoebel@informatik.uni-stuttgart.de . - - If unsure, say N. - Quota support CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk @@ -5804,173 +5992,6 @@ (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota support is only useful for multi user systems. If unsure, say N. - -Online mirror support -CONFIG_OMIRR - omirr is a package for _symmetric_ mirroring of files over the - Internet. In contrast to rdist, the online mirror daemon (omirrd) is - running all the time and transfers any changes on the file system as - soon as possible to all other servers. Symmetric means that all - servers have equal rights in changing a file: the last changer of a - file will win. This is the same behaviour as multiple processes - operating on a global file system. In effect, omirr can do the same - as NFS mounts, but will have better performance since the data is - stored on local disks. In contrast to a cache filesystem which has a - dedicated master copy, broken connections and/or servers are no - problem for continuing work on the remaining ones, because there is - no master copy. Every computer that wants to participate in the - mirroring needs to run the daemon omirrd, contained in the omirr - package which is available via FTP (user: anonymous) from - ftp://ftp.isa.de/pub/home/luik. You must say Y if you want to use - in.omirrd, but you should (but need not) say N if you don't (for - performance reasons). - - Note that this is experimental code; use at your own risk. - -Filename translation support -CONFIG_TRANS_NAMES - This is a useful feature if you have a pool of diskless Linux - clients which mount their root filesystems from a central - server. Depending on their hostnames, the clients can then see - different versions of certain files, which keeps maintenance at a - minimum when used for configuration files. The kernel running on the - clients should have this option enabled. If you don't administer a - pool of Linux clients, say N here, otherwise read on: - - When you say Y here, filenames, directory names etc become - context-sensitive. If you have a file named - "/etc/config#host=banana#", it will appear (by default) as - hardlinked to "/etc/config" on host "banana", while on host "mango" - another file "/etc/config#host=mango#" will appear as having been - hardlinked to "/etc/config". - This default behaviour can be changed by setting the _first_ - environment variable NAMETRANS to a colon-separated list of suffixes - which are tried in the specified order. For example, in - - 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' - - the command will see the same files as if it had been executed on - host "mango" with a diskless kernel. - - Using NAMETRANS supersedes _all_ default translations. Thus - translations can be completely switched off with an empty list, - e.g. - - 'env - NAMETRANS= "`env`" command ...' - - Note that some system utilities like tar, dump, restore should be - used with translation switched off, in order to avoid doubled space - in archive files and when extracting from them. Also, make sure that - nfsd, mountd (and similar ones like samba daemons) run without - translation, in order to avoid doubled (or even wrong) translation - at the server and at the client. - - You can automatically force the creation of context-dependent - filenames if there exists a template filename like - "/etc/mtab#host=CREATE#". As soon as a process running on "mango" - tries to create a file "/etc/mtab", the version - "/etc/mtab#host=mango#" is created instead (which appears in turn as - hardlinked to "/etc/mtab"). Note that if you want to make - "/etc/fstab" context-dependent, you should execute "touch - /etc/mtab#host=CREATE#" and "touch /etc/mtab.tmp#host=CREATE#", - because mount, umount and others running on different hosts would - otherwise try to create one shared /etc/mtab which would result in a - clash. Also one should execute "touch /etc/nologin#host=CREATE#" to - prevent global side effects from shutdown resp. runlevel. - - Please read Documentation/transname.txt if you intend to say Y here. - -Restrict translation to gid -CONFIG_TRANS_RESTRICT - If you say Y here, default filename translations are carried out - only if the parent directory of the context-sensitive file belongs - to a specific group id (gid). Trying to translate names everywhere - will decrease performance of file openings. Normally translations - are used only in system configuration files but not in ordinary user - file space. So you should change the gid of directories containing - context-dependent files to some special group like "adm" (group id - 4) and enable this option. As a result, users will not notice any - performance degradation resulting from filename translation. - - Note that translations resulting from the first environment variable - "NAMETRANS=..." are always carried out regardless of the gid of - directories. - - Beware: before turning on this option make sure that all directories - containing context-dependent files belong to the special group, or - system initialization may fail. If unsure, select N. - -Group id (gid) for translation restriction -CONFIG_TRANS_GID - Default name translations will be carried out only inside directories - belonging to the group id (gid) that you specify here. - Default is 4 (group "adm"). - -Nodename (hostname) translation -CONFIG_TR_NODENAME - Enables translation of name suffixes like in - "/etc/config#host=banana#". The syntax is - #host=#. The hostname can be queried with the - command "uname -n". Normally this option is used heavily when - translation is enabled. If unsure, say Y. - -Kernelname translation -CONFIG_TR_KERNNAME - Enables translation of name suffixes like in - "/etc/config#kname=default#". The string is hard compiled into the - kernel by the following option. Useful if your kernel does not know - the hostname at boot time, and there is no way to tell the hostname - by lilo or bootp. Please avoid using this option and prefer - "Nodename (hostname) translation" (CONFIG_TR_NODENAME) wherever - possible. When mounting the root over NFS, the own hostname must be - known at boot time anyway; this option is just for special use. - Note that the default translations are tried in the order as - occurring in the configuration, that is 1) host 2) kname 3) ktype 4) - machine 5) system. If unsure, say Y. - -String for kernelname translation -CONFIG_KERNNAME - Enter the string you want to compile into the kernel. The string - will be used as context in context-dependent files like - "/etc/config#kname=#". - -Kerneltype translation -CONFIG_TR_KERNTYPE - Enables translation of name suffixes like in - "/etc/config#ktype=default#". The syntax is - #ktype=#. The string is hard compiled in the - kernel by the following option. Use if you want to create different - kernels with different behaviour. For example, use the string - "default" on your server, and use "diskless" on all your diskless - clients (and perhaps "dataless" on dataless clients). This way you - can avoid dozens of "config#host=# with same contents and - you have no effort when new machines are added. If unsure, say Y. - -String for kerneltype translation -CONFIG_KERNTYPE - Enter the string you want to compile into the kernel. The string - will be used as context in context-dependent files like - "/etc/config#ktype=default#". If your kernel is to be used on a - server, you probably can use "default" here. If your kernel is - intended for a diskless client, you probably should enter "diskless" - here. - -Machine type translation -CONFIG_TR_MACHINE - Enables translation of name suffixes like in - "/etc/config#machine=i486#". The syntax is - #machine=#. The machine types can be queried with the - command "uname -m". Normally used only on multi-architecture - installations. If unsure, say Y. - -System name translation -CONFIG_TR_SYSNAME - Enables translation of name suffixes like in - "/etc/config#system=Linux#". The syntax is - #system=#. The system name can be queried with the - command "uname -s". Currently only supported by Linux, but hopefully - other operating systems will pick up the idea of context-dependent - translations. If unsure, say Y. Minix fs support CONFIG_MINIX_FS diff -u --recursive --new-file v2.1.111/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.111/linux/MAINTAINERS Tue Jul 21 00:15:29 1998 +++ linux/MAINTAINERS Sun Jul 26 23:35:55 1998 @@ -310,6 +310,12 @@ W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html S: Maintained +IP FIREWALL +P: Paul Russell +M: Paul.Russell@rustcorp.com.au +W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html +S: Maintained + IPX/SPX NETWORK LAYER P: Jay Schulist M: Jay Schulist @@ -325,6 +331,7 @@ JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@atrey.karlin.mff.cuni.cz +W: http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ L: linux-joystick@atrey.karlin.mff.cuni.cz S: Maintained @@ -555,6 +562,12 @@ M: R.E.Wolff@BitWizard.nl M: io8-linux@specialix.co.uk L: linux-kernel@vger.rutgers.edu ? +S: Supported + +SPX NETWORK LAYER +P: Jay Schulist +M: Jay.Schulist@spacs.k12.wi.us +L: linux-net@vger.rutgers.edu S: Supported SPX NETWORK LAYER diff -u --recursive --new-file v2.1.111/linux/Makefile linux/Makefile --- v2.1.111/linux/Makefile Sun Jul 26 11:57:14 1998 +++ linux/Makefile Sun Jul 26 14:40:18 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 111 +SUBLEVEL = 112 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -298,7 +298,7 @@ cd modules; \ MODULES=""; \ inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ - mkdir -p $$MODLIB/$$2; cp -p $$These $$MODLIB/$$2; \ + mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \ echo Installing modules under $$MODLIB/$$2; \ }; \ \ @@ -340,7 +340,8 @@ rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map rm -f .tmp* - rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash + rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c + rm -f drivers/char/conmakehash rm -f drivers/sound/bin2hex drivers/sound/hex2hex if [ -d modules ]; then \ rm -f core `find modules/ -type f -print`; \ diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.1.111/linux/arch/i386/kernel/io_apic.c Tue Jul 21 00:15:30 1998 +++ linux/arch/i386/kernel/io_apic.c Sun Jul 26 13:24:05 1998 @@ -966,21 +966,6 @@ mask_IO_APIC_irq(irq); } -/* - * Enter and exit the irq handler context.. - */ -static inline void enter_ioapic_irq(int cpu) -{ - hardirq_enter(cpu); - while (test_bit(0,&global_irq_lock)) barrier(); -} - -static inline void exit_ioapic_irq(int cpu) -{ - hardirq_exit(cpu); - release_irqlock(cpu); -} - static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) { irq_desc_t *desc = irq_desc + irq; @@ -1014,7 +999,7 @@ if (!action) return; - enter_ioapic_irq(cpu); + irq_enter(cpu, irq); /* * Edge triggered interrupts need to remember @@ -1035,7 +1020,7 @@ desc->status &= IRQ_DISABLED; spin_unlock(&irq_controller_lock); - exit_ioapic_irq(cpu); + irq_exit(cpu, irq); } static void do_level_ioapic_IRQ (unsigned int irq, int cpu, @@ -1074,7 +1059,7 @@ if (!action) return; - enter_ioapic_irq(cpu); + irq_enter(cpu, irq); handle_IRQ_event(irq, regs); @@ -1084,7 +1069,7 @@ unmask_IO_APIC_irq(irq); spin_unlock(&irq_controller_lock); - exit_ioapic_irq(cpu); + irq_exit(cpu, irq); } /* diff -u --recursive --new-file v2.1.111/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.1.111/linux/arch/i386/mm/ioremap.c Fri Apr 4 08:52:17 1997 +++ linux/arch/i386/mm/ioremap.c Sun Jul 26 14:28:07 1998 @@ -90,13 +90,34 @@ void * addr; struct vm_struct * area; - if (phys_addr < virt_to_phys(high_memory)) + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000) return phys_to_virt(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) + return NULL; + + /* + * Mappings have to be page-aligned + */ if (phys_addr & ~PAGE_MASK) return NULL; size = PAGE_ALIGN(size); + + /* + * Don't allow mappings that wrap.. + */ if (!size || size > phys_addr + size) return NULL; + + /* + * Ok, go for it.. + */ area = get_vm_area(size); if (!area) return NULL; diff -u --recursive --new-file v2.1.111/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.1.111/linux/drivers/block/ide-floppy.c Thu May 7 22:51:48 1998 +++ linux/drivers/block/ide-floppy.c Sun Jul 26 11:46:46 1998 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -1141,7 +1142,18 @@ static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return -EIO; + idefloppy_pc_t pc; + + if (cmd == CDROMEJECT) { + if (drive->usage > 1) + return -EBUSY; + idefloppy_create_prevent_cmd (&pc, 0); + (void) idefloppy_queue_pc_tail (drive, &pc); + idefloppy_create_start_stop_cmd (&pc, 2); + (void) idefloppy_queue_pc_tail (drive, &pc); + return 0; + } + return -EIO; } /* diff -u --recursive --new-file v2.1.111/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.111/linux/drivers/block/ide.c Wed Jul 1 19:38:53 1998 +++ linux/drivers/block/ide.c Sun Jul 26 11:46:46 1998 @@ -1525,6 +1525,7 @@ if (sb) invalidate_inodes(sb); invalidate_buffers (devp); + set_blocksize(devp, 1024); } drive->part[p].start_sect = 0; drive->part[p].nr_sects = 0; diff -u --recursive --new-file v2.1.111/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.111/linux/drivers/char/console.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/console.c Sun Jul 26 14:40:18 1998 @@ -188,7 +188,7 @@ return p; } -static inline void scrolldelta(int lines) +static void scrolldelta(int lines) { int currcons = fg_console; @@ -314,6 +314,8 @@ a ^= 0x80; if (_intensity == 2) a ^= 0x08; + if (hi_font_mask == 0x100) + a <<= 1; return a; } #else @@ -339,17 +341,23 @@ sw->con_invert_region(vc_cons[currcons].d, p, count); #ifndef VT_BUF_VRAM_ONLY else { - int col = can_do_color; u16 *q = p; int cnt = count; - while (cnt--) { - u16 a = *q; - if (col) + if (!can_do_color) { + while (cnt--) *q++ ^= 0x0800; + } else if (hi_font_mask == 0x100) { + while (cnt--) { + u16 a = *q; + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); + *q++ = a; + } + } else { + while (cnt--) { + u16 a = *q; a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); - else - a ^= 0x0800; - *q++ = a; + *q++ = a; + } } } #endif @@ -436,9 +444,9 @@ int i = scr_readw((u16 *) pos); u32 type = cursor_type; + if (! (type & 0x10)) return; if (softcursor_original != -1) return; softcursor_original = i; - if (! (type & 0x10)) return; i |= ((type >> 8) & 0xff00 ); i ^= ((type) & 0xff00 ); if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; @@ -450,6 +458,8 @@ static void hide_cursor(int currcons) { + if (currcons == sel_cons) + clear_selection(); if (softcursor_original != -1) { scr_writew(softcursor_original,(u16 *) pos); if (DO_UPDATE) @@ -464,6 +474,8 @@ if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) return; if (deccm) { + if (currcons == sel_cons) + clear_selection(); add_softcursor(currcons); if ((cursor_type & 0x0f) != 1) sw->con_cursor(vc_cons[currcons].d,CM_DRAW); @@ -510,8 +522,6 @@ } lock = 1; - clear_selection(); - hide_cursor(currcons); if (fg_console != new_console) { display = vc_cons[new_console].d->vc_display_fg; @@ -552,6 +562,8 @@ sw = conswitchp; cons_num = currcons; display_fg = &master_display_fg; + vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir; + vc_cons[currcons].d->vc_uni_pagedir = 0; hi_font_mask = 0; complement_mask = 0; sw->con_init(vc_cons[currcons].d, 1); @@ -591,6 +603,7 @@ vt_cons[currcons] = NULL; return -ENOMEM; } + con_set_default_unimap(currcons); screenbuf = (unsigned short *) q; kmalloced = 1; screenbuf_size = video_screen_size; @@ -1667,14 +1680,10 @@ /* DEC screen alignment test. kludge :-) */ video_erase_char = (video_erase_char & 0xff00) | 'E'; - /* Arno: - * Doesn't work, because csi_J(c,2) - * calls con_clear and doesn't print - * the erase char.. FIXME - */ csi_J(currcons, 2); video_erase_char = (video_erase_char & 0xff00) | ' '; + do_update_region(currcons, origin, screenbuf_size/2); } return; case ESsetG0: @@ -1755,10 +1764,6 @@ if (IS_FG) hide_cursor(currcons); - /* clear the selection */ - if (currcons == sel_cons) - clear_selection(); - disable_bh(CONSOLE_BH); while (!tty->stopped && count) { enable_bh(CONSOLE_BH); @@ -1825,11 +1830,11 @@ if (vc_state == ESnormal && ok) { /* Now try to find out how to display it */ - tc = conv_uni_to_pc(tc); + tc = conv_uni_to_pc(vc_cons[currcons].d, tc); if ( tc == -4 ) { /* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(0xfffd); + tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd); /* One reason for the -4 can be that we just did a clear_unimap(); @@ -1889,8 +1894,7 @@ static void console_bh(void) { if (want_console >= 0) { - if (want_console != fg_console) { - clear_selection(); + if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(fg_console); save_screen(); change_console(want_console); @@ -2401,8 +2405,8 @@ /* entering graphics mode? */ if (nopowersave) { - save_screen(); hide_cursor(currcons); + save_screen(); sw->con_blank(vc_cons[currcons].d, -1); console_blanked = fg_console + 1; set_origin(currcons); @@ -2460,6 +2464,9 @@ currcons = fg_console; console_blanked = 0; +#ifdef CONFIG_APM + apm_display_unblank(); +#endif if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); @@ -2567,24 +2574,31 @@ * /Jes */ -#define max_font_size 32768 +#define max_font_size 65536 int con_font_op(int currcons, struct console_font_op *op) { int rc = -EINVAL; - int size, set; - u8 *temp; + int size = max_font_size, set; + u8 *temp = NULL; struct console_font_op old_op; if (vt_cons[currcons]->vc_mode != KD_TEXT) goto quit; - memcpy(&old_op, &op, sizeof(op)); + memcpy(&old_op, op, sizeof(old_op)); if (op->op == KD_FONT_OP_SET) { + if (!op->data) + return -EINVAL; if (op->charcount > 512) goto quit; if (!op->height) { /* Need to guess font height [compat] */ int h, i; u8 *charmap = op->data, tmp; + + /* If from KDFONTOP ioctl, don't allow things which can be done in userland, + so that we can get rid of this soon */ + if (op->flags & KD_FONT_FLAG_NEW) + goto quit; rc = -EFAULT; for (h = 32; h > 0; h--) for (i = 0; i < op->charcount; i++) { @@ -2605,32 +2619,44 @@ if (size > max_font_size) return -ENOSPC; set = 1; - } else if (op->op == KD_FONT_OP_GET) { - size = max_font_size; + } else if (op->op == KD_FONT_OP_GET) set = 0; - } else + else return sw->con_font_op(vc_cons[currcons].d, op); - temp = kmalloc(size, GFP_KERNEL); - if (!temp) - return -ENOMEM; - if (set && copy_from_user(temp, op->data, size)) { - rc = -EFAULT; - goto quit2; + if (op->data) { + temp = kmalloc(size, GFP_KERNEL); + if (!temp) + return -ENOMEM; + if (set && copy_from_user(temp, op->data, size)) { + rc = -EFAULT; + goto quit; + } + op->data = temp; } - op->data = temp; rc = sw->con_font_op(vc_cons[currcons].d, op); op->data = old_op.data; if (!rc && !set) { int c = (op->width+7)/8 * 32 * op->charcount; - if (op->width > old_op.width || - op->height > old_op.height || - op->charcount > old_op.charcount) + + if (op->data && op->charcount > old_op.charcount) rc = -ENOSPC; - else if (copy_to_user(old_op.data, op->data, c)) + if (op->flags & KD_FONT_FLAG_NEW) { + if (op->width > old_op.width || + op->height > old_op.height) + rc = -ENOSPC; + } else { + if (op->width != 8) + rc = -EIO; + else if ((old_op.height && op->height > old_op.height) || + op->height > 32) + rc = -ENOSPC; + } + if (!rc && op->data && copy_to_user(op->data, temp, c)) rc = -EFAULT; } -quit2: kfree_s(temp, size); -quit: return rc; +quit: if (temp) + kfree_s(temp, size); + return rc; } /* @@ -2664,6 +2690,22 @@ { gotoxy(currcons, p[0], p[1]); set_cursor(currcons); +} + +u16 vcs_scr_readw(int currcons, u16 *org) +{ + if (org == pos && softcursor_original != -1) + return softcursor_original; + return scr_readw(org); +} + +void vcs_scr_writew(int currcons, u16 val, u16 *org) +{ + scr_writew(val, org); + if (org == pos) { + softcursor_original = -1; + add_softcursor(currcons); + } } diff -u --recursive --new-file v2.1.111/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.1.111/linux/drivers/char/consolemap.c Mon Aug 11 17:28:19 1997 +++ linux/drivers/char/consolemap.c Sun Jul 26 14:40:18 1998 @@ -5,6 +5,8 @@ * to font positions. * * aeb, 950210 + * + * Support for multiple unimaps by Jakub Jelinek , July 1998 */ #include @@ -14,6 +16,8 @@ #include #include #include +#include +#include static unsigned short translations[][256] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ @@ -163,29 +167,36 @@ #define MAX_GLYPH 512 /* Max possible glyph value */ -static unsigned char * inv_translate = NULL; -static unsigned char inv_norm_transl[MAX_GLYPH]; -static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL }; +static int inv_translate; + +struct uni_pagedir { + u16 **uni_pgdir[32]; + unsigned long refcount; + unsigned long sum; + unsigned char *inverse_translations[4]; + int readonly; +}; -static void set_inverse_transl(int i) +static struct uni_pagedir *dflt; + +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) { int j, glyph; - unsigned short *p = translations[i]; - unsigned char *q = inverse_translations[i]; + unsigned short *t = translations[i]; + unsigned char *q; + + if (!p) return; + q = p->inverse_translations[i]; if (!q) { - /* slightly messy to avoid calling kmalloc too early */ - q = inverse_translations[i] = ((i == LAT1_MAP) - ? inv_norm_transl - : (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL)); - if (!q) - return; + q = p->inverse_translations[i] = (unsigned char *) + kmalloc(MAX_GLYPH, GFP_KERNEL); + if (!q) return; } - for (j=0; j= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ q[glyph] = j; @@ -195,9 +206,7 @@ unsigned short *set_translate(int m) { - if (!inverse_translations[m]) - set_inverse_transl(m); - inv_translate = inverse_translations[m]; + inv_translate = m; return translations[m]; } @@ -208,13 +217,33 @@ * was active, or using Unicode. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -unsigned char inverse_translate(int glyph) { - if ( glyph < 0 || glyph >= MAX_GLYPH ) +unsigned char inverse_translate(struct vc_data *conp, int glyph) +{ + struct uni_pagedir *p; + + if (glyph < 0 || glyph >= MAX_GLYPH) return 0; + else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || + !p->inverse_translations[inv_translate]) + return glyph; else - return ((inv_translate && inv_translate[glyph]) - ? inv_translate[glyph] - : (unsigned char)(glyph & 0xff)); + return p->inverse_translations[inv_translate][glyph]; +} + +static void update_user_maps(void) +{ + int i; + struct uni_pagedir *p, *q = NULL; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + if (p && p != q) { + set_inverse_transl(vc_cons[i].d, p, USER_MAP); + q = p; + } + } } /* @@ -240,7 +269,7 @@ p[i] = UNI_DIRECT_BASE | uc; } - set_inverse_transl(USER_MAP); + update_user_maps(); return 0; } @@ -255,7 +284,7 @@ for (i=0; iuni_pgdir[i]) != NULL) { + for (j = 0; j < 32; j++) + if (p1[j]) + kfree(p1[j]); + kfree(p1); + } + p->uni_pgdir[i] = NULL; + } + for (i = 0; i < 4; i++) + if (p->inverse_translations[i]) { + kfree(p->inverse_translations[i]); + p->inverse_translations[i] = NULL; + } +} + +void con_free_unimap(int con) { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; + struct uni_pagedir *p; + struct vc_data *conp = vc_cons[con].d; + + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (!p) return; + *conp->vc_uni_pagedir_loc = 0; + if (--p->refcount) return; + con_release_unimap(p); + kfree(p); +} + +static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) +{ + int i, j, k; + struct uni_pagedir *q; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + if (!q || q == p || q->sum != p->sum) + continue; + for (j = 0; j < 32; j++) { + u16 **p1, **q1; + p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; + if (!p1 && !q1) + continue; + if (!p1 || !q1) + break; + for (k = 0; k < 32; k++) { + if (!p1[k] && !q1[k]) + continue; + if (!p1[k] || !q1[k]) + break; + if (memcmp(p1[k], q1[k], 64*sizeof(u16))) + break; + } + if (k < 32) + break; + } + if (j == 32) { + q->refcount++; + *conp->vc_uni_pagedir_loc = (unsigned long)q; + con_release_unimap(p); + kfree(p); + return 1; + } + } + return 0; +} static int -con_insert_unipair(u_short unicode, u_short fontpos) +con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) { - int i, n; - u16 **p1, *p2; + int i, n; + u16 **p1, *p2; - if ( !(p1 = uni_pagedir[n = unicode >> 11]) ) - { - p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); - if ( !p1 ) - return -ENOMEM; - - for ( i = 0 ; i < 32 ; i++ ) - p1[i] = NULL; - } - - if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) ) - { - p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); - if ( !p2 ) - return -ENOMEM; - - for ( i = 0 ; i < 64 ; i++ ) - p2[i] = 0xffff; /* No glyph for this character (yet) */ - } + if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { + p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); + if (!p1) return -ENOMEM; + for (i = 0; i < 32; i++) + p1[i] = NULL; + } - p2[unicode & 0x3f] = fontpos; - - return 0; + if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { + p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); + if (!p2) return -ENOMEM; + memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ + } + + p2[unicode & 0x3f] = fontpos; + + p->sum += (fontpos << 20) + unicode; + + return 0; } - + /* ui is a leftover from using a hashtable, but might be used again */ -void -con_clear_unimap(struct unimapinit *ui) +int con_clear_unimap(int con, struct unimapinit *ui) { - int i, j; - u16 **p1; + struct uni_pagedir *p, *q; + struct vc_data *conp = vc_cons[con].d; - for ( i = 0 ; i < 32 ; i++ ) - { - if ( (p1 = uni_pagedir[i]) != NULL ) - { - for ( j = 0 ; j < 32 ; j++ ) - { - if ( p1[j] ) - kfree(p1[j]); - } - kfree(p1); + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (p && p->readonly) return -EIO; + if (!p || --p->refcount) { + q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL); + if (!q) { + if (p) p->refcount++; + return -ENOMEM; + } + memset(q, 0, sizeof(*q)); + q->refcount=1; + *conp->vc_uni_pagedir_loc = (unsigned long)q; + } else { + if (p == dflt) dflt = NULL; + p->refcount++; + p->sum = 0; + con_release_unimap(p); } - uni_pagedir[i] = NULL; - } - - hashtable_contents_valid = 1; + return 0; } int -con_set_unimap(ushort ct, struct unipair *list) +con_set_unimap(int con, ushort ct, struct unipair *list) { - int err = 0, err1, i; + int err = 0, err1, i; + struct uni_pagedir *p, *q; + struct vc_data *conp = vc_cons[con].d; - while( ct-- ) - { - unsigned short unicode, fontpos; - __get_user(unicode, &list->unicode); - __get_user(fontpos, &list->fontpos); - if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 ) - err = err1; - list++; - } + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (p->readonly) return -EIO; + + if (!ct) return 0; + + if (p->refcount > 1) { + int j, k; + u16 **p1, *p2, l; + + err1 = con_clear_unimap(con, NULL); + if (err1) return err1; + + q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + for (i = 0, l = 0; i < 32; i++) + if ((p1 = p->uni_pgdir[i])) + for (j = 0; j < 32; j++) + if ((p2 = p1[j])) + for (k = 0; k < 64; k++, l++) + if (p2[k] != 0xffff) { + err1 = con_insert_unipair(q, l, p2[k]); + if (err1) { + p->refcount++; + *conp->vc_uni_pagedir_loc = (unsigned long)p; + con_release_unimap(q); + kfree(q); + return err1; + } + } + p = q; + } else if (p == dflt) + dflt = NULL; + + while (ct--) { + unsigned short unicode, fontpos; + __get_user(unicode, &list->unicode); + __get_user(fontpos, &list->fontpos); + if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0) + err = err1; + list++; + } + + if (con_unify_unimap(conp, p)) + return err; - for ( i = 0 ; i <= 3 ; i++ ) - set_inverse_transl(i); /* Update all inverse translations */ + for (i = 0; i <= 3; i++) + set_inverse_transl(conp, p, i); /* Update all inverse translations */ - return err; + return err; } /* Loads the unimap for the hardware font, as defined in uni_hash.tbl. @@ -401,83 +528,123 @@ with. This routine is executed at sys_setup time, and when the PIO_FONTRESET ioctl is called. */ -void -con_set_default_unimap(void) +int +con_set_default_unimap(int con) { - int i, j; - u16 *p; - - /* The default font is always 256 characters */ - - con_clear_unimap(NULL); + int i, j, err = 0, err1; + u16 *q; + struct uni_pagedir *p; + struct vc_data *conp = vc_cons[con].d; + + if (dflt) { + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (p == dflt) + return 0; + dflt->refcount++; + *conp->vc_uni_pagedir_loc = (unsigned long)dflt; + if (p && --p->refcount) { + con_release_unimap(p); + kfree(p); + } + return 0; + } + + /* The default font is always 256 characters */ - p = dfont_unitable; - for ( i = 0 ; i < 256 ; i++ ) - for ( j = dfont_unicount[i] ; j ; j-- ) - con_insert_unipair(*(p++), i); + err = con_clear_unimap(con,NULL); + if (err) return err; + + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + q = dfont_unitable; + + for (i = 0; i < 256; i++) + for (j = dfont_unicount[i]; j; j--) { + err1 = con_insert_unipair(p, *(q++), i); + if (err1) + err = err1; + } + + if (con_unify_unimap(conp, p)) { + dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + return err; + } - for ( i = 0 ; i <= 3 ; i++ ) - set_inverse_transl(i); /* Update all inverse translations */ + for (i = 0; i <= 3; i++) + set_inverse_transl(conp, p, i); /* Update all inverse translations */ + dflt = p; + return err; } int -con_get_unimap(ushort ct, ushort *uct, struct unipair *list){ +con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list) +{ int i, j, k, ect; u16 **p1, *p2; + struct uni_pagedir *p; + struct vc_data *conp = vc_cons[con].d; ect = 0; - if (hashtable_contents_valid) - { - for ( i = 0 ; i < 32 ; i++ ) - if ( (p1 = uni_pagedir[i]) != NULL ) - for ( j = 0 ; j < 32 ; j++ ) - if ( (p2 = *(p1++)) != NULL ) - for ( k = 0 ; k < 64 ; k++ ) - { - if ( *p2 < MAX_GLYPH && ect++ < ct ) - { - __put_user((u_short)((i<<11)+(j<<6)+k), - &list->unicode); - __put_user((u_short) *p2, &list->fontpos); - list++; - } - p2++; - } - } + if (*conp->vc_uni_pagedir_loc) { + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + for (i = 0; i < 32; i++) + if ((p1 = p->uni_pgdir[i])) + for (j = 0; j < 32; j++) + if ((p2 = *(p1++))) + for (k = 0; k < 64; k++) { + if (*p2 < MAX_GLYPH && ect++ < ct) { + __put_user((u_short)((i<<11)+(j<<6)+k), + &list->unicode); + __put_user((u_short) *p2, + &list->fontpos); + list++; + } + p2++; + } + } __put_user(ect, uct); return ((ect <= ct) ? 0 : -ENOMEM); } +void con_protect_unimap(int con, int rdonly) +{ + struct uni_pagedir *p = (struct uni_pagedir *) + *vc_cons[con].d->vc_uni_pagedir_loc; + + if (p) p->readonly = rdonly; +} + int -conv_uni_to_pc(long ucs) +conv_uni_to_pc(struct vc_data *conp, long ucs) { - int h; - u16 **p1, *p2; - - /* Only 16-bit codes supported at this time */ - if (ucs > 0xffff) - ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */ - else if (ucs < 0x20 || ucs >= 0xfffe) - return -1; /* Not a printable character */ - else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) - return -2; /* Zero-width space */ - /* - * UNI_DIRECT_BASE indicates the start of the region in the User Zone - * which always has a 1:1 mapping to the currently loaded font. The - * UNI_DIRECT_MASK indicates the bit span of the region. - */ - else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE ) - return ucs & UNI_DIRECT_MASK; + int h; + u16 **p1, *p2; + struct uni_pagedir *p; - if (!hashtable_contents_valid) - return -3; + /* Only 16-bit codes supported at this time */ + if (ucs > 0xffff) + ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */ + else if (ucs < 0x20 || ucs >= 0xfffe) + return -1; /* Not a printable character */ + else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) + return -2; /* Zero-width space */ + /* + * UNI_DIRECT_BASE indicates the start of the region in the User Zone + * which always has a 1:1 mapping to the currently loaded font. The + * UNI_DIRECT_MASK indicates the bit span of the region. + */ + else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) + return ucs & UNI_DIRECT_MASK; - if ( (p1 = uni_pagedir[ucs >> 11]) && - (p2 = p1[(ucs >> 6) & 0x1f]) && - (h = p2[ucs & 0x3f]) < MAX_GLYPH ) - return h; + if (!*conp->vc_uni_pagedir_loc) + return -3; + + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if ((p1 = p->uni_pgdir[ucs >> 11]) && + (p2 = p1[(ucs >> 6) & 0x1f]) && + (h = p2[ucs & 0x3f]) < MAX_GLYPH) + return h; - return -4; /* not found */ + return -4; /* not found */ } /* @@ -488,5 +655,9 @@ __initfunc(void console_map_init(void)) { - con_set_default_unimap(); + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) + if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) + con_set_default_unimap(i); } diff -u --recursive --new-file v2.1.111/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.111/linux/drivers/char/esp.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/esp.c Sat Jul 25 18:48:29 1998 @@ -37,7 +37,6 @@ * int espserial_init(void); */ -#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v2.1.111/linux/drivers/char/fbmem.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/char/fbmem.c Sun Jul 26 14:40:18 1998 @@ -420,6 +420,9 @@ #elif defined(__sparc__) /* Should never get here, all fb drivers should have their own mmap routines */ +#elif defined(__i386__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; #else #warning What do we have to do here?? #endif @@ -497,7 +500,7 @@ if (first) { first = 0; - take_over_console(&fb_con, 0, MAX_NR_CONSOLES-1, 1); + take_over_console(&fb_con, 12, MAX_NR_CONSOLES-1, 1); } return 0; diff -u --recursive --new-file v2.1.111/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.111/linux/drivers/char/selection.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/selection.c Sun Jul 26 14:40:18 1998 @@ -60,7 +60,7 @@ static unsigned char sel_pos(int n) { - return inverse_translate(screen_glyph(sel_cons, n)); + return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n)); } /* remove the current selection highlight, if any, diff -u --recursive --new-file v2.1.111/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.1.111/linux/drivers/char/vc_screen.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/vc_screen.c Sun Jul 26 14:40:18 1998 @@ -7,7 +7,8 @@ * [minor: N] * * /dev/vcsaN: idem, but including attributes, and prefixed with - * the 4 bytes lines,columns,x,y (as screendump used to give) + * the 4 bytes lines,columns,x,y (as screendump used to give). + * Attribute/character pair is in native endianity. * [minor: N+128] * * This replaces screendump and part of selection, so that the system @@ -20,6 +21,8 @@ * - making it shorter - scr_readw are macros which expand in PRETTY long code */ +#include + #include #include #include @@ -39,18 +42,6 @@ #undef addr #define HEADER_SIZE 4 -static unsigned short -func_scr_readw(unsigned short *org) -{ -return scr_readw( org ); -} - -static void -func_scr_writew(unsigned short val, unsigned short *org) -{ -scr_writew( val, org ); -} - static int vcs_size(struct inode *inode) { @@ -91,7 +82,7 @@ return file->f_pos; } -#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; } +#define RETURN(x) { enable_bh(CONSOLE_BH); return x; } static ssize_t vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) { @@ -104,7 +95,7 @@ attr = (currcons & 128); currcons = (currcons & 127); - disable_bh( CONSOLE_BH ); + disable_bh(CONSOLE_BH); if (currcons == 0) { currcons = fg_console; viewed = 1; @@ -125,7 +116,7 @@ if (!attr) { org = screen_pos(currcons, p, viewed); while (count-- > 0) - put_user(func_scr_readw(org++) & 0xff, buf++); + put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); } else { if (p < HEADER_SIZE) { char header[HEADER_SIZE]; @@ -140,21 +131,21 @@ org = screen_pos(currcons, p/2, viewed); if ((p & 1) && count > 0) #ifdef __BIG_ENDIAN - { count--; put_user(func_scr_readw(org++) & 0xff, buf++); } + { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); } #else - { count--; put_user(func_scr_readw(org++) >> 8, buf++); } + { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); } #endif } while (count > 1) { - put_user(func_scr_readw(org++), (unsigned short *) buf); + put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf); buf += 2; count -= 2; } if (count > 0) #ifdef __BIG_ENDIAN - put_user(func_scr_readw(org) >> 8, buf++); + put_user(vcs_scr_readw(currcons, org) >> 8, buf++); #else - put_user(func_scr_readw(org) & 0xff, buf++); + put_user(vcs_scr_readw(currcons, org) & 0xff, buf++); #endif } read = buf - buf0; @@ -174,7 +165,7 @@ attr = (currcons & 128); currcons = (currcons & 127); - disable_bh( CONSOLE_BH ); + disable_bh(CONSOLE_BH); if (currcons == 0) { currcons = fg_console; viewed = 1; @@ -198,7 +189,7 @@ unsigned char c; count--; get_user(c, (const unsigned char*)buf++); - func_scr_writew((func_scr_readw(org) & 0xff00) | c, org); + vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); org++; } } else { @@ -218,11 +209,11 @@ count--; get_user(c,buf++); #ifdef __BIG_ENDIAN - func_scr_writew(c | - (func_scr_readw(org) & 0xff00), org); + vcs_scr_writew(currcons, c | + (vcs_scr_readw(currcons, org) & 0xff00), org); #else - func_scr_writew((c << 8) | - (func_scr_readw(org) & 0xff), org); + vcs_scr_writew(currcons, (c << 8) | + (vcs_scr_readw(currcons, org) & 0xff), org); #endif org++; } @@ -230,7 +221,7 @@ while (count > 1) { unsigned short w; get_user(w, (const unsigned short *) buf); - func_scr_writew(w, org++); + vcs_scr_writew(currcons, w, org++); buf += 2; count -= 2; } @@ -238,9 +229,9 @@ unsigned char c; get_user(c, (const unsigned char*)buf++); #ifdef __BIG_ENDIAN - func_scr_writew((func_scr_readw(org) & 0xff) | (c << 8), org); + vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org); #else - func_scr_writew((func_scr_readw(org) & 0xff00) | c, org); + vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); #endif } } diff -u --recursive --new-file v2.1.111/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.111/linux/drivers/char/vt.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/char/vt.c Sun Jul 26 14:40:18 1998 @@ -113,21 +113,18 @@ } /* - * Generates sound of some count for some number of clock ticks - * [count = 1193180 / frequency] + * Generates sound of some frequency for some number of clock ticks * * If freq is 0, will turn off sound, else will turn it on for that time. * If msec is 0, will return immediately, else will sleep for msec time, then * turn sound off. * - * We use the BEEP_TIMER vector since we're using the same method to - * generate sound, and we'll overwrite any beep in progress. That may - * be something to fix later, if we like. - * * We also return immediately, which is what was implied within the X * comments - KDMKTONE doesn't put the process to sleep. */ -/* FIXME: This should go to arch-dependent code */ + +#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__) + static void kd_nosound(unsigned long ignored) { @@ -168,6 +165,15 @@ return; } +#else + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +#endif + void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; @@ -394,8 +400,6 @@ op.data = cfdarg.chardata; return con_font_op(fg_console, &op); case GIO_FONTX: { - if (!cfdarg.chardata) - return 0; op.op = KD_FONT_OP_GET; op.flags = 0; op.width = 8; @@ -432,9 +436,9 @@ case PIO_UNIMAP: if (!perm) return -EPERM; - return con_set_unimap(tmp.entry_ct, tmp.entries); + return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries); case GIO_UNIMAP: - return con_get_unimap(tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); + return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); } return 0; } @@ -994,11 +998,11 @@ #else { struct console_font_op op; - op.op = KD_FONT_SET_DEFAULT; + op.op = KD_FONT_OP_SET_DEFAULT; op.data = NULL; i = con_font_op(fg_console, &op); if (i) return i; - con_set_default_unimap(); + con_set_default_unimap(fg_console); return 0; } #endif @@ -1010,6 +1014,7 @@ return -EFAULT; if (!perm && op.op != KD_FONT_OP_GET) return -EPERM; + op.flags |= KD_FONT_FLAG_NEW; i = con_font_op(console, &op); if (i) return i; if (copy_to_user((void *) arg, &op, sizeof(op))) @@ -1039,7 +1044,7 @@ return -EPERM; i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); if (i) return -EFAULT; - con_clear_unimap(&ui); + con_clear_unimap(fg_console, &ui); return 0; } @@ -1189,10 +1194,6 @@ { unsigned char old_vc_mode; - if ((new_console == fg_console) || (vt_dont_switch)) - return; - if (!vc_cons_allocated(new_console)) - return; last_console = fg_console; /* diff -u --recursive --new-file v2.1.111/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.111/linux/drivers/misc/parport_procfs.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/misc/parport_procfs.c Sun Jul 26 19:39:25 1998 @@ -182,6 +182,8 @@ int len = 0; const char *str; + page[0] = '\0'; + if ((str = pp->probe_info.class_name) != NULL) len += sprintf (page+len, "CLASS:%s;\n", str); @@ -199,7 +201,7 @@ *start = 0; *eof = 1; - return strlen (page); + return len; } static inline void destroy_proc_entry(struct proc_dir_entry *root, diff -u --recursive --new-file v2.1.111/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.1.111/linux/drivers/net/3c509.c Sun Jul 26 11:57:15 1998 +++ linux/drivers/net/3c509.c Sun Jul 26 23:35:55 1998 @@ -451,6 +451,8 @@ dev->tbusy = 0; } + lp->stats.tx_bytes += skb->len; + if (el3_debug > 4) { printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS)); @@ -667,6 +669,7 @@ struct sk_buff *skb; skb = dev_alloc_skb(pkt_len+5); + lp->stats.rx_bytes += pkt_len; if (el3_debug > 4) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); diff -u --recursive --new-file v2.1.111/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.111/linux/drivers/net/Config.in Sun Jul 26 11:57:15 1998 +++ linux/drivers/net/Config.in Sun Jul 26 23:35:55 1998 @@ -31,8 +31,14 @@ source drivers/acorn/net/Config.in fi fi - if [ "$CONFIG_PMAC" = "y" ]; then - bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE + if [ "$CONFIG_PPC" = "y" ]; then + bool 'MACE (Power Mac ethernet) support' CONFIG_MACE + bool 'BMAC (G3 ethernet) support' CONFIG_BMAC + fi + if [ "$CONFIG_APUS" = "y" ]; then + tristate 'Ariadne support' CONFIG_ARIADNE + tristate 'A2065 support' CONFIG_A2065 + tristate 'Hydra support' CONFIG_HYDRA fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC diff -u --recursive --new-file v2.1.111/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.111/linux/drivers/net/Makefile Sun Jul 26 11:57:15 1998 +++ linux/drivers/net/Makefile Sun Jul 26 23:35:56 1998 @@ -151,6 +151,14 @@ endif endif +ifeq ($(CONFIG_ETHERH),y) +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_ETHERH),m) + CONFIG_8390_MODULE = y + endif +endif + ifeq ($(CONFIG_NE2K_PCI),y) L_OBJS += ne2k-pci.o CONFIG_8390_BUILTIN = y @@ -851,6 +859,10 @@ ifeq ($(CONFIG_MACE),y) L_OBJS += mace.o +endif + +ifeq ($(CONFIG_BMAC),y) +L_OBJS += bmac.o endif ifeq ($(CONFIG_VENDOR_SANGOMA),y) diff -u --recursive --new-file v2.1.111/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.111/linux/drivers/net/Space.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/net/Space.c Sun Jul 26 23:35:56 1998 @@ -95,6 +95,7 @@ extern int pamsnet_probe(struct device *); extern int tlan_probe(struct device *); extern int mace_probe(struct device *); +extern int bmac_probe(struct device *); extern int cs89x0_probe(struct device *dev); extern int ethertap_probe(struct device *dev); extern int ether1_probe (struct device *dev); @@ -380,6 +381,9 @@ struct devprobe ppc_probes[] __initdata = { #ifdef CONFIG_MACE {mace_probe, 0}, +#endif +#ifdef CONFIG_BMAC + {bmac_probe, 0}, #endif {NULL, 0}, }; diff -u --recursive --new-file v2.1.111/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.1.111/linux/drivers/net/bmac.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/bmac.c Sun Jul 26 23:35:56 1998 @@ -0,0 +1,1450 @@ +/* + * Network device driver for the BMAC ethernet controller on + * Apple Powermacs. Assumes it's under a DBDMA controller. + * + * Copyright (C) 1998 Randy Gobbel. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bmac.h" + +#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) +#define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1))) + +/* + * CRC polynomial - used in working out multicast filter bits. + */ +#define ENET_CRCPOLY 0x04c11db7 + +/* a bunch of constants for the "Heathrow" interrupt controller. + These really should be in an include file somewhere */ +#define IoBaseHeathrow ((unsigned *)0xf3000000) +#define HeathrowFCR 0x0038 /* FCR offset from Heathrow Base Address */ +#define fcrEnetEnabledBits 0x60000000 /* mask to enable Enet Xcvr/Controller */ +#define fcrResetEnetCell 0x80000000 /* mask used to reset Enet cell */ +#define fcrClearResetEnetCell 0x7fffffff /* mask used to clear reset Enet cell */ +#define fcrDisableEnet 0x1fffffff /* mask to disable Enet Xcvr/Controller */ + +#define N_RX_RING 64 +#define N_TX_RING 32 +#define MAX_TX_ACTIVE 1 +#define ETHERCRC 4 +#define ETHERMINPACKET 64 +#define ETHERMTU 1500 +#define RX_BUFLEN (ETHERMTU + 14 + ETHERCRC + 2) +#define TX_TIMEOUT HZ /* 1 second */ + +/* Bits in transmit DMA status */ +#define TX_DMA_ERR 0x80 + +#define XXDEBUG(args) + +struct bmac_data { +/* volatile struct bmac *bmac; */ + struct sk_buff_head *queue; + volatile struct dbdma_regs *tx_dma; + int tx_dma_intr; + volatile struct dbdma_regs *rx_dma; + int rx_dma_intr; + volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */ + volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */ + struct sk_buff *rx_bufs[N_RX_RING]; + int rx_fill; + int rx_empty; + struct sk_buff *tx_bufs[N_TX_RING]; + char *tx_double[N_TX_RING]; /* yuck--double buffering */ + int tx_fill; + int tx_empty; + unsigned char tx_fullup; + 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]; +}; + +typedef struct bmac_reg_entry { + char *name; + unsigned short reg_offset; +} bmac_reg_entry_t; + +#define N_REG_ENTRIES 30 + +bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = { + {"MEMADD", MEMADD}, + {"MEMDATAHI", MEMDATAHI}, + {"MEMDATALO", MEMDATALO}, + {"TXPNTR", TXPNTR}, + {"RXPNTR", RXPNTR}, + {"IPG1", IPG1}, + {"IPG2", IPG2}, + {"ALIMIT", ALIMIT}, + {"SLOT", SLOT}, + {"PALEN", PALEN}, + {"PAPAT", PAPAT}, + {"TXSFD", TXSFD}, + {"JAM", JAM}, + {"TXMAX", TXMAX}, + {"TXMIN", TXMIN}, + {"PAREG", PAREG}, + {"DCNT", DCNT}, + {"NCCNT", NCCNT}, + {"NTCNT", NTCNT}, + {"EXCNT", EXCNT}, + {"LTCNT", LTCNT}, + {"TXSM", TXSM}, + {"RXCFG", RXCFG}, + {"RXMAX", RXMAX}, + {"RXMIN", RXMIN}, + {"FRCNT", FRCNT}, + {"AECNT", AECNT}, + {"FECNT", FECNT}, + {"RXSM", RXSM}, + {"RXCV", RXCV} +}; + +struct device *bmac_devs = NULL; + +#if 0 +/* + * If we can't get a skbuff when we need it, we use this area for DMA. + */ +static unsigned char dummy_buf[RX_BUFLEN]; +#endif + +/* + * Number of bytes of private data per BMAC: allow enough for + * the rx and tx dma commands plus a branch dma command each, + * and another 16 bytes to allow us to align the dma command + * buffers on a 16 byte boundary. + */ +#define PRIV_BYTES (sizeof(struct bmac_data) \ + + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \ + + sizeof(struct sk_buff_head)) + +static unsigned char bitrev(unsigned char b); +static int bmac_open(struct device *dev); +static int bmac_close(struct device *dev); +static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev); +static struct net_device_stats *bmac_stats(struct device *dev); +static void bmac_set_multicast(struct device *dev); +static int bmac_reset_and_enable(struct device *dev, int enable); +static void bmac_start_chip(struct device *dev); +static int bmac_init_chip(struct device *dev); +static void bmac_init_registers(struct device *dev); +static void bmac_reset_chip(struct device *dev); +static int bmac_set_address(struct device *dev, void *addr); +static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs); +static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void bmac_set_timeout(struct device *dev); +static void bmac_tx_timeout(unsigned long data); +static void bmac_reset_chip(struct device *dev); +static void bmac_init_registers(struct device *dev); +static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy); +static int bmac_output(struct sk_buff *skb, struct device *dev); +static void bmac_start(struct device *dev); + +#define DBDMA_SET(x) ( ((x) | (x) << 16) ) +#define DBDMA_CLEAR(x) ( (x) << 16) + +static __inline__ void +dbdma_st32(volatile unsigned long *a, unsigned long x) +{ + __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory"); + return; +} + +static __inline__ unsigned long +dbdma_ld32(volatile unsigned long *a) +{ + unsigned long swap; + __asm__ volatile ("lwbrx %0,0,%1" : "=r" (swap) : "r" (a)); + return swap; +} + +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, + DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD)); + eieio(); +} + +static void +dbdma_reset(volatile struct dbdma_regs *dmap) +{ + dbdma_st32((volatile unsigned long *)&dmap->control, + DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)); + eieio(); + while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio(); +} + +static void +dbdma_setcmd(volatile struct dbdma_cmd *cp, + unsigned short cmd, unsigned count, unsigned long addr, + unsigned long cmd_dep) +{ + out_le16(&cp->command, cmd); + out_le16(&cp->req_count, count); + out_le32(&cp->phy_addr, addr); + out_le32(&cp->cmd_dep, cmd_dep); + out_le16(&cp->xfer_status, 0); + out_le16(&cp->res_count, 0); +} + +static __inline__ +void bmwrite(struct device *dev, unsigned long reg_offset, unsigned data ) +{ + out_le16((void *)dev->base_addr + reg_offset, data); +} + + +static __inline__ +volatile unsigned short bmread(struct device *dev, unsigned long reg_offset ) +{ + return in_le16((void *)dev->base_addr + reg_offset); +} + +static void +bmac_reset_chip(struct device *dev) +{ + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *rd = bp->rx_dma; + volatile struct dbdma_regs *td = bp->tx_dma; + volatile unsigned *heathrowFCR; + unsigned int fcrValue; + + dbdma_reset(rd); + dbdma_reset(td); + + heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR); + + fcrValue = in_le32(heathrowFCR); + + fcrValue &= fcrDisableEnet; /* clear out Xvr and Controller Bit */ + out_le32(heathrowFCR, fcrValue); + udelay(50000); + + fcrValue |= fcrResetEnetCell; /* set bit to reset them */ + out_le32(heathrowFCR, fcrValue); + udelay(50000); + + fcrValue &= fcrDisableEnet; + out_le32(heathrowFCR, fcrValue); + udelay(50000); + + fcrValue |= fcrEnetEnabledBits; + out_le32(heathrowFCR, fcrValue); + udelay(50000); + + out_le32(heathrowFCR, fcrValue); +} + +static void +bmac_init_registers(struct device *dev) +{ + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile unsigned short regValue; + unsigned short *pWord16; + int i; + +/* XXDEBUG(("bmac: enter init_registers\n")); */ + + bmwrite(dev, TXRST, TxResetBit); + + do { + regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */ + } while (regValue & TxResetBit); + + bmwrite(dev, RXRST, RxResetValue); + bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow); + bmwrite(dev, RSEED, (unsigned short)0x1968); + + regValue = bmread(dev, XIFC); + regValue |= TxOutputEnable; + bmwrite(dev, XIFC, regValue); + + bmread(dev, PAREG); + + /* set collision counters to 0 */ + bmwrite(dev, NCCNT, 0); + bmwrite(dev, NTCNT, 0); + bmwrite(dev, EXCNT, 0); + bmwrite(dev, LTCNT, 0); + + /* set rx counters to 0 */ + bmwrite(dev, FRCNT, 0); + bmwrite(dev, LECNT, 0); + bmwrite(dev, AECNT, 0); + bmwrite(dev, FECNT, 0); + bmwrite(dev, RXCV, 0); + + /* set tx fifo information */ + bmwrite(dev, TXTH, 4); /* 4 octets before tx starts */ + + bmwrite(dev, TXFIFOCSR, 0); /* first disable txFIFO */ + bmwrite(dev, TXFIFOCSR, TxFIFOEnable ); + + /* set rx fifo information */ + bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ + bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); + + //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */ + bmread(dev, STATUS); /* read it just to clear it */ + + bmwrite(dev, INTDISABLE, EnableNormal); + + /* zero out the chip Hash Filter registers */ + for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; + bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ + bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */ + bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */ + bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */ + + pWord16 = (unsigned short *)dev->dev_addr; + bmwrite(dev, MADD0, *pWord16++); + bmwrite(dev, MADD1, *pWord16++); + bmwrite(dev, MADD2, *pWord16); + + + bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets); + + return; +} + +#if 0 +static void +bmac_disable_interrupts(struct device *dev) +{ + bmwrite(dev, INTDISABLE, DisableAll); +} + +static void +bmac_enable_interrupts(struct device *dev) +{ + bmwrite(dev, INTDISABLE, EnableNormal); +} +#endif + + +static void +bmac_start_chip(struct device *dev) +{ + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *rd = bp->rx_dma; + unsigned short oldConfig; + + /* enable rx dma channel */ + dbdma_continue(rd); + + /* turn on rx plus any other bits already on (promiscuous possibly) */ + oldConfig = bmread(dev, RXCFG); + bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); + + oldConfig = bmread(dev, TXCFG); + bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); +} + +static int +bmac_init_chip(struct device *dev) +{ + bmac_init_registers(dev); + return 1; +} + +static int bmac_set_address(struct device *dev, void *addr) +{ + unsigned char *p = addr; + unsigned short *pWord16; + unsigned long flags; + int i; + + XXDEBUG(("bmac: enter set_address\n")); + save_flags(flags); cli(); + + for (i = 0; i < 6; ++i) { + dev->dev_addr[i] = p[i]; + } + /* load up the hardware address */ + pWord16 = (unsigned short *)dev->dev_addr; + bmwrite(dev, MADD0, *pWord16++); + bmwrite(dev, MADD1, *pWord16++); + bmwrite(dev, MADD2, *pWord16); + + restore_flags(flags); + XXDEBUG(("bmac: exit set_address\n")); + return 0; +} + +static inline void bmac_set_timeout(struct device *dev) +{ + struct bmac_data *bp = (struct bmac_data *) dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + if (bp->timeout_active) + del_timer(&bp->tx_timeout); + bp->tx_timeout.expires = jiffies + TX_TIMEOUT; + bp->tx_timeout.function = bmac_tx_timeout; + bp->tx_timeout.data = (unsigned long) dev; + add_timer(&bp->tx_timeout); + bp->timeout_active = 1; + restore_flags(flags); +} + +static void +bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp, + char *doubleBuf) +{ + void *vaddr, *page_break; + unsigned long baddr; + unsigned long len; + + len = skb->len; + vaddr = skb->data; + baddr = virt_to_bus(vaddr); + page_break = round_page(vaddr); + if (trunc_page(vaddr) != trunc_page(vaddr+len) && + (unsigned long)round_page(baddr) != virt_to_bus(page_break)) { + baddr = virt_to_bus(doubleBuf); + XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len)); + } else + flush_page_to_ram((unsigned long)vaddr); + + dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0); +} + +static void +bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp) +{ + dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0); +} + +/* Bit-reverse one byte of an ethernet hardware address. */ +static unsigned char +bitrev(unsigned char b) +{ + int d = 0, i; + + for (i = 0; i < 8; ++i, b >>= 1) + d = (d << 1) | (b & 1); + return d; +} + + +static int +bmac_init_tx_ring(struct bmac_data *bp) +{ + int i; + volatile struct dbdma_regs *td = bp->tx_dma; + char *addr; + + if (!bp->tx_allocated) { + /* zero out tx cmds, alloc space for double buffering */ + addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA); + for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr; + bp->tx_allocated = 1; + } + memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd)); + + bp->tx_empty = 0; + bp->tx_fill = 0; + bp->tx_fullup = 0; + + /* put a branch at the end of the tx command list */ + dbdma_setcmd(&bp->tx_cmds[N_TX_RING], + (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds)); + + /* reset tx dma */ + dbdma_reset(td); + out_le32(&td->wait_sel, 0x00200020); + out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds)); + + return 1; + +} + +static int +bmac_init_rx_ring(struct bmac_data *bp) +{ + volatile struct dbdma_regs *rd = bp->rx_dma; + int i; + + /* 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); + skb_reserve(bp->rx_bufs[i], 2); + } + bp->rx_allocated = 1; + } + + 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; + + /* Put a branch back to the beginning of the receive command list */ + dbdma_setcmd(&bp->rx_cmds[N_RX_RING], + (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds)); + + /* start rx dma */ + dbdma_reset(rd); + out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds)); + + return 1; +} + + +static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev) +{ + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *td = bp->tx_dma; + int i; + + /* see if there's a free slot in the tx ring */ +/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */ +/* bp->tx_empty, bp->tx_fill)); */ + i = bp->tx_fill + 1; + if (i >= N_TX_RING) i = 0; + if (i == bp->tx_empty) { + dev->tbusy = 1; + bp->tx_fullup = 1; + XXDEBUG(("bmac_transmit_packet: tx ring full\n")); + return -1; /* can't take it at the moment */ + } + + dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0); + + bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]); + + bp->tx_bufs[bp->tx_fill] = skb; + bp->tx_fill = i; + + dbdma_continue(td); + + return 0; +} + +static int rxintcount = 0; + +static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *rd = bp->rx_dma; + volatile struct dbdma_cmd *cp; + int i, nb, stat; + struct sk_buff *skb; + unsigned int residual; + int last; + unsigned long flags; + + save_flags(flags); cli(); + + if (++rxintcount < 10) { + XXDEBUG(("bmac_rxdma_intr\n")); + } + + last = -1; + i = bp->rx_empty; + + while (1) { + cp = &bp->rx_cmds[i]; + stat = ld_le16(&cp->xfer_status); + residual = ld_le16(&cp->res_count); + 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]; + 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]); + ++bp->stats.rx_packets; + } else { + ++bp->stats.rx_dropped; + } + st_le16(&cp->res_count, 0); + st_le16(&cp->xfer_status, 0); + last = i; + if (++i >= N_RX_RING) i = 0; + } + + if (last != -1) { + bp->rx_fill = last; + bp->rx_empty = i; + } + + restore_flags(flags); + + dbdma_continue(rd); + + if (rxintcount < 10) { + XXDEBUG(("bmac_rxdma_intr done\n")); + } +} + +static int txintcount = 0; + +static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_cmd *cp; + int stat; + unsigned long flags; + + save_flags(flags); cli(); + + if (txintcount++ < 10) { + XXDEBUG(("bmac_txdma_intr\n")); + } + +/* del_timer(&bp->tx_timeout); */ +/* bp->timeout_active = 0; */ + + while (1) { + cp = &bp->tx_cmds[bp->tx_empty]; + stat = ld_le16(&cp->xfer_status); + if (txintcount < 10) { + XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); + } + if (!(stat & ACTIVE)) break; + + if (bp->tx_bufs[bp->tx_empty]) { + ++bp->stats.tx_packets; + dev_kfree_skb(bp->tx_bufs[bp->tx_empty]); + } + bp->tx_bufs[bp->tx_empty] = NULL; + bp->tx_fullup = 0; + dev->tbusy = 0; +/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */ +/* i, bp->tx_fill)); */ + mark_bh(NET_BH); + if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0; + if (bp->tx_empty == bp->tx_fill) break; + } + + restore_flags(flags); + + if (txintcount < 10) { + XXDEBUG(("bmac_txdma_intr done->bmac_start\n")); + } + + bmac_start(dev); +} + +static struct net_device_stats *bmac_stats(struct device *dev) +{ + struct bmac_data *p = (struct bmac_data *) dev->priv; + + return &p->stats; +} + +#if 0 +/* Real fast bit-reversal algorithm, 6-bit values */ +static int reverse6[64] = { + 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, + 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, + 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, + 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, + 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, + 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, + 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, + 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f +}; + +static unsigned int +crc416(unsigned int curval, unsigned short nxtval) +{ + register unsigned int counter, cur = curval, next = nxtval; + register int high_crc_set, low_data_set; + + /* Swap bytes */ + next = ((next & 0x00FF) << 8) | (next >> 8); + + /* Compute bit-by-bit */ + for (counter = 0; counter < 16; ++counter) { + /* is high CRC bit set? */ + if ((cur & 0x80000000) == 0) high_crc_set = 0; + else high_crc_set = 1; + + cur = cur << 1; + + if ((next & 0x0001) == 0) low_data_set = 0; + else low_data_set = 1; + + next = next >> 1; + + /* do the XOR */ + if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY; + } + return cur; +} + +static unsigned int +bmac_crc(unsigned short *address) +{ + unsigned int newcrc; + + XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2])); + newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ + newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ + newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ + + return(newcrc); +} + +/* + * Add requested mcast addr to BMac's hash table filter. + * + */ + +static void +bmac_addhash(struct bmac_data *bp, unsigned char *addr) +{ + unsigned int crc; + unsigned short mask; + + if (!(*addr + crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ + crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ + if (bp->hash_use_count[crc]++) return; /* This bit is already set */ + mask = crc % 16; + mask = (unsigned char)1 << mask; + bp->hash_use_count[crc/16] |= mask; + } + + static void + bmac_removehash(struct bmac_data *bp, unsigned char *addr) + { + unsigned int crc; + unsigned char mask; + + /* Now, delete the address from the filter copy, as indicated */ + crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ + crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ + if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */ + if (--bp->hash_use_count[crc]) return; /* That bit is still in use */ + mask = crc % 16; + mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */ + bp->hash_table_mask[crc/16] &= mask; + } + +/* + * Sync the adapter with the software copy of the multicast mask + * (logical address filter). + */ + + static void + bmac_rx_off(struct device *dev) + { + unsigned short rx_cfg; + + rx_cfg = bmread(dev, RXCFG); + rx_cfg &= ~RxMACEnable; + bmwrite(dev, RXCFG, rx_cfg); + do { + rx_cfg = bmread(dev, RXCFG); + } while (rx_cfg & RxMACEnable); + } + + unsigned short + bmac_rx_on(struct device *dev, int hash_enable, int promisc_enable) + { + unsigned short rx_cfg; + + rx_cfg = bmread(dev, RXCFG); + rx_cfg |= RxMACEnable; + if (hash_enable) rx_cfg |= RxHashFilterEnable; + else rx_cfg &= ~RxHashFilterEnable; + if (promisc_enable) rx_cfg |= RxPromiscEnable; + else rx_cfg &= ~RxPromiscEnable; + bmwrite(dev, RXRST, RxResetValue); + bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ + bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); + bmwrite(dev, RXCFG, rx_cfg ); + return rx_cfg; + } + + static void + bmac_update_hash_table_mask(struct device *dev, struct bmac_data *bp) + { + bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ + bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */ + bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */ + bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */ + } + +#if 0 + static void + bmac_add_multi(struct device *dev, + struct bmac_data *bp, unsigned char *addr) + { +/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */ + bmac_addhash(bp, addr); + bmac_rx_off(dev); + bmac_update_hash_table_mask(dev, bp); + bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0); +/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */ + } + + static void + bmac_remove_multi(struct device *dev, + struct bmac_data *bp, unsigned char *addr) + { + bmac_removehash(bp, addr); + bmac_rx_off(dev); + bmac_update_hash_table_mask(dev, bp); + bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0); + } +#endif + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ + static void bmac_set_multicast(struct device *dev) + { + struct dev_mc_list *dmi; + struct bmac_data *bp = (struct bmac_data *) dev->priv; + int num_addrs = dev->mc_count; + unsigned short rx_cfg; + int i; + + XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs)); + + if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff; + bmac_update_hash_table_mask(dev, bp); + rx_cfg = bmac_rx_on(dev, 1, 0); + XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n")); + } else if if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) { + rx_cfg = bmread(dev, RXCFG); + rx_cfg |= RxPromiscEnable; + bmwrite(dev, RXCFG, rx_cfg); + rx_cfg = bmac_rx_on(dev, 0, 1); + XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg)); + } else { + for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; + for (i=0; i<64; i++) bp->hash_use_count[i] = 0; + if (num_addrs == 0) { + rx_cfg = bmac_rx_on(dev, 0, 0); + XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg)); + } else { + for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) + bmac_addhash(bp, dmi->dmi_addr); + bmac_update_hash_table_mask(dev, bp); + rx_cfg = bmac_rx_on(dev, 1, 0); + XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg)); + } + } +/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */ + } +#endif + +/* The version of set_multicast below was lifted from sunhme.c */ + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + + static void bmac_set_multicast(struct device *dev) + { + struct dev_mc_list *dmi = dev->mc_list; + char *addrs; + int i, j, bit, byte; + unsigned short rx_cfg; + u32 crc, poly = CRC_POLYNOMIAL_LE; + + /* Let the transmits drain. */ +/* while(dev->tbusy) schedule(); */ + + /* Lock out others. */ +/* set_bit(0, (void *) &dev->tbusy); */ + + if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + bmwrite(dev, BHASH0, 0xffff); + bmwrite(dev, BHASH1, 0xffff); + bmwrite(dev, BHASH2, 0xffff); + bmwrite(dev, BHASH3, 0xffff); + } else if(dev->flags & IFF_PROMISC) { + rx_cfg = bmread(dev, RXCFG); + rx_cfg |= RxPromiscEnable; + bmwrite(dev, RXCFG, rx_cfg); + } else { + u16 hash_table[4]; + + for(i = 0; i < 4; i++) hash_table[i] = 0; + + for(i = 0; i < dev->mc_count; i++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + + if(!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + for(byte = 0; byte < 6; byte++) { + for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + if(test) + crc = crc ^ poly; + } + } + crc >>= 26; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + bmwrite(dev, BHASH0, hash_table[0]); + bmwrite(dev, BHASH1, hash_table[1]); + bmwrite(dev, BHASH2, hash_table[2]); + bmwrite(dev, BHASH3, hash_table[3]); + } + + /* Let us get going again. */ +/* dev->tbusy = 0; */ + } + + + static int miscintcount = 0; + + static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) + { + struct device *dev = (struct device *) dev_id; + struct bmac_data *bp = (struct bmac_data *)dev->priv; + unsigned int status = bmread(dev, STATUS); + if (miscintcount++ < 10) { + XXDEBUG(("bmac_misc_intr\n")); + } +/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ +/* bmac_txdma_intr_inner(irq, dev_id, regs); */ +/* if (status & FrameReceived) bp->stats.rx_dropped++; */ + if (status & RxErrorMask) bp->stats.rx_errors++; + if (status & RxCRCCntExp) bp->stats.rx_crc_errors++; + if (status & RxLenCntExp) bp->stats.rx_length_errors++; + if (status & RxOverFlow) bp->stats.rx_over_errors++; + if (status & RxAlignCntExp) bp->stats.rx_frame_errors++; + +/* if (status & FrameSent) bp->stats.tx_dropped++; */ + if (status & TxErrorMask) bp->stats.tx_errors++; + if (status & TxUnderrun) bp->stats.tx_fifo_errors++; + if (status & TxNormalCollExp) bp->stats.collisions++; + } + +/* + * Procedure for reading EEPROM + */ +#define SROMAddressLength 5 +#define DataInOn 0x0008 +#define DataInOff 0x0000 +#define Clk 0x0002 +#define ChipSelect 0x0001 +#define SDIShiftCount 3 +#define SD0ShiftCount 2 +#define DelayValue 1000 /* number of microseconds */ +#define SROMStartOffset 10 /* this is in words */ +#define SROMReadCount 3 /* number of words to read from SROM */ +#define SROMAddressBits 6 +#define EnetAddressOffset 20 + + static unsigned char + bmac_clock_out_bit(struct device *dev) + { + unsigned short data; + unsigned short val; + + bmwrite(dev, SROMCSR, ChipSelect | Clk); + udelay(DelayValue); + + data = bmread(dev, SROMCSR); + udelay(DelayValue); + val = (data >> SD0ShiftCount) & 1; + + bmwrite(dev, SROMCSR, ChipSelect); + udelay(DelayValue); + + return val; + } + + static void + bmac_clock_in_bit(struct device *dev, unsigned int val) + { + unsigned short data; + + if (val != 0 && val != 1) return; + + data = (val << SDIShiftCount); + bmwrite(dev, SROMCSR, data | ChipSelect ); + udelay(DelayValue); + + bmwrite(dev, SROMCSR, data | ChipSelect | Clk ); + udelay(DelayValue); + + bmwrite(dev, SROMCSR, data | ChipSelect); + udelay(DelayValue); + } + + static void + reset_and_select_srom(struct device *dev) + { + /* first reset */ + bmwrite(dev, SROMCSR, 0); + udelay(DelayValue); + + /* send it the read command (110) */ + bmac_clock_in_bit(dev, 1); + bmac_clock_in_bit(dev, 1); + bmac_clock_in_bit(dev, 0); + } + + static unsigned short + read_srom(struct device *dev, unsigned int addr, unsigned int addr_len) + { + unsigned short data, val; + int i; + + /* send out the address we want to read from */ + for (i = 0; i < addr_len; i++) { + val = addr >> (addr_len-i-1); + bmac_clock_in_bit(dev, val & 1); + } + + /* Now read in the 16-bit data */ + data = 0; + for (i = 0; i < 16; i++) { + val = bmac_clock_out_bit(dev); + data <<= 1; + data |= val; + } + bmwrite(dev, SROMCSR, 0); + + return data; + } + +/* + * It looks like Cogent and SMC use different methods for calculating + * checksums. What a pain.. + */ + + static int + bmac_verify_checksum(struct device *dev) + { + unsigned short data, storedCS; + + reset_and_select_srom(dev); + data = read_srom(dev, 3, SROMAddressBits); + storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00); + + return 0; + } + + + static void + bmac_get_station_address(struct device *dev, unsigned char *ea) + { + int i; + unsigned short data; + + for (i = 0; i < 6; i++) + { + reset_and_select_srom(dev); + data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits); + ea[2*i] = bitrev(data & 0x0ff); + ea[2*i+1] = bitrev((data >> 8) & 0x0ff); + } + } + + static int bmac_reset_and_enable(struct device *dev, int enable) + { + struct bmac_data *bp = dev->priv; + unsigned long flags; + + 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; +/* { */ +/* unsigned char random_packet[100]; */ +/* unsigned int i; */ +/* struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */ +/* unsigned char *data = skb_put(skb, sizeof(random_packet)); */ +/* XXDEBUG(("transmitting random packet\n")); */ +/* for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */ +/* bmac_transmit_packet(skb, dev); */ +/* XXDEBUG(("done transmitting random packet\n")); */ +/* } */ + } + restore_flags(flags); + return 1; + } + + int + bmac_probe(struct device *dev) + { + int j, rev; + struct bmac_data *bp; + struct device_node *bmacs; + unsigned char *addr; + + bmacs = find_devices("bmac"); + if (bmacs == NULL) return ENODEV; + + bmac_devs = dev; /* KLUDGE!! */ + + if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) { + printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n", + bmacs->full_name); + return EINVAL; + } + + if (dev == NULL) { + dev = init_etherdev(NULL, PRIV_BYTES); + bmac_devs = dev; /*KLUDGE!!*/ + } else { + /* XXX this doesn't look right (but it's never used :-) */ + dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL); + if (dev->priv == 0) return -ENOMEM; + } + + dev->base_addr = bmacs->addrs[0].address; + dev->irq = bmacs->intrs[0].line; + + bmwrite(dev, INTDISABLE, DisableAll); + + if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) { + printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); + return -EAGAIN; + } + if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", + dev)) { + printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line); + return -EAGAIN; + } + if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", + dev)) { + printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line); + return -EAGAIN; + } + + addr = get_property(bmacs, "mac-address", NULL); + if (addr == NULL) { + addr = get_property(bmacs, "local-mac-address", NULL); + if (addr == NULL) { + printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n", + dev->base_addr); + return -EAGAIN; + } + } + + printk(KERN_INFO "%s: BMAC at", dev->name); + rev = addr[0] == 0 && addr[1] == 0xA0; + for (j = 0; j < 6; ++j) { + dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; + printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); + } + XXDEBUG((", base_addr=%#0lx", dev->base_addr)); + printk("\n"); + + dev->open = bmac_open; + dev->stop = bmac_close; + dev->hard_start_xmit = bmac_output; + dev->get_stats = bmac_stats; + dev->set_multicast_list = bmac_set_multicast; + dev->set_mac_address = bmac_set_address; + + bmac_get_station_address(dev, addr); + if (bmac_verify_checksum(dev) != 0) return EINVAL; + + ether_setup(dev); + + bp = (struct bmac_data *) dev->priv; + memset(bp, 0, sizeof(struct bmac_data)); + bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address; + bp->tx_dma_intr = bmacs->intrs[1].line; + bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address; + bp->rx_dma_intr = bmacs->intrs[2].line; + + bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1); + bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1; + + bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); + skb_queue_head_init(bp->queue); + + memset(&bp->stats, 0, sizeof(bp->stats)); + memset((char *) bp->tx_cmds, 0, + (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); +/* init_timer(&bp->tx_timeout); */ +/* bp->timeout_active = 0; */ + + if (!bmac_reset_and_enable(dev, 0)) return EINVAL; + +#ifdef CONFIG_PROC_FS + proc_net_register(&(struct proc_dir_entry) { + PROC_NET_BMAC, 4, "bmac", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + bmac_proc_info + }); +#endif + + return 0; + } + + static int bmac_open(struct device *dev) + { +/* XXDEBUG(("bmac: enter open\n")); */ + /* reset the chip */ + bmac_reset_and_enable(dev, 1); + + dev->flags |= IFF_UP | IFF_RUNNING; + + return 0; + } + + static int bmac_close(struct device *dev) + { + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *rd = bp->rx_dma; + volatile struct dbdma_regs *td = bp->tx_dma; + unsigned short config; + int i; + + dev->flags &= ~(IFF_UP | IFF_RUNNING); + + /* disable rx and tx */ + config = bmread(dev, RXCFG); + bmwrite(dev, RXCFG, (config & ~RxMACEnable)); + + config = bmread(dev, TXCFG); + bmwrite(dev, TXCFG, (config & ~TxMACEnable)); + + bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */ + + /* disable rx and tx dma */ + st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ + st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ + + /* free some skb's */ + XXDEBUG(("bmac: free rx bufs\n")); + for (i=0; irx_bufs[i] != NULL) { + dev_kfree_skb(bp->rx_bufs[i]); + bp->rx_bufs[i] = NULL; + } + } + bp->rx_allocated = 0; + XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */ + if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]); + XXDEBUG(("bmac: free tx bufs\n")); + for (i = 0; itx_bufs[i] != NULL) { + dev_kfree_skb(bp->tx_bufs[i]); + bp->tx_bufs[i] = NULL; + } + } + bp->tx_allocated = 0; + bp->reset_and_enabled = 0; + XXDEBUG(("bmac: all bufs freed\n")); + + return 0; + } + + static void + bmac_start(struct device *dev) + { + struct bmac_data *bp = dev->priv; + int i; + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); cli(); + while (1) { + i = bp->tx_fill + 1; + if (i >= N_TX_RING) i = 0; + if (i == bp->tx_empty) break; + skb = skb_dequeue(bp->queue); + if (skb == NULL) break; + bmac_transmit_packet(skb, dev); + } + restore_flags(flags); + } + + static int + bmac_output(struct sk_buff *skb, struct device *dev) + { + struct bmac_data *bp = dev->priv; + skb_queue_tail(bp->queue, skb); + bmac_start(dev); + return 0; + } + + static void bmac_tx_timeout(unsigned long data) + { + struct device *dev = (struct device *) data; + struct bmac_data *bp = (struct bmac_data *) dev->priv; + volatile struct dbdma_regs *td = bp->tx_dma; + volatile struct dbdma_regs *rd = bp->rx_dma; + volatile struct dbdma_cmd *cp; + unsigned long flags; + unsigned short config, oldConfig; + int i; + + XXDEBUG(("bmac: tx_timeout called\n")); + save_flags(flags); cli(); + bp->timeout_active = 0; + + /* update various counters */ +/* bmac_handle_misc_intrs(bp, 0); */ + + cp = &bp->tx_cmds[bp->tx_empty]; +/* XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */ +/* ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, */ +/* mb->pr, mb->xmtfs, mb->fifofc)); */ + + /* turn off both tx and rx and reset the chip */ + config = bmread(dev, RXCFG); + bmwrite(dev, RXCFG, (config & ~RxMACEnable)); + config = bmread(dev, TXCFG); + bmwrite(dev, TXCFG, (config & ~TxMACEnable)); + out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); + printk(KERN_ERR "bmac: transmit timeout - resetting\n"); + bmac_reset_chip(dev); + + /* restart rx dma */ + cp = bus_to_virt(ld_le32(&rd->cmdptr)); + out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); + out_le16(&cp->xfer_status, 0); + out_le32(&rd->cmdptr, virt_to_bus(cp)); + out_le32(&rd->control, DBDMA_SET(RUN|WAKE)); + + /* fix up the transmit side */ + XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n", + bp->tx_empty, bp->tx_fill, bp->tx_fullup)); + i = bp->tx_empty; + ++bp->stats.tx_errors; + if (i != bp->tx_fill) { + dev_kfree_skb(bp->tx_bufs[i]); + bp->tx_bufs[i] = NULL; + if (++i >= N_TX_RING) i = 0; + bp->tx_empty = i; + } + bp->tx_fullup = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n")); + if (i != bp->tx_fill) { + cp = &bp->tx_cmds[i]; + out_le16(&cp->xfer_status, 0); + out_le16(&cp->command, OUTPUT_LAST); + out_le32(&td->cmdptr, virt_to_bus(cp)); + out_le32(&td->control, DBDMA_SET(RUN)); +/* bmac_set_timeout(dev); */ + XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i)); + } + + /* turn it back on */ + oldConfig = bmread(dev, RXCFG); + bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); + oldConfig = bmread(dev, TXCFG); + bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); + + restore_flags(flags); + } + +#if 0 + static void dump_dbdma(volatile struct dbdma_cmd *cp,int count) + { + int i,*ip; + + for (i=0;i< count;i++) + { + ip = (int*)(cp+i); + + printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n", + ld_le32(ip+0), + ld_le32(ip+1), + ld_le32(ip+2), + ld_le32(ip+3)); + } + + } +#endif + + static int + bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy) + { + int len = 0; + off_t pos = 0; + off_t begin = 0; + int i; + + if (bmac_devs == NULL) return (-ENOSYS); + + len += sprintf(buffer, "BMAC counters & registers\n"); + + for (i = 0; i offset+length) break; + } + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) len = length; + + return len; + } diff -u --recursive --new-file v2.1.111/linux/drivers/net/bmac.h linux/drivers/net/bmac.h --- v2.1.111/linux/drivers/net/bmac.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/bmac.h Sun Jul 26 23:35:56 1998 @@ -0,0 +1,164 @@ +/* + * mace.h - definitions for the registers in the "Big Mac" + * Ethernet controller found in PowerMac G3 models. + * + * Copyright (C) 1998 Randy Gobbel. + * + * 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. + */ + +/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal" + * (HME) controller. See sunhme.h + */ + + +/* register offsets */ + +/* global status and control */ +#define XIFC 0x000 /* low-level interface control */ +# define TxOutputEnable 0x0001 /* output driver enable */ +# define XIFLoopback 0x0002 /* Loopback-mode XIF enable */ +# define MIILoopback 0x0004 /* Loopback-mode MII enable */ +# define MIILoopbackBits 0x0006 +# define MIIBuffDisable 0x0008 /* MII receive buffer disable */ +# define SQETestEnable 0x0010 /* SQE test enable */ +# define SQETimeWindow 0x03e0 /* SQE time window */ +# define XIFLanceMode 0x0010 /* Lance mode enable */ +# define XIFLanceIPG0 0x03e0 /* Lance mode IPG0 */ +#define TXFIFOCSR 0x100 /* transmit FIFO control */ +# define TxFIFOEnable 0x0001 +#define TXTH 0x110 /* transmit threshold */ +# define TxThreshold 0x0004 +#define RXFIFOCSR 0x120 /* receive FIFO control */ +# define RxFIFOEnable 0x0001 +#define MEMADD 0x130 /* memory address, unknown function */ +#define MEMDATAHI 0x140 /* memory data high, presently unused in driver */ +#define MEMDATALO 0x150 /* memory data low, presently unused in driver */ +#define XCVRIF 0x160 /* transceiver interface control */ +# define COLActiveLow 0x0002 +# define SerialMode 0x0004 +# define ClkBit 0x0008 +# define LinkStatus 0x0100 +#define CHIPID 0x170 /* chip ID */ +#define MIFCSR 0x180 /* ??? */ +#define SROMCSR 0x190 /* SROM control */ +# define ChipSelect 0x0001 +# define Clk 0x0002 +#define TXPNTR 0x1a0 /* transmit pointer */ +#define RXPNTR 0x1b0 /* receive pointer */ +#define STATUS 0x200 /* status--reading this clears it */ +#define INTDISABLE 0x210 /* interrupt enable/disable control */ +/* bits below are the same in both STATUS and INTDISABLE registers */ +# define FrameReceived 0x00000001 /* Received a frame */ +# define RxFrameCntExp 0x00000002 /* Receive frame counter expired */ +# define RxAlignCntExp 0x00000004 /* Align-error counter expired */ +# define RxCRCCntExp 0x00000008 /* CRC-error counter expired */ +# define RxLenCntExp 0x00000010 /* Length-error counter expired */ +# define RxOverFlow 0x00000020 /* Receive FIFO overflow */ +# define RxCodeViolation 0x00000040 /* Code-violation counter expired */ +# define SQETestError 0x00000080 /* Test error in XIF for SQE */ +# define FrameSent 0x00000100 /* Transmitted a frame */ +# define TxUnderrun 0x00000200 /* Transmit FIFO underrun */ +# define TxMaxSizeError 0x00000400 /* Max-packet size error */ +# define TxNormalCollExp 0x00000800 /* Normal-collision counter expired */ +# define TxExcessCollExp 0x00001000 /* Excess-collision counter expired */ +# define TxLateCollExp 0x00002000 /* Late-collision counter expired */ +# define TxNetworkCollExp 0x00004000 /* First-collision counter expired */ +# define TxDeferTimerExp 0x00008000 /* Defer-timer expired */ +# define RxFIFOToHost 0x00010000 /* Data moved from FIFO to host */ +# define RxNoDescriptors 0x00020000 /* No more receive descriptors */ +# define RxDMAError 0x00040000 /* Error during receive DMA */ +# define RxDMALateErr 0x00080000 /* Receive DMA, data late */ +# define RxParityErr 0x00100000 /* Parity error during receive DMA */ +# define RxTagError 0x00200000 /* Tag error during receive DMA */ +# define TxEOPError 0x00400000 /* Tx descriptor did not have EOP set */ +# define MIFIntrEvent 0x00800000 /* MIF is signaling an interrupt */ +# define TxHostToFIFO 0x01000000 /* Data moved from host to FIFO */ +# define TxFIFOAllSent 0x02000000 /* Transmitted all packets in FIFO */ +# define TxDMAError 0x04000000 /* Error during transmit DMA */ +# define TxDMALateError 0x08000000 /* Late error during transmit DMA */ +# define TxParityError 0x10000000 /* Parity error during transmit DMA */ +# define TxTagError 0x20000000 /* Tag error during transmit DMA */ +# define PIOError 0x40000000 /* PIO access got an error */ +# define PIOParityError 0x80000000 /* PIO access got a parity error */ +# define DisableAll 0xffffffff +# define EnableAll 0x00000000 +/* # define NormalIntEvents ~(FrameReceived | FrameSent | TxUnderrun) */ +# define EnableNormal ~(FrameReceived | FrameSent) +# define EnableErrors (FrameReceived | FrameSent) +# define RxErrorMask (RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \ + RxLenCntExp | RxOverFlow | RxCodeViolation) +# define TxErrorMask (TxUnderrun | TxMaxSizeError | TxExcessCollExp | \ + TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp) + +/* transmit control */ +#define TXRST 0x420 /* transmit reset */ +# define TxResetBit 0x0001 +#define TXCFG 0x430 /* transmit configuration control*/ +# define TxMACEnable 0x0001 /* output driver enable */ +# define TxSlowMode 0x0020 /* enable slow mode */ +# define TxIgnoreColl 0x0040 /* ignore transmit collisions */ +# define TxNoFCS 0x0080 /* do not emit FCS */ +# define TxNoBackoff 0x0100 /* no backoff in case of collisions */ +# define TxFullDuplex 0x0200 /* enable full-duplex */ +# define TxNeverGiveUp 0x0400 /* don't give up on transmits */ +#define IPG1 0x440 /* Inter-packet gap 1 */ +#define IPG2 0x450 /* Inter-packet gap 2 */ +#define ALIMIT 0x460 /* Transmit attempt limit */ +#define SLOT 0x470 /* Transmit slot time */ +#define PALEN 0x480 /* Size of transmit preamble */ +#define PAPAT 0x490 /* Pattern for transmit preamble */ +#define TXSFD 0x4a0 /* Transmit frame delimiter */ +#define JAM 0x4b0 /* Jam size */ +#define TXMAX 0x4c0 /* Transmit max pkt size */ +#define TXMIN 0x4d0 /* Transmit min pkt size */ +#define PAREG 0x4e0 /* Count of transmit peak attempts */ +#define DCNT 0x4f0 /* Transmit defer timer */ +#define NCCNT 0x500 /* Transmit normal-collision counter */ +#define NTCNT 0x510 /* Transmit first-collision counter */ +#define EXCNT 0x520 /* Transmit excess-collision counter */ +#define LTCNT 0x530 /* Transmit late-collision counter */ +#define RSEED 0x540 /* Transmit random number seed */ +#define TXSM 0x550 /* Transmit state machine */ + +/* receive control */ +#define RXRST 0x620 /* receive reset */ +# define RxResetValue 0x0000 +#define RXCFG 0x630 /* receive configuration control */ +# define RxMACEnable 0x0001 /* receiver overall enable */ +# define RxCFGReserved 0x0004 +# define RxPadStripEnab 0x0020 /* enable pad byte stripping */ +# define RxPromiscEnable 0x0040 /* turn on promiscuous mode */ +# define RxNoErrCheck 0x0080 /* disable receive error checking */ +# define RxCRCNoStrip 0x0100 /* disable auto-CRC-stripping */ +# define RxRejectOwnPackets 0x0200 /* don't receive our own packets */ +# define RxGrpPromisck 0x0400 /* enable group promiscuous mode */ +# define RxHashFilterEnable 0x0800 /* enable hash filter */ +# define RxAddrFilterEnable 0x1000 /* enable address filter */ +#define RXMAX 0x640 /* Max receive packet size */ +#define RXMIN 0x650 /* Min receive packet size */ +#define MADD2 0x660 /* our enet address, high part */ +#define MADD1 0x670 /* our enet address, middle part */ +#define MADD0 0x680 /* our enet address, low part */ +#define FRCNT 0x690 /* receive frame counter */ +#define LECNT 0x6a0 /* Receive excess length error counter */ +#define AECNT 0x6b0 /* Receive misaligned error counter */ +#define FECNT 0x6c0 /* Receive CRC error counter */ +#define RXSM 0x6d0 /* Receive state machine */ +#define RXCV 0x6e0 /* Receive code violation */ + +#define BHASH3 0x700 /* multicast hash register */ +#define BHASH2 0x710 /* multicast hash register */ +#define BHASH1 0x720 /* multicast hash register */ +#define BHASH0 0x730 /* multicast hash register */ + +#define AFR2 0x740 /* address filtering setup? */ +#define AFR1 0x750 /* address filtering setup? */ +#define AFR0 0x760 /* address filtering setup? */ +#define AFCR 0x770 /* address filter compare register? */ +# define EnableAllCompares 0x0fff + +/* bits in XIFC */ diff -u --recursive --new-file v2.1.111/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.1.111/linux/drivers/net/daynaport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/daynaport.c Sun Jul 26 23:35:56 1998 @@ -0,0 +1,603 @@ +/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */ +/* + Derived from code: + + Written 1993-94 by Donald Becker. + + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + TODO: + + The block output routines may be wrong for non Dayna + cards + + Reading MAC addresses +*/ + +static const char *version = + "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "8390.h" + +int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom); + +static int ns8390_open(struct device *dev); +static void ns8390_no_reset(struct device *dev); +static int ns8390_close_card(struct device *dev); + +static void interlan_reset(struct device *dev); + +static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void dayna_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void dayna_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); + +static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void sane_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void sane_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); + + +#define WD_START_PG 0x00 /* First page of TX buffer */ +#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ +#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ + + +#define DAYNA_MAC_BASE 0xf0007 +#define DAYNA_8390_BASE 0x80000 /* 3 */ +#define DAYNA_8390_MEM 0x00000 +#define DAYNA_MEMSIZE 0x04000 /* First word of each long ! */ + +#define APPLE_8390_BASE 0xE0000 +#define APPLE_8390_MEM 0xD0000 +#define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */ + +#define KINETICS_8390_BASE 0x80003 +#define KINETICS_8390_MEM 0x00000 +#define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */ + +static int test_8390(volatile char *ptr, int scale) +{ + int regd; + int v; + + if(nubus_hwreg_present(&ptr[0x00])==0) + return -EIO; + if(nubus_hwreg_present(&ptr[0x0D<DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100) + return NS8390_APPLE; + + /* Dayna ex Kinetics board */ + if(nb->DrHW==0x0103) + return NS8390_DAYNA; + + /* Asante board */ + if(nb->DrHW==0x0104) + return NS8390_ASANTE; + if(nb->DrHW==0x0100) + return NS8390_INTERLAN; + if(nb->DrHW==0x0106) + return NS8390_KINETICS; + if(nb->DrSW==0x010C) + return NS8390_FARALLON; + return -1; +} + +/* + * Probe for 8390 cards. + * The ns8390_probe1() routine initializes the card and fills the + * station address field. On entry base_addr is set, irq is set + * (These come from the nubus probe code). dev->mem_start points + * at the memory ring, dev->mem_end gives the end of it. + */ + +int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match) +{ + struct device *dev; + volatile unsigned short *i; + volatile unsigned char *p; + int plen; + int id; + + if(match->category!=NUBUS_CAT_NETWORK || match->type!=1) + return -ENODEV; + /* Ok so it is an ethernet network device */ + if((id=ns8390_ident(match))==-1) + { + printk("Ethernet but type unknown %d\n",match->DrHW); + return -ENODEV; + } + dev = init_etherdev(0, 0); + if(dev==NULL) + return -ENOMEM; + + /* + * Dayna specific init + */ + if(id==NS8390_DAYNA) + { + dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE); + dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM); + dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ + + printk("daynaport: testing board: "); + + printk("memory - "); + + i=(void *)dev->mem_start; + memset((void *)i,0xAA, DAYNA_MEMSIZE); + while(i<(volatile unsigned short *)dev->mem_end) + { + if(*i!=0xAAAA) + goto membad; + *i=0x5555; + if(*i!=0x5555) + goto membad; + i+=2; /* Skip a word */ + } + + printk("controller - "); + + p=(void *)dev->base_addr; + plen=0; + + while(plen<0x3FF00) + { + if(test_8390(p,0)==0) + break; + if(test_8390(p,1)==0) + break; + if(test_8390(p,2)==0) + break; + if(test_8390(p,3)==0) + break; + plen++; + p++; + } + if(plen==0x3FF00) + goto membad; + printk("OK\n"); + dev->irq=slot; + if(ns8390_probe1(dev, 0, "dayna", id, -1)==0) + return 0; + } + /* Apple, Farallon, Asante */ + if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE) + { + dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); + dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); + dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ + dev->irq=slot; + printk("apple/clone: testing board: "); + + printk("memory - "); + + i=(void *)dev->mem_start; + memset((void *)i,0xAA, DAYNA_MEMSIZE); + while(i<(volatile unsigned short *)dev->mem_end) + { + if(*i!=0xAAAA) + goto membad; + *i=0x5555; + if(*i!=0x5555) + goto membad; + i+=2; /* Skip a word */ + } + printk("OK\n"); + + if(id==NS8390_FARALLON) + { + if(ns8390_probe1(dev, 1, "farallon", id, -1)==0) + return 0; + } + else + { + if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0) + return 0; + } + } + /* Interlan */ + if(id==NS8390_INTERLAN) + { + /* As apple and asante */ + dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); + dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); + dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ + dev->irq=slot; + if(ns8390_probe1(dev, 1, "interlan", id, -1)==0) + return 0; + } + /* Kinetics */ + if(id==NS8390_KINETICS) + { + dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE); + dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM); + dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */ + dev->irq=slot; + if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0) + return 0; + } + kfree(dev); + return -ENODEV; +membad: + printk("failed.\n"); + kfree(dev); + return -ENODEV; +} + +int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff) +{ + static unsigned version_printed = 0; + + static unsigned char fwrd4_offsets[16]={ + 0, 4, 8, 12, + 16, 20, 24, 28, + 32, 36, 40, 44, + 48, 52, 56, 60 + }; + static unsigned char back4_offsets[16]={ + 60, 56, 52, 48, + 44, 40, 36, 32, + 28, 24, 20, 16, + 12, 8, 4, 0 + }; + + unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff; + + if (ei_debug && version_printed++ == 0) + printk(version); + + /* Snarf the interrupt now. There's no point in waiting since we cannot + share a slot! and the board will usually be enabled. */ + if (nubus_request_irq(dev->irq, dev, ei_interrupt)) + { + printk (" unable to get nubus IRQ %d.\n", dev->irq); + return EAGAIN; + } + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) + { + printk (" unable to get memory for dev->priv.\n"); + nubus_free_irq(dev->irq); + return -ENOMEM; + } + + /* OK, we are certain this is going to work. Setup the device. */ + + ei_status.name = model_name; + ei_status.word16 = word16; + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + + dev->rmem_start = dev->mem_start + TX_PAGES*256; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_end = dev->mem_end; + + if(promoff==-1) /* Use nubus resources ? */ + { + if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr)) + { + printk("mac_ns8390: MAC address not in resources!\n"); + return -ENODEV; + } + } + else /* Pull it off the card */ + { + int i=0; + int x=1; + /* These should go in the end I hope */ + if(type==NS8390_DAYNA) + x=2; + if(type==NS8390_INTERLAN) + x=4; + while(i<6) + { + dev->dev_addr[i]=*prom; + prom+=x; + if(i) + printk(":"); + printk("%02X",dev->dev_addr[i++]); + } + } + + printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", + model_name, dev->irq, dev->mem_start, dev->mem_end-1); + + switch(type) + { + case NS8390_DAYNA: /* Dayna card */ + /* 16 bit, 4 word offsets */ + ei_status.reset_8390 = &ns8390_no_reset; + ei_status.block_input = &dayna_block_input; + ei_status.block_output = &dayna_block_output; + ei_status.get_8390_hdr = &dayna_get_8390_hdr; + ei_status.reg_offset = fwrd4_offsets; + break; + case NS8390_APPLE: /* Apple/Asante/Farallon */ + case NS8390_FARALLON: + case NS8390_ASANTE: + /* 16 bit card, register map is reversed */ + ei_status.reset_8390 = &ns8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; + case NS8390_INTERLAN: /* Interlan */ + /* 16 bit card, map is forward */ + ei_status.reset_8390 = &interlan_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; + case NS8390_KINETICS: /* Kinetics */ + /* 8bit card, map is forward */ + ei_status.reset_8390 = &ns8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; + default: + panic("Detected a card I can't drive - whoops\n"); + } + dev->open = &ns8390_open; + dev->stop = &ns8390_close_card; + + NS8390_init(dev, 0); + + return 0; +} + +static int ns8390_open(struct device *dev) +{ + ei_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static void ns8390_no_reset(struct device *dev) +{ + if (ei_debug > 1) + printk("Need to reset the NS8390 t=%lu...", jiffies); + ei_status.txing = 0; + if (ei_debug > 1) printk("reset not supported\n"); + return; +} + +static int ns8390_close_card(struct device *dev) +{ + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + ei_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +struct nubus_device_specifier nubus_8390={ + ns8390_probe, + NULL +}; + + +/* + * Interlan Specific Code Starts Here + */ + +static void interlan_reset(struct device *dev) +{ + unsigned char *target=nubus_slot_addr(dev->irq); + if (ei_debug > 1) + printk("Need to reset the NS8390 t=%lu...", jiffies); + ei_status.txing = 0; + /* This write resets the card */ + target[0xC0000]=0; + if (ei_debug > 1) printk("reset complete\n"); + return; +} + +/* + * Daynaport code (some is used by other drivers) + */ + + +/* Grab the 8390 specific header. Similar to the block_input routine, but + we don't need to be concerned with ring wrap as the header will be at + the start of a page, so we optimize accordingly. */ + + +/* Block input and output are easy on shared memory ethercards, and trivial + on the Daynaport card where there is no choice of how to do it. + The only complications are that the ring buffer wraps. +*/ + +static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count) +{ + volatile unsigned short *ptr; + unsigned short *target=to; + from<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+from); + while(count>=2) + { + *target++=*ptr++; /* Copy and */ + ptr++; /* Cruft and */ + count-=2; + } + /* + * Trailing byte ? + */ + if(count) + { + /* Big endian */ + unsigned short v=*ptr; + *((char *)target)=v>>8; + } +} + +static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count) +{ + volatile unsigned short *ptr; + const unsigned short *src=from; + to<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+to); + while(count>=2) + { + *ptr++=*src++; /* Copy and */ + ptr++; /* Cruft and */ + count-=2; + } + /* + * Trailing byte ? + */ + if(count) + { + /* Big endian */ + unsigned short v=*src; + *((char *)ptr)=v>>8; + } +} + +static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4); + /* Register endianism - fix here rather than 8390.c */ + hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + /* + * Note the offset maths is done in card memory space which + * is word per long onto our space. + */ + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count); + count -= semi_count; + dayna_cpu_memcpy(dev, skb->data + semi_count, + dev->rmem_start - dev->mem_start, count); + } + else + { + dayna_cpu_memcpy(dev, skb->data, xfer_base, count); + } +} + +static void dayna_block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + cpu_dayna_memcpy(dev, shmem, buf, count); +} + +/* + * Cards with full width memory + */ + + +static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4); + /* Register endianism - fix here rather than 8390.c */ + hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count); + count -= semi_count; + memcpy(skb->data + semi_count, + (char *)dev->rmem_start, count); + } + else + { + memcpy(skb->data, (char *)dev->mem_start+xfer_base, count); + } +} + +static void sane_block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + memcpy((char *)dev->mem_start+shmem, buf, count); +} + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" + * version-control: t + * tab-width: 4 + * kept-new-versions: 5 + * End: + */ diff -u --recursive --new-file v2.1.111/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.1.111/linux/drivers/net/eepro.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/eepro.c Sun Jul 26 23:35:56 1998 @@ -1106,6 +1106,8 @@ dev->tbusy = 0; } + lp->stats.tx_bytes += length; + if (net_debug > 5) printk("eepro: exiting hardware_send_packet routine.\n"); return; @@ -1164,6 +1166,7 @@ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; + lp->stats.rx_bytes += rcv_size; } else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ diff -u --recursive --new-file v2.1.111/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.111/linux/drivers/net/ibmtr.c Thu Jul 16 18:09:25 1998 +++ linux/drivers/net/ibmtr.c Sun Jul 26 23:35:56 1998 @@ -59,9 +59,10 @@ * Changes by Christopher Turcksin * + Now compiles ok as a module again. * - * Changes by Paul Norton (pnorton@cts.com) : + * Changes by Paul Norton (p.norton@computer.org) : * + moved the header manipulation code in tr_tx and tr_rx to * net/802/tr.c. (July 12 1997) + * + add retry and timeout on open if cable disconnected. (May 5 1998) * + lifted 2000 byte mtu limit. now depends on shared-RAM size. * May 25 1998) */ @@ -929,9 +930,12 @@ DPRINTK("No signal detected for Auto Speed Detection.\n"); else if (open_error_code==0x11) { - ti->open_status=FAILURE; - DPRINTK("Ring broken/disconnected.\n"); - wake_up(&ti->wait_for_reset); + if (ti->retry_count--) + DPRINTK("Ring broken/disconnected, retrying...\n"); + else { + DPRINTK("Ring broken/disconnected, open failed.\n"); + ti->open_status = FAILURE; + } } else DPRINTK("Unrecoverable error: error code = %04x.\n", open_error_code); diff -u --recursive --new-file v2.1.111/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h --- v2.1.111/linux/drivers/net/ibmtr.h Thu Jul 16 18:09:25 1998 +++ linux/drivers/net/ibmtr.h Sun Jul 26 23:35:56 1998 @@ -7,6 +7,7 @@ #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 @@ -215,6 +216,7 @@ struct timer_list tr_timer; unsigned char ring_speed; __u32 func_addr; + unsigned int retry_count; }; /* token ring adapter commands */ diff -u --recursive --new-file v2.1.111/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.1.111/linux/drivers/net/lance.c Tue Jun 9 11:57:29 1998 +++ linux/drivers/net/lance.c Sun Jul 26 23:35:56 1998 @@ -326,8 +326,7 @@ struct pci_dev *pdev = NULL; if (lance_debug > 1) printk("lance.c: PCI is present, checking for devices...\n"); - while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) { - unsigned char pci_bus, pci_device_fn; + while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) { unsigned int pci_ioaddr; unsigned short pci_command; diff -u --recursive --new-file v2.1.111/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.1.111/linux/drivers/net/mace.c Thu Apr 23 20:21:33 1998 +++ linux/drivers/net/mace.c Sun Jul 26 23:35:56 1998 @@ -573,6 +573,7 @@ if ((fs & XMTSV) == 0) { printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat); + return; } cp = mp->tx_cmds + NCMDS_TX * i; stat = ld_le16(&cp->xfer_status); @@ -765,7 +766,14 @@ if (frame_status & RS_FCSERR) ++mp->stats.rx_crc_errors; } else { - nb -= 8; + /* Mace feature AUTO_STRIP_RCV is on by default, dropping the + * FCS on frames with 802.3 headers. This means that Ethernet + * frames have 8 extra octets at the end, while 802.3 frames + * have only 4. We need to correctly account for this. */ + if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */ + nb -= 4; + else /* Ethernet header; mace includes FCS */ + nb -= 8; skb_put(skb, nb); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); diff -u --recursive --new-file v2.1.111/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.111/linux/drivers/net/myri_sbus.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/myri_sbus.c Sun Jul 26 23:35:56 1998 @@ -1044,27 +1044,11 @@ dev->hard_start_xmit = &myri_start_xmit; dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; - dev->irq = sdev->irqs[0].pri; + dev->irq = sdev->irqs[0]; dev->dma = 0; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); -#ifdef __sparc_v9__ - if(sparc_cpu_model == sun4u) { - struct devid_cookie dcookie; - - dcookie.real_dev_id = dev; - dcookie.imap = dcookie.iclr = 0; - dcookie.pil = -1; - dcookie.bus_cookie = sdev->my_bus; - if(request_irq(dev->irq, &myri_interrupt, - (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), - "MyriCOM Ethernet", &dcookie)) { - printk("MyriCOM: Cannot register interrupt handler.\n"); - return ENODEV; - } - } else -#endif if(request_irq(dev->irq, &myri_interrupt, SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); diff -u --recursive --new-file v2.1.111/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.111/linux/drivers/net/plip.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/net/plip.c Sun Jul 26 23:35:56 1998 @@ -574,6 +574,7 @@ /* Inform the upper layer for the arrival of a packet. */ rcv->skb->protocol=eth_type_trans(rcv->skb, dev); netif_rx(rcv->skb); + nl->enet_stats.rx_bytes += rcv->length.h; nl->enet_stats.rx_packets++; rcv->skb = NULL; if (net_debug > 2) @@ -741,6 +742,7 @@ &snd->nibble, snd->checksum)) return TIMEOUT; + nl->enet_stats.tx_bytes += snd->skb->len; dev_kfree_skb(snd->skb); nl->enet_stats.tx_packets++; snd->state = PLIP_PK_DONE; diff -u --recursive --new-file v2.1.111/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.1.111/linux/drivers/net/seeq8005.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/net/seeq8005.c Sun Jul 26 23:35:56 1998 @@ -372,6 +372,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev) { int ioaddr = dev->base_addr; + struct net_local *lp = (struct net_local *)dev->priv; if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. @@ -397,6 +398,7 @@ hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; + lp->stats.tx_bytes += length; } dev_kfree_skb (skb); @@ -547,6 +549,7 @@ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN)); diff -u --recursive --new-file v2.1.111/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.1.111/linux/drivers/net/sk_g16.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/net/sk_g16.c Sun Jul 26 23:35:56 1998 @@ -1250,6 +1250,8 @@ */ dev->tbusy = 0; } + + p->stats.tx_bytes += skb->len; } dev_kfree_skb(skb); return 0; @@ -1585,6 +1587,7 @@ writeb(RX_OWN, rmdp->u.s.status); p->stats.rx_packets++; + p->stats.rx_bytes += len; p->rmdnum++; diff -u --recursive --new-file v2.1.111/linux/drivers/net/sonic.c linux/drivers/net/sonic.c --- v2.1.111/linux/drivers/net/sonic.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/sonic.c Sun Jul 26 23:35:56 1998 @@ -430,6 +430,7 @@ lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS; lp->cur_tx++; + lp->stats.tx_bytes += length; if (sonic_debug > 2) printk("sonic_send_packet: issueing Tx command\n"); @@ -610,6 +611,7 @@ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* pass the packet to upper layers */ lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { /* This should only happen, if we enable accepting broken packets. */ diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.111/linux/drivers/net/sunhme.c Fri May 8 23:14:48 1998 +++ linux/drivers/net/sunhme.c Sun Jul 26 23:35:56 1998 @@ -2098,6 +2098,7 @@ } #endif +#ifndef __sparc_v9__ static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *) dev_id; @@ -2141,6 +2142,7 @@ dev->interrupt = 0; HMD(("done\n")); } +#endif static int happy_meal_open(struct device *dev) { @@ -2148,6 +2150,7 @@ int res; HMD(("happy_meal_open: ")); +#ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) { if(request_irq(dev->irq, &sun4c_happy_meal_interrupt, SA_SHIRQ, "HAPPY MEAL", (void *) dev)) { @@ -2155,47 +2158,26 @@ printk("happy meal: Can't order irq %d to go.\n", dev->irq); return -EAGAIN; } - } -#ifdef __sparc_v9__ - else if(sparc_cpu_model == sun4u) { - struct devid_cookie dcookie; - + } else +#else #ifdef CONFIG_PCI - if(hp->happy_flags & HFLAG_PCI) { - if(request_irq(dev->irq, &pci_happy_meal_interrupt, - SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) { - HMD(("EAGAIN\n")); - printk("happy_meal(PCI: Can't order irq %d to go.\n", - dev->irq); - return -EAGAIN; - } - goto v9_done; - } -#endif - dcookie.real_dev_id = dev; - dcookie.imap = dcookie.iclr = 0; - dcookie.pil = -1; - dcookie.bus_cookie = hp->happy_sbus_dev->my_bus; - if(request_irq(dev->irq, &happy_meal_interrupt, - (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), - "HAPPY MEAL", &dcookie)) { - HMD(("EAGAIN\n")); - printk("happy_meal(SBUS): Can't order irq %d to go.\n", - dev->irq); + if(hp->happy_flags & HFLAG_PCI) { + if(request_irq(dev->irq, &pci_happy_meal_interrupt, + SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) { + HMD(("EAGAIN\n")); + printk("happy_meal(PCI: Can't order irq %s to go.\n", + __irq_itoa(dev->irq)); return -EAGAIN; } -#ifdef CONFIG_PCI - v9_done: + } else #endif - } #endif - else { - if(request_irq(dev->irq, &happy_meal_interrupt, - SA_SHIRQ, "HAPPY MEAL", (void *) dev)) { - HMD(("EAGAIN\n")); - printk("happy meal: Can't order irq %d to go.\n", dev->irq); - return -EAGAIN; - } + if(request_irq(dev->irq, &happy_meal_interrupt, + SA_SHIRQ, "HAPPY MEAL", (void *)dev)) { + HMD(("EAGAIN\n")); + printk("happy_meal(SBUS): Can't order irq %s to go.\n", + __irq_itoa(dev->irq)); + return -EAGAIN; } HMD(("Init happy timer\n")); init_timer(&hp->happy_timer); @@ -2594,7 +2576,7 @@ dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; - dev->irq = sdev->irqs[0].pri; + dev->irq = sdev->irqs[0]; dev->dma = 0; ether_setup(dev); #ifdef MODULE diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.111/linux/drivers/net/sunlance.c Fri May 8 23:14:48 1998 +++ linux/drivers/net/sunlance.c Sun Jul 26 23:35:56 1998 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.75 1998/04/24 12:29:50 davem Exp $ +/* $Id: sunlance.c,v 1.79 1998/06/04 09:54:58 jj Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -672,39 +672,11 @@ last_dev = dev; -#ifdef __sparc_v9__ - if (sparc_cpu_model == sun4u) { - struct devid_cookie dcookie; - - dcookie.real_dev_id = dev; - dcookie.imap = dcookie.iclr = 0; - dcookie.pil = -1; - dcookie.bus_cookie = lp->sbus; - if(request_irq(dev->irq, &lance_interrupt, - (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), - lancestr, &dcookie)) { - printk ("Lance: Can't get irq %d\n", dev->irq); - return -EAGAIN; - } - } -#else - if (sparc_cpu_model == sun4d) { - struct devid_cookie dcookie; - - dcookie.real_dev_id = dev; - dcookie.bus_cookie = (void *)dev->base_addr; - if(request_irq(dev->irq, &lance_interrupt, - (SA_SHIRQ | SA_DCOOKIE), - lancestr, &dcookie)) { - printk ("Lance: Can't get irq %d\n", dev->irq); - return -EAGAIN; - } - } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, + if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) { - printk ("Lance: Can't get irq %d\n", dev->irq); + printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq)); return -EAGAIN; } -#endif /* Stop the Lance */ ll->rap = LE_CSR0; @@ -1124,7 +1096,7 @@ dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; - dev->irq = (unsigned char) sdev->irqs [0].pri; + dev->irq = sdev->irqs[0]; dev->dma = 0; ether_setup (dev); @@ -1166,7 +1138,7 @@ if (idprom->id_machtype == (SM_SUN4|SM_4_330)) { memset (&sdev, 0, sizeof(sdev)); sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR; - sdev.irqs[0].pri = 6; + sdev.irqs[0] = 6; return sparc_lance_init(dev, &sdev, 0, 0); } return ENODEV; diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.111/linux/drivers/net/sunqe.c Sun Jun 7 11:16:32 1998 +++ linux/drivers/net/sunqe.c Sun Jul 26 23:35:56 1998 @@ -1103,7 +1103,7 @@ qe_devs[i]->hard_start_xmit = qe_start_xmit; qe_devs[i]->get_stats = qe_get_stats; qe_devs[i]->set_multicast_list = qe_set_multicast; - qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri; + qe_devs[i]->irq = sdev->irqs[0]; qe_devs[i]->dma = 0; ether_setup(qe_devs[i]); } @@ -1114,32 +1114,14 @@ * for it now. */ if(sparc_cpu_model == sun4c) { - if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt, + if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt, SA_SHIRQ, "QuadEther", (void *) qecp)) { printk("QuadEther: Can't register QEC master irq handler.\n"); res = EAGAIN; goto qec_free_devs; } - } -#ifdef __sparc_v9__ - else if(sparc_cpu_model == sun4u) { - struct devid_cookie dcookie; - - dcookie.real_dev_id = qecp; - dcookie.imap = dcookie.iclr = 0; - dcookie.pil = -1; - dcookie.bus_cookie = sdev->my_bus; - if(request_irq(sdev->irqs[0].pri, &qec_interrupt, - (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), - "QuadEther", &dcookie)) { - printk("QuadEther: Can't register QEC master irq handler.\n"); - res = EAGAIN; - goto qec_free_devs; - } - } -#endif - else { - if(request_irq(sdev->irqs[0].pri, &qec_interrupt, + } else { + if(request_irq(sdev->irqs[0], &qec_interrupt, SA_SHIRQ, "QuadEther", (void *) qecp)) { printk("QuadEther: Can't register QEC master irq handler.\n"); res = EAGAIN; @@ -1241,7 +1223,7 @@ unregister_netdev(root_qec_dev->qes[i]->dev); kfree(root_qec_dev->qes[i]); } - free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev); + free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev); kfree(root_qec_dev); root_qec_dev = next_qec; } diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.1.111/linux/drivers/net/wavelan.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/net/wavelan.c Sun Jul 26 23:35:56 1998 @@ -264,7 +264,7 @@ static void psa_write(u_long ioaddr, u_short hacr, - int o, /* Offset in psa */ + int o, /* Offset in PSA */ u_char * b, /* Buffer in memory */ int n) /* Length of buffer */ { @@ -403,7 +403,7 @@ * Get the type of encryption available. */ static inline int -mmc_encr(u_long ioaddr) /* i/o port of the card */ +mmc_encr(u_long ioaddr) /* I/O port of the card */ { int temp; @@ -420,7 +420,7 @@ * I hope this one will be optimally inlined. */ static inline void -fee_wait(u_long ioaddr, /* i/o port of the card */ +fee_wait(u_long ioaddr, /* I/O port of the card */ int delay, /* Base delay to wait for */ int number) /* Number of time to wait */ { @@ -436,7 +436,7 @@ * Read bytes from the Frequency EEPROM (frequency select cards). */ static void -fee_read(u_long ioaddr, /* i/o port of the card */ +fee_read(u_long ioaddr, /* I/O port of the card */ u_short o, /* destination offset */ u_short * b, /* data buffer */ int n) /* number of registers */ @@ -471,7 +471,7 @@ * Jean II */ static void -fee_write(u_long ioaddr, /* i/o port of the card */ +fee_write(u_long ioaddr, /* I/O port of the card */ u_short o, /* destination offset */ u_short * b, /* data buffer */ int n) /* number of registers */ @@ -486,7 +486,7 @@ fee_wait(ioaddr, 10, 100); /* Read the protected register. */ - printk("Protected 2 : %02X-%02X\n", + printk("Protected 2: %02X-%02X\n", mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); #endif /* DOESNT_SEEM_TO_WORK */ @@ -501,7 +501,7 @@ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); #ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* Or use : */ + /* or use: */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); #endif /* DOESNT_SEEM_TO_WORK */ @@ -758,7 +758,7 @@ /* Read the first transmit buffer */ obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status)); - /* Hack for reconfiguration... */ + /* Hack for reconfiguration */ if(tx_status == 0xFFFF) if(!wv_config_complete(dev, ioaddr, lp)) break; /* Not completed */ @@ -787,7 +787,7 @@ lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; } - /* Hack for reconfiguration... */ + /* Hack for reconfiguration */ if(tx_status == 0xFFFF) continue; @@ -921,7 +921,7 @@ static void wv_psa_show(psa_t * p) { - printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n"); + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, p->psa_io_base_addr_2, @@ -1107,10 +1107,10 @@ printk(KERN_DEBUG "status: "); printk("stat 0x%x[%s%s%s%s] ", (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12, - (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "", + (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", - (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "", - (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : ""); + (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "", + (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : ""); printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "", @@ -1166,7 +1166,7 @@ printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); printk(KERN_DEBUG "ru:"); /* - * Not implemented yet... + * Not implemented yet */ printk("\n"); } /* wv_ru_show */ @@ -1335,7 +1335,7 @@ #endif #ifdef DEBUG_BASIC_SHOW - /* Now, let's go for the basic stuff */ + /* Now, let's go for the basic stuff. */ printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); for(i = 0; i < WAVELAN_ADDR_SIZE; i++) printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); @@ -1353,9 +1353,8 @@ { unsigned short freq; - /* Ask the EEPROM to read the frequency from the first area */ - fee_read(ioaddr, 0x00 /* 1st area - frequency... */, - &freq, 1); + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); /* Print frequency */ printk(", 2.00, %ld", (freq >> 6) + 2400L); @@ -1539,16 +1538,16 @@ return 0; } -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ +#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ /*------------------------------------------------------------------*/ /* - * Frequency setting (for hardware able of it) - * It's a bit complicated and you don't really want to look into it... + * Frequency setting (for hardware capable of it) + * It's a bit complicated and you don't really want to look into it. * (called in wavelan_ioctl) */ static inline int -wv_set_frequency(u_long ioaddr, /* i/o port of the card */ +wv_set_frequency(u_long ioaddr, /* I/O port of the card */ iw_freq * frequency) { const int BAND_NUM = 10; /* Number of bands */ @@ -1560,8 +1559,8 @@ /* Setting by frequency */ /* Theoretically, you may set any frequency between * the two limits with a 0.5 MHz precision. In practice, - * I don't want you to have trouble with local - * regulations. */ + * I don't want you to have trouble with local regulations. + */ if((frequency->e == 1) && (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) { @@ -1587,8 +1586,7 @@ u_short table[10]; /* Authorized frequency table */ /* Read the frequency table. */ - fee_read(ioaddr, 0x71 /* frequency table */, - table, 10); + fee_read(ioaddr, 0x71, table, 10); #ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "Frequency table: "); @@ -1616,29 +1614,26 @@ unsigned short area_verify[16]; unsigned short dac_verify[2]; /* Corresponding gain (in the power adjust value table) - * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 - * & WCIN062D.DOC, page 6.2.9 */ + * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 + * and WCIN062D.DOC, page 6.2.9. */ unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; int power_band = 0; /* Selected band */ unsigned short power_adjust; /* Correct value */ - /* Search for the gain */ + /* Search for the gain. */ power_band = 0; while((freq > power_limit[power_band]) && (power_limit[++power_band] != 0)) ; /* Read the first area. */ - fee_read(ioaddr, 0x00, - area, 16); + fee_read(ioaddr, 0x00, area, 16); /* Read the DAC. */ - fee_read(ioaddr, 0x60, - dac, 2); + fee_read(ioaddr, 0x60, dac, 2); /* Read the new power adjust value. */ - fee_read(ioaddr, 0x6B - (power_band >> 1), - &power_adjust, 1); + fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1); if(power_band & 0x1) power_adjust >>= 8; else @@ -1682,15 +1677,13 @@ fee_write(ioaddr, 0x60, dac, 2); - /* We now should verify here that the writing of the EEPROM was OK. */ + /* We now should verify here that the writing of the EEPROM went OK. */ /* Reread the first area. */ - fee_read(ioaddr, 0x00, - area_verify, 16); + fee_read(ioaddr, 0x00, area_verify, 16); /* Reread the DAC. */ - fee_read(ioaddr, 0x60, - dac_verify, 2); + fee_read(ioaddr, 0x60, dac_verify, 2); /* Compare. */ if(memcmp(area, area_verify, 16 * 2) || @@ -1710,16 +1703,16 @@ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - /* Wait until the download is finished */ + /* Wait until the download is finished. */ fee_wait(ioaddr, 100, 100); /* We must now download the power adjust value (gain) to - * the synthesizers (from the EEPROM - area 7 - DAC) */ + * the synthesizers (from the EEPROM - area 7 - DAC). */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - /* Wait until the download is finished */ + /* Wait for the download to finish. */ fee_wait(ioaddr, 100, 100); #ifdef DEBUG_IOCTL_INFO @@ -1745,22 +1738,21 @@ /*------------------------------------------------------------------*/ /* - * Give the list of available frequencies + * Give the list of available frequencies. */ static inline int -wv_frequency_list(u_long ioaddr, /* i/o port of the card */ - iw_freq * list, /* List of frequency to fill */ +wv_frequency_list(u_long ioaddr, /* I/O port of the card */ + iw_freq * list, /* List of frequencies to fill */ int max) /* Maximum number of frequencies */ { u_short table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ - /* Read the frequency table */ - fee_read(ioaddr, 0x71 /* frequency table */, - table, 10); + /* Read the frequency table. */ + fee_read(ioaddr, 0x71 /* frequency table */, table, 10); - /* Check all frequencies */ + /* Check all frequencies. */ i = 0; for(freq = 0; freq < 150; freq++) /* Look in the table if the frequency is allowed */ @@ -1837,8 +1829,8 @@ /*------------------------------------------------------------------*/ /* - * Perform ioctl: configuration and information - * This is here that are treated the wireless extensions (iwconfig) + * Perform ioctl for configuration and information. + * It is here that the wireless extensions are treated (iwconfig). */ static int wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ @@ -1857,7 +1849,7 @@ printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); #endif - /* Disable interrupts & save flags */ + /* Disable interrupts and save flags. */ x = wv_splhi(); /* Look what is the request */ @@ -1866,21 +1858,21 @@ /* --------------- WIRELESS EXTENSIONS --------------- */ case SIOCGIWNAME: - strcpy(wrq->u.name, "Wavelan"); + strcpy(wrq->u.name, "WaveLAN"); break; case SIOCSIWNWID: /* Set NWID in WaveLAN. */ if(wrq->u.nwid.on) { - /* Set NWID in psa */ + /* Set NWID in psa. */ psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; psa.psa_nwid_select = 0x01; psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3); - /* Set NWID in mmc */ + /* Set NWID in mmc. */ m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF; m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8; mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m, @@ -1925,9 +1917,8 @@ { unsigned short freq; - /* Ask the EEPROM to read the frequency from the first area */ - fee_read(ioaddr, 0x00 /* 1st area - frequency... */, - &freq, 1); + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; wrq->u.freq.e = 1; } @@ -2096,7 +2087,7 @@ { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, }; - /* Verify the user buffer */ + /* Verify the user buffer. */ ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(priv)); if(ret) @@ -2149,7 +2140,7 @@ memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n"); + printk(KERN_DEBUG "SetSpy: set of new addresses is: \n"); for(i = 0; i < wrq->u.data.length; i++) printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n", lp->spy_address[i][0], @@ -2226,7 +2217,7 @@ #ifdef HISTOGRAM case SIOCSIPHISTO: - /* Verif if the user is root */ + /* Verify that the user is root. */ if(!suser()) return -EPERM; @@ -2416,10 +2407,11 @@ u_char stats[3]; /* signal level, noise level, signal quality */ /* Read signal level, silence level and signal quality bytes. */ - /* Note: in the PCMCIA hardware, these are part of the frame. It seems + /* Note: in the PCMCIA hardware, these are part of the frame. It seems * that for the ISA hardware, it's nowhere to be found in the frame, * so I'm obliged to do this (it has a side effect on /proc/net/wireless). - * Any ideas? */ + * Any ideas? + */ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); @@ -2631,14 +2623,14 @@ * The principle: * Each block contains a transmit command, a NOP command, * a transmit block descriptor and a buffer. - * The CU reads the transmit block which points to the tbd, - * reads the tbd and the content of the buffer. - * When it has finished with it, it goes to the next command + * The CU read the transmit block which point to the tbd, + * read the tbd and the content of the buffer. + * When it has finish with it, it goes to the next command * which in our case is the NOP. The NOP points on itself, - * so the CU stops here. + * so the CU stop here. * When we add the next block, we modify the previous nop * to make it point on the new tx command. - * Simple, isn't it? + * Simple, isn't it ? * * (called in wavelan_packet_xmit()) */ @@ -2772,8 +2764,8 @@ /*------------------------------------------------------------------*/ /* * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the hardware is ready to accept - * the packet. We also prevent reentrance. Then, we call the function + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ static int @@ -2876,7 +2868,7 @@ /* Disable encryption */ psa.psa_encryption_select = 0; - /* Set to standard values + /* Set to standard values: * 0x04 for AT, * 0x01 for MCA, * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) @@ -2891,7 +2883,7 @@ psa.psa_conf_status |= 1; #ifdef USE_PSA_CONFIG - /* Write the psa */ + /* Write the psa. */ psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 4); psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, @@ -2948,7 +2940,7 @@ mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m)); /* The following code starts the modem of the 2.00 frequency - * selectable cards at power on. It's not strictly needed for the + * selectable cards at power on. It's not strictly needed for the * following boots. * The original patch was by Joe Finney for the PCMCIA driver, but * I've cleaned it up a bit and added documentation. diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h --- v2.1.111/linux/drivers/net/wavelan.h Mon Mar 17 14:54:26 1997 +++ linux/drivers/net/wavelan.h Sun Jul 26 23:35:56 1998 @@ -1,34 +1,34 @@ /* - * Wavelan ISA driver + * WaveLAN ISA driver * * Jean II - HPLB '96 * * Reorganisation and extension of the driver. - * Original copyrigth follow. See wavelan.p.h for details. + * Original copyright follows. See wavelan.p.h for details. * - * This file contain the declarations of the Wavelan hardware. Note that - * the Wavelan ISA include a i82586 controler (see definitions in + * This file contains the declarations for the WaveLAN hardware. Note that + * the WaveLAN ISA includes a i82586 controller (see definitions in * file i82586.h). * - * The main difference between the ISA hardware and the pcmcia one is - * the Ethernet Controler (i82586 instead of i82593). - * The i82586 allow multiple transmit buffers. The PSA need to be accessed + * The main difference between the ISA hardware and the PCMCIA one is + * the Ethernet controller (i82586 instead of i82593). + * The i82586 allows multiple transmit buffers. The PSA needs to be accessed * through the host interface. */ #ifndef _WAVELAN_H #define _WAVELAN_H -/* The detection of the wavelan card is made by reading the MAC - * address from the card and checking it. If you have a non AT&T - * product (OEM, like DEC RoamAbout, or Digital Ocean, Epson, ...), - * you might need to modify this part to accomodate your hardware... +/* Detection of the WaveLAN card is done by reading the MAC + * address from the card and checking it. If you have a non-AT&T + * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), + * you might need to modify this part to accommodate your hardware. */ const char MAC_ADDRESSES[][3] = { - { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ - { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ - /* Add your card here and send me the patch ! */ + { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ + /* Add your card here and send me the patch! */ }; #define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ @@ -49,7 +49,7 @@ unsigned short hu_command; /* Command register */ #define HACR_RESET 0x0001 /* Reset board */ #define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ -#define HACR_16BITS 0x0004 /* 16 bits operation (0 => 8bits) */ +#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */ #define HACR_OUT0 0x0008 /* General purpose output pin 0 */ /* not used - must be 1 */ #define HACR_OUT1 0x0010 /* General purpose output pin 1 */ @@ -112,11 +112,11 @@ /************************** MEMORY LAYOUT **************************/ /* - * Onboard 64k RAM layout. + * Onboard 64 k RAM layout. * (Offsets from 0x0000.) */ -#define OFFSET_RU 0x0000 /* 75 % memory */ -#define OFFSET_CU 0xC000 /* 25 % memory */ +#define OFFSET_RU 0x0000 /* 75% memory */ +#define OFFSET_CU 0xC000 /* 25% memory */ #define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t)) #define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t)) #define OFFSET_SCP I82586_SCP_ADDR @@ -151,26 +151,26 @@ unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ #define PSA_UNIVERSAL 0 /* Universal (factory) */ #define PSA_LOCAL 1 /* Local */ - unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ -#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ -#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ -#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ -#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ + unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ #define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ #define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ - unsigned char psa_subband; /* [0x20] Subband */ + unsigned char psa_subband; /* [0x20] Subband */ #define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ -#define PSA_SUBBAND_2425 1 /* 2425 MHz */ -#define PSA_SUBBAND_2460 2 /* 2460 MHz */ -#define PSA_SUBBAND_2484 3 /* 2484 MHz */ -#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ - unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */ unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ - unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ - unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */ unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ @@ -183,8 +183,8 @@ #define PSA_SIZE 64 -/* Calculate offset of a field in the above structure - * Warning : only even addresses are used */ +/* Calculate offset of a field in the above structure. + * Warning: only even addresses are used. */ #define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) /******************** MODEM MANAGEMENT INTERFACE ********************/ @@ -196,25 +196,25 @@ struct mmw_t { unsigned char mmw_encr_key[8]; /* encryption key */ - unsigned char mmw_encr_enable; /* enable/disable encryption */ -#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ -#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_encr_enable; /* Enable or disable encryption. */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */ unsigned char mmw_unused0[1]; /* unused */ - unsigned char mmw_des_io_invert; /* Encryption option */ -#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ -#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ + unsigned char mmw_des_io_invert; /* encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */ unsigned char mmw_unused1[5]; /* unused */ unsigned char mmw_loopt_sel; /* looptest selection */ -#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ -#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ -#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */ +#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */ #define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ #define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ #define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ #define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ unsigned char mmw_jabber_enable; /* jabber timer enable */ /* Abort transmissions > 200 ms */ - unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ + unsigned char mmw_freeze; /* freeze or unfreeze signal level */ /* 0 : signal level & qual updated for every new message, 1 : frozen */ unsigned char mmw_anten_sel; /* antenna selection */ #define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ @@ -227,7 +227,7 @@ unsigned char mmw_thr_pre_set; /* level threshold preset */ /* Discard all packet with signal < this value (4) */ unsigned char mmw_decay_prm; /* decay parameters */ - unsigned char mmw_decay_updat_prm; /* decay update parameterz */ + unsigned char mmw_decay_updat_prm; /* decay update parameters */ unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ /* Discard all packet with quality < this value (3) */ unsigned char mmw_netw_id_l; /* NWID low order byte */ @@ -237,31 +237,31 @@ /* 2.0 Hardware extension - frequency selection support */ unsigned char mmw_mode_select; /* for analog tests (set to 0) */ unsigned char mmw_unused3[1]; /* unused */ - unsigned char mmw_fee_ctrl; /* frequency eeprom control */ -#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ -#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ -#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ + unsigned char mmw_fee_ctrl; /* frequency EEPROM control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */ #define MMW_FEE_CTRL_READ 0x06 /* Read */ #define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ -#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ -#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */ #define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ #define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ #define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ -#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ -#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */ #define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ - /* Never issue this command (PRDS) : it's irreversible !!! */ + /* Never issue the PRDS command: it's irreversible! */ - unsigned char mmw_fee_addr; /* EEprom address */ -#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ + unsigned char mmw_fee_addr; /* EEPROM address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */ #define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ #define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ #define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ #define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ #define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ - unsigned char mmw_fee_data_l; /* Write data to EEprom */ + unsigned char mmw_fee_data_l; /* Write data to EEPROM. */ unsigned char mmw_fee_data_h; /* high octet */ unsigned char mmw_ext_ant; /* Setting for external antenna */ #define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ @@ -293,13 +293,13 @@ #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ - unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ + unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ unsigned char mmr_unused2[2]; /* unused */ - unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ - unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ - /* Warning : Read high order octet first !!! */ - unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ - unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ + unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */ + /* Warning: read high-order octet first! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */ unsigned char mmr_thr_pre_set; /* level threshold preset */ #define MMR_THR_PRE_SET 0x3F /* level threshold preset */ #define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ @@ -312,17 +312,17 @@ unsigned char mmr_sgnl_qual; /* signal quality */ #define MMR_SGNL_QUAL 0x0F /* signal quality */ #define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ - unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ + unsigned char mmr_netw_id_l; /* NWID low order byte (?) */ unsigned char mmr_unused3[3]; /* unused */ /* 2.0 Hardware extension - frequency selection support */ - unsigned char mmr_fee_status; /* Status of frequency eeprom */ -#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ + unsigned char mmr_fee_status; /* Status of frequency EEPROM */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */ #define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ -#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */ unsigned char mmr_unused4[1]; /* unused */ - unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ - unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ + unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ + unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ }; #define MMR_SIZE 36 diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.1.111/linux/drivers/net/wavelan.p.h Tue May 13 22:41:12 1997 +++ linux/drivers/net/wavelan.p.h Sun Jul 26 23:35:56 1998 @@ -1,79 +1,79 @@ /* - * Wavelan ISA driver + * WaveLAN ISA driver * * Jean II - HPLB '96 * * Reorganisation and extension of the driver. * - * This file contain all definition and declarations necessary for the - * wavelan isa driver. This file is a private header, so it should - * be included only on wavelan.c !!! + * This file contains all definitions and declarations necessary for the + * WaveLAN ISA driver. This file is a private header, so it should + * be included only in wavelan.c! */ #ifndef WAVELAN_P_H #define WAVELAN_P_H -/************************** DOCUMENTATION **************************/ +/************************** DOCUMENTATION ***************************/ /* - * This driver provide a Linux interface to the Wavelan ISA hardware - * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/"). + * This driver provides a Linux interface to the WaveLAN ISA hardware. + * The WaveLAN is a product of Lucent (http://www.wavelan.com/). * This division was formerly part of NCR and then AT&T. - * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and - * Aironet (Arlan). If you have one of those product, you will need to - * make some changes below... - * - * This driver is still a beta software. A lot of bugs have been corrected, - * a lot of functionalities are implemented, the whole appear pretty stable, - * but there is still some area of improvement (encryption, performance...). - * - * To know how to use this driver, read the NET3 HOWTO. - * If you want to exploit the many other fonctionalities, look comments - * in the code... + * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and + * Aironet (Arlan). If you have one of those products, you will need to + * make some changes below. + * + * This driver is still beta software. A lot of bugs have been corrected, + * a lot of functionality is implemented, and the whole appears stable, + * but there is still room for improvement (encryption, performance). + * + * To learn how to use this driver, read the NET3 HOWTO. + * If you want to exploit the many other functionalities, read the comments + * in the code. * - * This driver is the result of the effort of many peoples (see below). + * This driver is the result of the effort of many people (see below). */ /* ------------------------ SPECIFIC NOTES ------------------------ */ /* - * wavelan.o is darn too big - * ------------------------- - * That's true ! There is a very simple way to reduce the driver - * object by 33% (yes !). Comment out the following line : + * wavelan.o is too darned big + * --------------------------- + * That's true! There is a very simple way to reduce the driver + * object by 33%! Comment out the following line: * #include * - * MAC address and hardware detection : - * ---------------------------------- - * The detection code of the wavelan chech that the first 3 - * octets of the MAC address fit the company code. This type of - * detection work well for AT&T cards (because the AT&T code is + * MAC address and hardware detection: + * ----------------------------------- + * The detection code for the WaveLAN checks that the first three + * octets of the MAC address fit the company code. This type of + * detection works well for AT&T cards (because the AT&T code is * hardcoded in wavelan.h), but of course will fail for other - * manufacturer. + * manufacturers. * - * If you are sure that your card is derived from the wavelan, - * here is the way to configure it : + * If you are sure that your card is derived from the WaveLAN, + * here is the way to configure it: * 1) Get your MAC address - * a) With your card utilities (wfreqsel, instconf, ...) - * b) With the driver : + * a) With your card utilities (wfreqsel, instconf, etc.) + * b) With the driver: * o compile the kernel with DEBUG_CONFIG_INFO enabled * o Boot and look the card messages * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) - * 3) Compile & verify - * 4) Send me the MAC code - I will include it in the next version... + * 3) Compile and verify + * 4) Send me the MAC code. I will include it in the next version. * - * "CU Inactive" message at boot up : + * "CU Inactive" message at boot up: * ----------------------------------- - * It seem that there is some weird timings problems with the - * Intel microcontroler. In fact, this message is triggered by a - * bad reading of the on board ram the first time we read the - * control block. If you ignore this message, all is ok (but in - * fact, currently, it reset the wavelan hardware). + * It seems that there is some weird timing problem with the + * Intel microcontroller. In fact, this message is triggered by a + * bad reading of the onboard RAM the first time we read the + * control block. If you ignore this message, all is OK (but in + * fact, currently, it resets the WaveLAN hardware). * - * To get rid of that problem, there is two solution. The first + * There are two ways to get rid of that problem. The first * is to add a dummy read of the scb at the end of - * wv_82586_config. The second is to add the timers + * wv_82586_config. The second is to add the timers * wv_synchronous_cmd and wv_ack (the udelay just after the - * waiting loops - seem that the controler is not totally ready - * when it say it is !). + * waiting loops--it seems that the controller is not totally ready + * when it says it is). * * In the current code, I use the second solution (to be * consistent with the original solution of Bruce Janson). @@ -81,10 +81,10 @@ /* --------------------- WIRELESS EXTENSIONS --------------------- */ /* - * This driver is the first one to support "wireless extensions". - * This set of extensions provide you some way to control the wireless - * caracteristics of the hardware in a standard way and support for - * applications for taking advantage of it (like Mobile IP). + * This driver is the first to support "wireless extensions". + * This set of extensions provides a standard way to control the wireless + * characteristics of the hardware. Applications such as mobile IP may + * take advantage of it. * * You will need to enable the CONFIG_NET_RADIO define in the kernel * configuration to enable the wireless extensions (this is the one @@ -96,64 +96,64 @@ /* ---------------------------- FILES ---------------------------- */ /* - * wavelan.c : The actual code for the driver - C functions + * wavelan.c: actual code for the driver: C functions * - * wavelan.p.h : Private header : local types / vars for the driver + * wavelan.p.h: private header: local types and variables for driver * - * wavelan.h : Description of the hardware interface & structs + * wavelan.h: description of the hardware interface and structs * - * i82586.h : Description if the Ethernet controler + * i82586.h: description of the Ethernet controller */ /* --------------------------- HISTORY --------------------------- */ /* - * (Made with information in drivers headers. It may not be accurate, - * and I garantee nothing except my best effort...) + * This is based on information in the drivers' headers. It may not be + * accurate, and I guarantee only my best effort. * - * The history of the Wavelan drivers is as complicated as history of - * the Wavelan itself (NCR -> AT&T -> Lucent). + * The history of the WaveLAN drivers is as complicated as the history of + * the WaveLAN itself (NCR -> AT&T -> Lucent). * - * All started with Anders Klemets , - * writting a Wavelan ISA driver for the MACH microkernel. Girish + * It all started with Anders Klemets + * writing a WaveLAN ISA driver for the Mach microkernel. Girish * Welling had also worked on it. - * Keith Moore modify this for the Pcmcia hardware. + * Keith Moore modified this for the PCMCIA hardware. * - * Robert Morris port these two drivers to BSDI - * and add specific Pcmcia support (there is currently no equivalent - * of the PCMCIA package under BSD...). + * Robert Morris ported these two drivers to BSDI + * and added specific PCMCIA support (there is currently no equivalent + * of the PCMCIA package under BSD). * - * Jim Binkley port both BSDI drivers to freeBSD. + * Jim Binkley ported both BSDI drivers to FreeBSD. * - * Bruce Janson port the BSDI ISA driver to Linux. + * Bruce Janson ported the BSDI ISA driver to Linux. * - * Anthony D. Joseph started modify Bruce driver + * Anthony D. Joseph started to modify Bruce's driver * (with help of the BSDI PCMCIA driver) for PCMCIA. - * Yunzhou Li finished is work. + * Yunzhou Li finished this work. * Joe Finney patched the driver to start - * correctly 2.00 cards (2.4 GHz with frequency selection). + * 2.00 cards correctly (2.4 GHz with frequency selection). * David Hinds integrated the whole in his - * Pcmcia package (+ bug corrections). + * PCMCIA package (and bug corrections). * * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some - * patchs to the Pcmcia driver. After, I added code in the ISA driver + * patches to the PCMCIA driver. Later, I added code in the ISA driver * for Wireless Extensions and full support of frequency selection - * cards. Then, I've done the same to the Pcmcia driver + some - * reorganisation. Finally, I came back to the ISA driver to - * upgrade it at the same level as the Pcmcia one and reorganise - * the code + * cards. Then, I did the same to the PCMCIA driver, and did some + * reorganisation. Finally, I came back to the ISA driver to + * upgrade it at the same level as the PCMCIA one and reorganise + * the code. * Loeke Brederveld from Lucent has given me - * much needed informations on the Wavelan hardware. + * much needed information on the WaveLAN hardware. */ -/* The original copyrights and litteratures mention others names and - * credits. I don't know what there part in this development was... +/* The original copyrights and literature mention others' names and + * credits. I don't know what their part in this development was. */ -/* By the way : for the copyright & legal stuff : - * Almost everybody wrote code under GNU or BSD license (or alike), - * and want that their original copyright remain somewhere in the +/* By the way, for the copyright and legal stuff: + * almost everybody wrote code under the GNU or BSD license (or similar), + * and want their original copyright to remain somewhere in the * code (for myself, I go with the GPL). - * Nobody want to take responsibility for anything, except the fame... + * Nobody wants to take responsibility for anything, except the fame. */ /* --------------------------- CREDITS --------------------------- */ @@ -162,121 +162,120 @@ * Linux operating system. * It is based on other device drivers and information * either written or supplied by: - * Ajay Bakre (bakre@paul.rutgers.edu), - * Donald Becker (becker@cesdis.gsfc.nasa.gov), - * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), + * Ajay Bakre , + * Donald Becker , + * Loeke Brederveld , * Brent Elphick , - * Anders Klemets (klemets@it.kth.se), - * Vladimir V. Kolpakov (w@stier.koenig.ru), - * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), - * Pauline Middelink (middelin@polyware.iaf.nl), - * Robert Morris (rtm@das.harvard.edu), - * Jean Tourrilhes (jt@hplb.hpl.hp.com), - * Girish Welling (welling@paul.rutgers.edu), + * Anders Klemets , + * Vladimir V. Kolpakov , + * Marc Meertens , + * Pauline Middelink , + * Robert Morris , + * Jean Tourrilhes , + * Girish Welling , * Clark Woodworth - * Yongguang Zhang ... + * Yongguang Zhang * * Thanks go also to: - * James Ashton (jaa101@syseng.anu.edu.au), - * Alan Cox (iialan@iiit.swan.ac.uk), - * Allan Creighton (allanc@cs.usyd.edu.au), - * Matthew Geier (matthew@cs.usyd.edu.au), - * Remo di Giovanni (remo@cs.usyd.edu.au), - * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), - * Vipul Gupta (vgupta@cs.binghamton.edu), - * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), - * Tim Nicholson (tim@cs.usyd.edu.au), - * Ian Parkin (ian@cs.usyd.edu.au), - * John Rosenberg (johnr@cs.usyd.edu.au), - * George Rossi (george@phm.gov.au), - * Arthur Scott (arthur@cs.usyd.edu.au), + * James Ashton , + * Alan Cox , + * Allan Creighton , + * Matthew Geier , + * Remo di Giovanni , + * Eckhard Grah , + * Vipul Gupta , + * Mark Hagan , + * Tim Nicholson , + * Ian Parkin , + * John Rosenberg , + * George Rossi , + * Arthur Scott , * Stanislav Sinyagin - * Peter Storey, - * for their assistance and advice. + * and Peter Storey for their assistance and advice. * * Additional Credits: * - * My developpement has been done under Linux 2.0.x (Debian 1.1) with + * My development has been done under Linux 2.0.x (Debian 1.1) with * an HP Vectra XP/60. * */ /* ------------------------- IMPROVEMENTS ------------------------- */ /* - * I proudly present : + * I proudly present: * - * Changes mades in first pre-release : + * Changes made in first pre-release: * ---------------------------------- - * - Reorganisation of the code, function name change - * - Creation of private header (wavelan.p.h) - * - Reorganised debug messages - * - More comments, history, ... - * - mmc_init : configure the PSA if not done - * - mmc_init : correct default value of level threshold for pcmcia - * - mmc_init : 2.00 detection better code for 2.00 init + * - reorganisation of the code, function name change + * - creation of private header (wavelan.p.h) + * - reorganised debug messages + * - more comments, history, etc. + * - mmc_init: configure the PSA if not done + * - mmc_init: correct default value of level threshold for PCMCIA + * - mmc_init: 2.00 detection better code for 2.00 initialization * - better info at startup - * - irq setting (note : this setting is permanent...) - * - Watchdog : change strategy (+ solve module removal problems) - * - add wireless extensions (ioctl & get_wireless_stats) + * - IRQ setting (note: this setting is permanent) + * - watchdog: change strategy (and solve module removal problems) + * - add wireless extensions (ioctl and get_wireless_stats) * get/set nwid/frequency on fly, info for /proc/net/wireless - * - More wireless extension : SETSPY and GETSPY - * - Make wireless extensions optional - * - Private ioctl to set/get quality & level threshold, histogram - * - Remove /proc/net/wavelan - * - Supress useless stuff from lp (net_local) + * - more wireless extensions: SETSPY and GETSPY + * - make wireless extensions optional + * - private ioctl to set/get quality and level threshold, histogram + * - remove /proc/net/wavelan + * - suppress useless stuff from lp (net_local) * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) - * - Add message level (debug stuff in /var/adm/debug & errors not + * - add message level (debug stuff in /var/adm/debug and errors not * displayed at console and still in /var/adm/messages) * - multi device support - * - Start fixing the probe (init code) - * - More inlines + * - start fixing the probe (init code) + * - more inlines * - man page - * - Lot of others minor details & cleanups + * - many other minor details and cleanups * - * Changes made in second pre-release : - * ---------------------------------- - * - Cleanup init code (probe & module init) - * - Better multi device support (module) - * - name assignement (module) - * - * Changes made in third pre-release : - * --------------------------------- - * - Be more conservative on timers - * - Preliminary support for multicast (I still lack some details...) + * Changes made in second pre-release: + * ----------------------------------- + * - clean up init code (probe and module init) + * - better multiple device support (module) + * - name assignment (module) * - * Changes made in fourth pre-release : + * Changes made in third pre-release: * ---------------------------------- + * - be more conservative on timers + * - preliminary support for multicast (I still lack some details) + * + * Changes made in fourth pre-release: + * ----------------------------------- * - multicast (revisited and finished) - * - Avoid reset in set_multicast_list (a really big hack) - * if somebody could apply this code for other i82586 based driver... - * - Share on board memory 75% RU / 25% CU (instead of 50/50) + * - avoid reset in set_multicast_list (a really big hack) + * if somebody could apply this code for other i82586 based drivers + * - share onboard memory 75% RU and 25% CU (instead of 50/50) * - * Changes made for release in 2.1.15 : - * ---------------------------------- - * - Change the detection code for multi manufacturer code support + * Changes made for release in 2.1.15: + * ----------------------------------- + * - change the detection code for multi manufacturer code support * - * Changes made for release in 2.1.17 : - * ---------------------------------- - * - Update to wireless extensions changes - * - Silly bug in card initial configuration (psa_conf_status) + * Changes made for release in 2.1.17: + * ----------------------------------- + * - update to wireless extensions changes + * - silly bug in card initial configuration (psa_conf_status) * - * Changes made for release in 2.1.27 & 2.0.30 : - * ------------------------------------------- - * - Small bug in debug code (probably not the last one...) - * - Remove extern kerword for wavelan_probe() - * - Level threshold is now a standard wireless extension (version 4 !) + * Changes made for release in 2.1.27 & 2.0.30: + * -------------------------------------------- + * - small bug in debug code (probably not the last one...) + * - remove extern keyword for wavelan_probe() + * - level threshold is now a standard wireless extension (version 4 !) * - modules parameters types (new module interface) * - * Changes made for release in 2.1.36 : - * ---------------------------------- + * Changes made for release in 2.1.36: + * ----------------------------------- * - byte count stats (courtesy of David Hinds) - * - Remove dev_tint stuff (courtesy of David Hinds) - * - Encryption setting from Brent Elphick (thanks a lot !) + * - remove dev_tint stuff (courtesy of David Hinds) + * - encryption setting from Brent Elphick (thanks a lot!) * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) * - * Wishes & dreams : - * --------------- - * - Roaming + * Wishes & dreams: + * ---------------- + * - roaming */ /***************************** INCLUDES *****************************/ @@ -309,52 +308,52 @@ #include /* Wireless extensions */ -/* Wavelan declarations */ +/* WaveLAN declarations */ #include "i82586.h" #include "wavelan.h" /****************************** DEBUG ******************************/ -#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ -#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ -#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ -#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ +#undef DEBUG_MODULE_TRACE /* module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ #define DEBUG_INTERRUPT_ERROR /* problems */ -#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ -#undef DEBUG_CONFIG_INFO /* What's going on... */ -#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ -#undef DEBUG_TX_TRACE /* Transmission calls */ -#undef DEBUG_TX_INFO /* Header of the transmited packet */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ +#undef DEBUG_CONFIG_INFO /* what's going on */ +#define DEBUG_CONFIG_ERRORS /* errors on configuration */ +#undef DEBUG_TX_TRACE /* transmission calls */ +#undef DEBUG_TX_INFO /* header of the transmitted packet */ #define DEBUG_TX_ERROR /* unexpected conditions */ -#undef DEBUG_RX_TRACE /* Transmission calls */ -#undef DEBUG_RX_INFO /* Header of the transmited packet */ +#undef DEBUG_RX_TRACE /* transmission calls */ +#undef DEBUG_RX_INFO /* header of the transmitted packet */ #define DEBUG_RX_ERROR /* unexpected conditions */ -#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen */ -#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ -#undef DEBUG_IOCTL_INFO /* Various debug info */ -#define DEBUG_IOCTL_ERROR /* What's going wrong */ -#define DEBUG_BASIC_SHOW /* Show basic startup info */ -#undef DEBUG_VERSION_SHOW /* Print version info */ -#undef DEBUG_PSA_SHOW /* Dump psa to screen */ -#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ -#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ -#undef DEBUG_I82586_SHOW /* Show i82586 status */ -#undef DEBUG_DEVICE_SHOW /* Show device parameters */ - -/* Options : */ -#define USE_PSA_CONFIG /* Use info from the PSA */ -#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions */ -#undef STRUCT_CHECK /* Verify padding of structures */ -#undef PSA_CRC /* Check CRC in PSA */ -#undef OLDIES /* Old code (to redo) */ -#undef RECORD_SNR /* To redo */ -#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ -#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ - -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ -/* Warning : these stuff will slow down the driver... */ -#define WIRELESS_SPY /* Enable spying addresses */ -#undef HISTOGRAM /* Enable histogram of sig level... */ +#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen. */ +#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ +#undef DEBUG_IOCTL_INFO /* various debugging info */ +#define DEBUG_IOCTL_ERROR /* what's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info. */ +#undef DEBUG_VERSION_SHOW /* Print version info. */ +#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ +#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ +#undef DEBUG_I82586_SHOW /* Show i82586 status. */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters. */ + +/* Options */ +#define USE_PSA_CONFIG /* Use info from the PSA. */ +#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions. */ +#undef STRUCT_CHECK /* Verify padding of structures. */ +#undef PSA_CRC /* Check CRC in PSA. */ +#undef OLDIES /* old code (to redo) */ +#undef RECORD_SNR /* to redo */ +#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ + +#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ +/* Warning: this stuff will slow down the driver. */ +#define WIRELESS_SPY /* Enable spying addresses. */ +#undef HISTOGRAM /* Enable histogram of signal level. */ #endif /************************ CONSTANTS & MACROS ************************/ @@ -364,7 +363,7 @@ #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */ +#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */ /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) @@ -396,23 +395,23 @@ /* * Static specific data for the interface. * - * For each network interface, Linux keep data in two structure. "device" - * keep the generic data (same format for everybody) and "net_local" keep - * the additional specific data. + * For each network interface, Linux keeps data in two structures: "device" + * keeps the generic data (same format for everybody) and "net_local" keeps + * additional specific data. * Note that some of this specific data is in fact generic (en_stats, for * example). */ struct net_local { - net_local * next; /* Linked list of the devices */ - device * dev; /* Reverse link... */ + net_local * next; /* linked list of the devices */ + device * dev; /* reverse link */ en_stats stats; /* Ethernet interface statistics */ - int nresets; /* Number of hw resets */ - u_char reconfig_82586; /* Need to reconfigure the controler */ - u_char promiscuous; /* Promiscuous mode */ - int mc_count; /* Number of multicast addresses */ - timer_list watchdog; /* To avoid blocking state */ - u_short hacr; /* Current host interface state */ + int nresets; /* number of hardware resets */ + u_char reconfig_82586; /* We need to reconfigure the controller. */ + u_char promiscuous; /* promiscuous mode */ + int mc_count; /* number of multicast addresses */ + timer_list watchdog; /* to avoid blocking state */ + u_short hacr; /* current host interface state */ int tx_n_in_use; u_short rx_head; @@ -421,82 +420,83 @@ u_short tx_first_in_use; #ifdef WIRELESS_EXT - iw_stats wstats; /* Wireless specific stats */ + iw_stats wstats; /* Wireless-specific statistics */ #endif #ifdef WIRELESS_SPY - int spy_number; /* Number of addresses to spy */ - mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */ - iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */ + int spy_number; /* number of addresses to spy */ + mac_addr spy_address[IW_MAX_SPY]; /* the addresses to spy */ + iw_qual spy_stat[IW_MAX_SPY]; /* statistics gathered */ #endif /* WIRELESS_SPY */ + #ifdef HISTOGRAM - int his_number; /* Number of intervals */ - u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ - u_long his_sum[16]; /* Sum in interval */ + int his_number; /* number of intervals */ + u_char his_range[16]; /* boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* sum in interval */ #endif /* HISTOGRAM */ }; /**************************** PROTOTYPES ****************************/ -/* ----------------------- MISC SUBROUTINES ------------------------ */ +/* ----------------------- MISC. SUBROUTINES ------------------------ */ static inline unsigned long /* flags */ wv_splhi(void); /* Disable interrupts */ static inline void - wv_splx(unsigned long); /* ReEnable interrupts : flags */ + wv_splx(unsigned long); /* Enable interrupts: flags */ static u_char wv_irq_to_psa(int); static int wv_psa_to_irq(u_char); /* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ static inline u_short /* data */ - hasr_read(u_long); /* Read the host interface : base address */ + hasr_read(u_long); /* Read the host interface: base address */ static inline void - hacr_write(u_long, /* Write to host interface : base address */ + hacr_write(u_long, /* Write to host interface: base address */ u_short), /* data */ hacr_write_slow(u_long, u_short), set_chan_attn(u_long, /* ioaddr */ - u_short), /* hacr */ + u_short), /* hacr */ wv_hacr_reset(u_long), /* ioaddr */ wv_16_off(u_long, /* ioaddr */ - u_short), /* hacr */ + u_short), /* hacr */ wv_16_on(u_long, /* ioaddr */ - u_short), /* hacr */ + u_short), /* hacr */ wv_ints_off(device *), wv_ints_on(device *); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static void - psa_read(u_long, /* Read the Parameter Storage Area */ + psa_read(u_long, /* Read the Parameter Storage Area. */ u_short, /* hacr */ int, /* offset in PSA */ u_char *, /* buffer to fill */ int), /* size to read */ - psa_write(u_long, /* Write to the PSA */ + psa_write(u_long, /* Write to the PSA. */ u_short, /* hacr */ - int, /* Offset in psa */ - u_char *, /* Buffer in memory */ - int); /* Length of buffer */ + int, /* offset in PSA */ + u_char *, /* buffer in memory */ + int); /* length of buffer */ static inline void - mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ u_short, u_char), - mmc_write(u_long, /* Write n bytes to the MMC */ + mmc_write(u_long, /* Write n bytes to the MMC. */ u_char, u_char *, int); -static inline u_char /* Read 1 byte from the MMC */ +static inline u_char /* Read 1 byte from the MMC. */ mmc_in(u_long, u_short); static inline void - mmc_read(u_long, /* Read n bytes from the MMC */ + mmc_read(u_long, /* Read n bytes from the MMC. */ u_char, u_char *, int), - fee_wait(u_long, /* Wait for frequency EEprom : base address */ - int, /* Base delay to wait for */ - int); /* Number of time to wait */ + fee_wait(u_long, /* Wait for frequency EEPROM: base address */ + int, /* base delay to wait for */ + int); /* time to wait */ static void - fee_read(u_long, /* Read the frequency EEprom : base address */ + fee_read(u_long, /* Read the frequency EEPROM: base address */ u_short, /* destination offset */ u_short *, /* data buffer */ int); /* number of registers */ @@ -539,60 +539,59 @@ wavelan_set_multicast_list(device *); /* ----------------------- PACKET RECEPTION ----------------------- */ static inline void - wv_packet_read(device *, /* Read a packet from a frame */ + wv_packet_read(device *, /* Read a packet from a frame. */ u_short, int), - wv_receive(device *); /* Read all packets waiting */ + wv_receive(device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline void - wv_packet_write(device *, /* Write a packet to the Tx buffer */ + wv_packet_write(device *, /* Write a packet to the Tx buffer. */ void *, short); static int - wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ + wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *), /* Initialize the modem */ - wv_ru_start(device *), /* Start the i82586 receiver unit */ - wv_cu_start(device *), /* Start the i82586 command unit */ - wv_82586_start(device *); /* Start the i82586 */ + wv_mmc_init(device *), /* Initialize the modem. */ + wv_ru_start(device *), /* Start the i82586 receiver unit. */ + wv_cu_start(device *), /* Start the i82586 command unit. */ + wv_82586_start(device *); /* Start the i82586. */ static void - wv_82586_config(device *); /* Configure the i82586 */ + wv_82586_config(device *); /* Configure the i82586. */ static inline void wv_82586_stop(device *); static int - wv_hw_reset(device *), /* Reset the wavelan hardware */ + wv_hw_reset(device *), /* Reset the WaveLAN hardware. */ wv_check_ioaddr(u_long, /* ioaddr */ u_char *); /* mac address (read) */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ static void - wavelan_interrupt(int, /* Interrupt handler */ + wavelan_interrupt(int, /* interrupt handler */ void *, struct pt_regs *); static void - wavelan_watchdog(u_long); /* Transmission watchdog */ + wavelan_watchdog(u_long); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device */ - wavelan_close(device *), /* Close the device */ - wavelan_config(device *); /* Configure one device */ + wavelan_open(device *), /* Open the device. */ + wavelan_close(device *), /* Close the device. */ + wavelan_config(device *); /* Configure one device. */ extern int - wavelan_probe(device *); /* See Space.c */ + wavelan_probe(device *); /* See Space.c. */ /**************************** VARIABLES ****************************/ /* - * This is the root of the linked list of wavelan drivers + * This is the root of the linked list of WaveLAN drivers * It is use to verify that we don't reuse the same base address - * for two differents drivers and to make the cleanup when - * removing the module. + * for two different drivers and to clean up when removing the module. */ static net_local * wavelan_list = (net_local *) NULL; /* - * This table is used to translate the psa value to irq number - * and vice versa... + * This table is used to translate the PSA value to IRQ number + * and vice versa. */ static u_char irqvals[] = { @@ -603,7 +602,7 @@ }; /* - * Table of the available i/o address (base address) for wavelan + * Table of the available I/O addresses (base addresses) for WaveLAN */ static unsigned short iobase[] = { @@ -612,7 +611,7 @@ * controllers. * Leave out the others too -- we will always use 0x390 and leave * 0x300 for the Ethernet device. - * Jean II : 0x3E0 is really fine as well... + * Jean II: 0x3E0 is fine as well. */ 0x300, 0x390, 0x3E0, 0x3C0 #endif /* 0 */ diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.1.111/linux/drivers/scsi/eata.c Sun Jun 7 11:16:34 1998 +++ linux/drivers/scsi/eata.c Sun Jul 26 12:56:08 1998 @@ -1,6 +1,21 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 + * + Added command line option (rs:[y|n]) to reverse the scan order + * of PCI boards. The default is rs:y, which reverses the BIOS order + * while registering PCI boards. The default value rs:y generates + * the same order of all previous revisions of this driver. + * Pls. note that "BIOS order" might have been reversed itself + * after the 2.1.9x PCI modifications in the linux kernel. + * The rs value is ignored when the explicit list of addresses + * is used by the "eata=port0,port1,..." command line option. + * + Added command line option (et:[y|n]) to force use of extended + * translation (255 heads, 63 sectors) as disk geometry. + * The default is et:n, which uses the disk geometry returned + * by scsicam_bios_param. The default value et:n is compatible with + * all previous revisions of this driver. + * * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 * Increased busy timeout from 10 msec. to 200 msec. while * processing interrupts. @@ -193,6 +208,10 @@ * PM3222 - SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI) * PM3224 - SmartRAID Adapter for PCI (PM3224W is 16-bit wide SCSI) * + * The above list is just an indication: as a matter of fact all DPT + * boards using the EATA/DMA protocol are supported by this driver, + * since they use exactely the same programming interface. + * * The DPT PM2001 provides only the EATA/PIO interface and hence is not * supported by this driver. * @@ -255,6 +274,10 @@ * * eh:y use new scsi code (linux 2.2 only); * eh:n use old scsi code; + * et:y force use of extended translation (255 heads, 63 sectors); + * et:n use disk geometry detected by scsicam_bios_param; + * rs:y reverse scan order while detecting PCI boards; + * rs:n use BIOS order while detecting PCI boards; * lc:y enables linked commands; * lc:n disables linked commands; * tc:y enables tagged commands; @@ -265,15 +288,16 @@ * tm:3 use only ordered queue tags; * mq:xx set the max queue depth to the value xx (2 <= xx <= 32). * - * The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using - * the list of detection probes could be: - * "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n". + * The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n". + * An example using the list of detection probes could be: + * "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n". * * When loading as a module, parameters can be specified as well. * The above example would be (use 1 in place of y and 0 in place of n): * * modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \ - * max_queue_depth=4 tag_mode=0 use_new_eh_code=0 + * max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \ + * ext_tran=0 rev_scan=1 * * ---------------------------------------------------------------------------- * In this implementation, linked commands are designed to work with any DISK @@ -307,6 +331,19 @@ * When the driver detects a batch including overlapping requests * (a really rare event) strict serial (pid) order is enforced. * ---------------------------------------------------------------------------- + * The extended translation option (et:y) is useful when using large physical + * disks/arrays. It could also be useful when switching between Adaptec boards + * and DPT boards without reformatting the disk. + * When a boot disk is partitioned with extended translation, in order to + * be able to boot it with a DPT board is could be necessary to add to + * lilo.conf additional commands as in the following example: + * + * fix-table + * disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546 + * + * where the above geometry should be replaced with the one reported at + * power up by the DPT controller. + * ---------------------------------------------------------------------------- * * The boards are named EATA0, EATA1,... according to the detection order. * @@ -330,6 +367,8 @@ MODULE_PARM(max_queue_depth, "i"); MODULE_PARM(tag_mode, "i"); MODULE_PARM(use_new_eh_code, "i"); +MODULE_PARM(ext_tran, "i"); +MODULE_PARM(rev_scan, "i"); MODULE_AUTHOR("Dario Ballabio"); #endif @@ -413,6 +452,7 @@ #undef DEBUG_RESET #undef DEBUG_GENERATE_ERRORS #undef DEBUG_GENERATE_ABORTS +#undef DEBUG_GEOMETRY #define MAX_ISA 4 #define MAX_VESA 0 @@ -663,6 +703,8 @@ static int setup_done = FALSE; static int link_statistics = 0; static int tag_mode = TAG_MIXED; +static int ext_tran = FALSE; +static int rev_scan = TRUE; #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) static int tagged_comm = TRUE; @@ -1067,9 +1109,9 @@ if (j == 0) { printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n"); - printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n", - driver_name, tag_type, YESNO(linked_comm), - max_queue_depth, YESNO(use_new_eh_code)); + printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n", + driver_name, tag_type, YESNO(linked_comm), max_queue_depth, + YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran)); } printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n", @@ -1132,6 +1174,8 @@ else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; else if (!strncmp(cur, "ls:", 3)) link_statistics = val; else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val; + else if (!strncmp(cur, "et:", 3)) ext_tran = val; + else if (!strncmp(cur, "rs:", 3)) rev_scan = val; if ((cur = strchr(cur, ','))) ++cur; } @@ -1165,8 +1209,8 @@ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; - /* Reverse the returned address order */ - io_port[MAX_INT_PARAM + MAX_PCI - k] = + /* 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; } @@ -1193,8 +1237,8 @@ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) continue; - /* Reverse the returned address order */ - io_port[MAX_INT_PARAM + MAX_PCI - k] = + /* 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; } @@ -1845,6 +1889,23 @@ } #endif /* new_eh_code */ + +int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { + int size = disk->capacity; + + if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) { + dkinfo[0] = 255; + dkinfo[1] = 63; + dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); + } + +#if defined (DEBUG_GEOMETRY) + printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name, + dkinfo[0], dkinfo[1], dkinfo[2]); +#endif + + return FALSE; +} static void sort(unsigned long sk[], unsigned int da[], unsigned int n, unsigned int rev) { diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h --- v2.1.111/linux/drivers/scsi/eata.h Sun Jun 7 11:16:34 1998 +++ linux/drivers/scsi/eata.h Sun Jul 26 12:56:08 1998 @@ -14,8 +14,9 @@ int eata2x_old_abort(Scsi_Cmnd *); int eata2x_reset(Scsi_Cmnd *); int eata2x_old_reset(Scsi_Cmnd *, unsigned int); +int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "4.32.00" +#define EATA_VERSION "4.33.00" #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) @@ -32,7 +33,7 @@ eh_device_reset_handler: NULL, \ eh_bus_reset_handler: NULL, \ eh_host_reset_handler: eata2x_reset, \ - bios_param: scsicam_bios_param, \ + bios_param: eata2x_biosparam, \ this_id: 7, \ unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING, \ @@ -48,7 +49,7 @@ queuecommand: eata2x_queuecommand, \ abort: eata2x_old_abort, \ reset: eata2x_old_reset, \ - bios_param: scsicam_bios_param, \ + bios_param: eata2x_biosparam, \ this_id: 7, \ unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING \ diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.1.111/linux/drivers/scsi/ide-scsi.c Thu May 14 19:47:41 1998 +++ linux/drivers/scsi/ide-scsi.c Sun Jul 26 11:46:46 1998 @@ -772,7 +772,7 @@ rq->cmd = IDESCSI_PC_RQ; spin_unlock(&io_request_lock); (void) ide_do_drive_cmd (drive, rq, ide_end); - spin_lock(&io_request_lock); + spin_lock_irq(&io_request_lock); return 0; abort: if (pc) kfree (pc); diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.111/linux/drivers/scsi/scsi.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/scsi/scsi.c Sat Jul 25 18:49:15 1998 @@ -750,6 +750,7 @@ case TYPE_MOD: case TYPE_PROCESSOR: case TYPE_SCANNER: + case TYPE_MEDIUM_CHANGER: SDpnt->writeable = 1; break; case TYPE_WORM: diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.1.111/linux/drivers/scsi/u14-34f.c Sun Jun 7 11:16:35 1998 +++ linux/drivers/scsi/u14-34f.c Sun Jul 26 12:56:08 1998 @@ -1,6 +1,14 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 + * Added command line option (et:[y|n]) to use the existing + * translation (returned by scsicam_bios_param) as disk geometry. + * The default is et:n, which uses the disk geometry jumpered + * on the board. + * The default value et:n is compatible with all previous revisions + * of this driver. + * * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 * Increased busy timeout from 10 msec. to 200 msec. while * processing interrupts. @@ -245,20 +253,23 @@ * * eh:y use new scsi code (linux 2.2 only); * eh:n use old scsi code; + * et:y use disk geometry returned by scsicam_bios_param; + * et:n use disk geometry jumpered on the board; * lc:y enables linked commands; * lc:n disables linked commands; * of:y enables old firmware support; * of:n disables old firmware support; * mq:xx set the max queue depth to the value xx (2 <= xx <= 8). * - * The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list - * of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n". + * The default value is: "u14-34f=lc:n,of:n,mq:8,et:n". + * An example using the list of detection probes could be: + * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n". * * When loading as a module, parameters can be specified as well. * The above example would be (use 1 in place of y and 0 in place of n): * * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \ - * max_queue_depth=4 use_new_eh_code=0 + * max_queue_depth=4 use_new_eh_code=0 ext_tran=0 * * ---------------------------------------------------------------------------- * In this implementation, linked commands are designed to work with any DISK @@ -314,6 +325,7 @@ MODULE_PARM(link_statistics, "i"); MODULE_PARM(max_queue_depth, "i"); MODULE_PARM(use_new_eh_code, "i"); +MODULE_PARM(ext_tran, "i"); MODULE_AUTHOR("Dario Ballabio"); #endif @@ -405,6 +417,7 @@ #undef DEBUG_RESET #undef DEBUG_GENERATE_ERRORS #undef DEBUG_GENERATE_ABORTS +#undef DEBUG_GEOMETRY #define MAX_ISA 3 #define MAX_VESA 1 @@ -556,6 +569,7 @@ static int do_trace = FALSE; static int setup_done = FALSE; static int link_statistics = 0; +static int ext_tran = FALSE; #if defined(HAVE_OLD_UX4F_FIRMWARE) static int have_old_firmware = TRUE; @@ -876,9 +890,9 @@ if (j == 0) { printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n"); - printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n", + printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n", driver_name, YESNO(have_old_firmware), YESNO(linked_comm), - max_queue_depth, YESNO(use_new_eh_code)); + max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran)); } printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n", @@ -922,6 +936,7 @@ else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; else if (!strncmp(cur, "ls:", 3)) link_statistics = val; else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val; + else if (!strncmp(cur, "et:", 3)) ext_tran = val; if ((cur = strchr(cur, ','))) ++cur; } @@ -1555,6 +1570,18 @@ dkinfo[0] = HD(j)->heads; dkinfo[1] = HD(j)->sectors; dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors); + + if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) { + dkinfo[0] = 255; + dkinfo[1] = 63; + dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); + } + +#if defined (DEBUG_GEOMETRY) + printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name, + dkinfo[0], dkinfo[1], dkinfo[2]); +#endif + return FALSE; } diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h --- v2.1.111/linux/drivers/scsi/u14-34f.h Sun Jun 7 11:16:35 1998 +++ linux/drivers/scsi/u14-34f.h Sun Jul 26 12:56:08 1998 @@ -4,6 +4,7 @@ #ifndef _U14_34F_H #define _U14_34F_H +#include #include int u14_34f_detect(Scsi_Host_Template *); @@ -15,7 +16,7 @@ int u14_34f_old_reset(Scsi_Cmnd *, unsigned int); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "4.32.00" +#define U14_34F_VERSION "4.33.00" #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c --- v2.1.111/linux/drivers/sound/msnd.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/msnd.c Sat Jul 25 18:48:29 1998 @@ -24,7 +24,6 @@ * ********************************************************************/ -#include #include #if LINUX_VERSION_CODE < 0x020101 # define LINUX20 diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd_classic.h linux/drivers/sound/msnd_classic.h --- v2.1.111/linux/drivers/sound/msnd_classic.h Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/msnd_classic.h Sat Jul 25 18:48:29 1998 @@ -30,6 +30,8 @@ #ifndef __MSND_CLASSIC_H #define __MSND_CLASSIC_H +#include + #define DSP_NUMIO 0x10 #define HP_MEMM 0x08 diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd_pinnacle.h linux/drivers/sound/msnd_pinnacle.h --- v2.1.111/linux/drivers/sound/msnd_pinnacle.h Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/msnd_pinnacle.h Sat Jul 25 18:48:29 1998 @@ -30,6 +30,8 @@ #ifndef __MSND_PINNACLE_H #define __MSND_PINNACLE_H +#include + #define DSP_NUMIO 0x08 #define HP_DSPR 0x04 diff -u --recursive --new-file v2.1.111/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.1.111/linux/drivers/video/Config.in Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/Config.in Sun Jul 26 14:40:19 1998 @@ -23,6 +23,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 + tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN fi fi if [ "$CONFIG_ATARI" = "y" ]; then @@ -32,8 +33,8 @@ if [ "$CONFIG_PPC" = "y" ]; then bool 'Open Firmware frame buffer device support' CONFIG_FB_OF if [ "$CONFIG_FB_OF" = "y" ]; then -# bool 'Apple "control" display support' CONFIG_FB_CONTROL -# bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM + bool 'Apple "control" display support' CONFIG_FB_CONTROL + bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM # bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE bool 'ATI Mach64 display support' CONFIG_FB_ATY # bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT @@ -69,7 +70,12 @@ if [ "$ARCH" = "sparc64" ]; then bool ' Creator/Creator3D support' CONFIG_FB_CREATOR fi - bool ' CGsix (GX,GXplus) support' CONFIG_FB_CGSIX + bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX + bool ' BWtwo support' CONFIG_FB_BWTWO + bool ' CGthree support' CONFIG_FB_CGTHREE + if [ "$ARCH" = "sparc" ]; then + bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX + fi fi fi if [ "$ARCH" = "sparc64" ]; then @@ -104,13 +110,15 @@ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \ - "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then define_bool CONFIG_FBCON_MFB y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \ - "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then define_bool CONFIG_FBCON_MFB m fi fi @@ -128,40 +136,50 @@ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \ - "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then + "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ - "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ - "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" ]; then + "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then define_bool CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ - "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" ]; then + "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then define_bool CONFIG_FBCON_CFB16 m fi fi - if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then + if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_CLGEN" = "y" ]; then define_bool CONFIG_FBCON_CFB24 y else - if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_CLGEN" = "m" ]; then define_bool CONFIG_FBCON_CFB24 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ - "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then + "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then define_bool CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ - "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then define_bool CONFIG_FBCON_CFB32 m fi fi @@ -202,14 +220,19 @@ fi fi fi + bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16 - bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 + fi bool 'Select other fonts' CONFIG_FBCON_FONTS if [ "$CONFIG_FBCON_FONTS" = "y" ]; then bool ' VGA 8x8 font' CONFIG_FONT_8x8 bool ' VGA 8x16 font' CONFIG_FONT_8x16 - bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + fi bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 fi @@ -219,15 +242,19 @@ bool ' VGA 8x8 font' CONFIG_FONT_8x8 bool ' VGA 8x16 font' CONFIG_FONT_8x16 bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16 - bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 - bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22 + bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11 + fi bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8 bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8 else define_bool CONFIG_FONT_8x8 y define_bool CONFIG_FONT_8x16 y if [ "$CONFIG_MAC" = "y" ]; then - define_bool CONFIG_FONT_6x11 y + if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then + define_bool CONFIG_FONT_6x11 y + fi fi if [ "$CONFIG_AMIGA" = "y" ]; then define_bool CONFIG_FONT_PEARL_8x8 y diff -u --recursive --new-file v2.1.111/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.1.111/linux/drivers/video/Makefile Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/Makefile Sun Jul 26 14:40:19 1998 @@ -30,13 +30,13 @@ endif ifeq ($(CONFIG_PROM_CONSOLE),y) - L_OBJS += promcon.o + L_OBJS += promcon.o promcon_tbl.o endif ifeq ($(CONFIG_FB),y) L_OBJS += fonts.o OX_OBJS += fbcon.o fbcmap.o -# fbgen is not compiled by default since nobody uses it yet +# fbgen is not compiled by default since nobody uses it yet, except clgenfb ifeq ($(CONFIG_FONT_8x8),y) L_OBJS += font_8x8.o endif @@ -94,6 +94,14 @@ L_OBJS += atyfb.o endif +ifeq ($(CONFIG_FB_CONTROL),y) +L_OBJS += controlfb.o +endif + +ifeq ($(CONFIG_FB_PLATINUM),y) +L_OBJS += platinumfb.o +endif + ifeq ($(CONFIG_FB_CT65550),y) L_OBJS += chipsfb.o endif @@ -126,6 +134,16 @@ endif endif +ifeq ($(CONFIG_FB_CLGEN),y) +L_OBJS += clgenfb.o +OX_OBJS += fbgen.o +else + ifeq ($(CONFIG_FB_CLGEN),m) + M_OBJS += clgenfb.o + OX_OBJS += fbgen.o + endif +endif + ifeq ($(CONFIG_FB_S3TRIO),y) L_OBJS += S3triofb.o else @@ -186,6 +204,27 @@ M_OBJS += cgsixfb.o endif endif + ifeq ($(CONFIG_FB_BWTWO),y) + L_OBJS += bwtwofb.o + else + ifeq ($(CONFIG_FB_BWTWO),m) + M_OBJS += bwtwofb.o + endif + endif + ifeq ($(CONFIG_FB_CGTHREE),y) + L_OBJS += cgthreefb.o + else + ifeq ($(CONFIG_FB_CGTHREE),m) + M_OBJS += cgthreefb.o + endif + endif + ifeq ($(CONFIG_FB_TCX),y) + L_OBJS += tcxfb.o + else + ifeq ($(CONFIG_FB_TCX),m) + M_OBJS += tcxfb.o + endif + endif else ifeq ($(CONFIG_FB_SBUS),m) M_OBJS += sbusfb.o @@ -203,6 +242,27 @@ M_OBJS += cgsixfb.o endif endif + ifeq ($(CONFIG_FB_BWTWO),y) + M_OBJS += bwtwofb.o + else + ifeq ($(CONFIG_FB_BWTWO),m) + M_OBJS += bwtwofb.o + endif + endif + ifeq ($(CONFIG_FB_CGTHREE),y) + M_OBJS += cgthreefb.o + else + ifeq ($(CONFIG_FB_CGTHREE),m) + M_OBJS += cgthreefb.o + endif + endif + ifeq ($(CONFIG_FB_TCX),y) + M_OBJS += tcxfb.o + else + ifeq ($(CONFIG_FB_TCX),m) + M_OBJS += tcxfb.o + endif + endif endif endif @@ -353,3 +413,10 @@ gspcore.c: gspcore.gsp $(GSPA) $< > $*.hex $(GSPH2C) $*.hex > gspcore.c + +promcon_tbl.c: prom.uni + ../char/conmakehash prom.uni | \ + sed -e '/#include <[^>]*>/p' -e 's/types/init/' \ + -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c + +promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h diff -u --recursive --new-file v2.1.111/linux/drivers/video/atafb.c linux/drivers/video/atafb.c --- v2.1.111/linux/drivers/video/atafb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/atafb.c Sun Jul 26 14:40:19 1998 @@ -47,6 +47,7 @@ #define ATAFB_EXT #define ATAFB_FALCON +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.1.111/linux/drivers/video/atyfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/atyfb.c Sun Jul 26 14:40:19 1998 @@ -1,7 +1,7 @@ /* * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * - * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1997-1998 Geert Uytterhoeven * Copyright (C) 1998 Bernd Harries * Copyright (C) 1998 Eddie C. Dost * @@ -26,26 +26,19 @@ TODO: - - support arbitrary video modes - (ecd): - - fix initialization and allocation of resources for cursor (and disp?). - - fix initialization of cursor timer. - - add code to detect ramdac type on initialization. - - add code to support cursor on all cards and all ramdacs. - make cursor parameters controllable via ioctl()s. - - handle arbitrary fonts. - (Anyone to help with all this?) ******************************************************************************/ + #include #include #include @@ -63,10 +56,15 @@ #include #include #include +#include +#include + #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif + #include + #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) #include #include @@ -80,157 +78,76 @@ #include "fbcon.h" #include "fbcon-cfb8.h" #include "fbcon-cfb16.h" +#include "fbcon-cfb24.h" #include "fbcon-cfb32.h" -#ifndef __powerpc__ -#define eieio() /* Enforce In-order Execution of I/O */ -#endif - -static int currcon = 0; -static struct display fb_disp; - -static char atyfb_name[16] = "ATY Mach64"; - -struct atyfb_par { - union { - /* this should contain chipset specific mode information */ - struct { - int vmode; - int cmode; - } gx, gt, vt; - } hw; - u_int vxres; /* virtual screen size */ - u_int vyres; - int xoffset; /* virtual screen position */ - int yoffset; - int accel; -}; - +#define GUI_RESERVE 0x00001000 -/* - * Video mode values. - * These are supposed to be the same as the values that - * Apple uses in MacOS. - */ -#define VMODE_NVRAM 0 /* use value stored in nvram */ -#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */ -#define VMODE_512_384_60 2 /* 512x384, 60Hz */ -#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */ -#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */ -#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */ -#define VMODE_640_480_67 6 /* 640x480, 67Hz */ -#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */ -#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */ -#define VMODE_800_600_56 9 /* 800x600, 56Hz */ -#define VMODE_800_600_60 10 /* 800x600, 60Hz */ -#define VMODE_800_600_72 11 /* 800x600, 72Hz */ -#define VMODE_800_600_75 12 /* 800x600, 75Hz */ -#define VMODE_832_624_75 13 /* 832x624, 75Hz */ -#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */ -#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */ -#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */ -#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */ -#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ -#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ -#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ -#define VMODE_MAX 20 -#define VMODE_CHOOSE 99 /* choose based on monitor sense */ +#define CLASS_GX 1 +#define CLASS_CT 2 +#define CLASS_VT 3 +#define CLASS_GT 4 -/* - * Color mode values, used to select number of bits/pixel. - */ -#define CMODE_NVRAM -1 /* use value stored in nvram */ -#define CMODE_8 0 /* 8 bits/pixel */ -#define CMODE_16 1 /* 16 (actually 15) bits/pixel */ -#define CMODE_32 2 /* 32 (actually 24) bits/pixel */ +#ifndef __powerpc__ +#define eieio() /* Enforce In-order Execution of I/O */ +#endif -static int default_vmode = VMODE_NVRAM; -static int default_cmode = CMODE_NVRAM; +/* FIXME: remove the FAIL definition */ +#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) -/* - * Addresses in NVRAM where video mode and pixel size are stored. - */ -#define NV_VMODE 0x140f -#define NV_CMODE 0x1410 -#endif /* CONFIG_PMAC || CONFIG_CHRP */ + /* + * Elements of the Hardware specific atyfb_par structure + */ -/* - * Horizontal and vertical resolution for each mode. - */ -static struct vmode_attr { - int hres; - int vres; - int vfreq; - int interlaced; -} vmode_attrs[VMODE_MAX] = { - {512, 384, 60, 1}, - {512, 384, 60}, - {640, 480, 50, 1}, - {640, 480, 60, 1}, - {640, 480, 60}, - {640, 480, 67}, - {640, 870, 75}, - {768, 576, 50, 1}, - {800, 600, 56}, - {800, 600, 60}, - {800, 600, 72}, - {800, 600, 75}, - {832, 624, 75}, - {1024, 768, 60}, - {1024, 768, 72}, - {1024, 768, 75}, - {1024, 768, 75}, - {1152, 870, 75}, - {1280, 960, 75}, - {1280, 1024, 75} +struct crtc { + u32 vxres; + u32 vyres; + u32 xoffset; + u32 yoffset; + u32 bpp; + u32 h_tot_disp; + u32 h_sync_strt_wid; + u32 v_tot_disp; + u32 v_sync_strt_wid; + u32 off_pitch; + u32 gen_cntl; + u32 dp_pix_width; /* acceleration */ + u32 dp_chain_mask; /* acceleration */ }; +struct pll_gx { + u8 m; + u8 n; +}; -/* - * We get a sense value from the monitor and use it to choose - * what resolution to use. This structure maps sense values - * to display mode values (which determine the resolution and - * frequencies). - */ -static struct mon_map { - int sense; - int vmode; -} monitor_map [] = { - {0x000, VMODE_1280_1024_75}, /* 21" RGB */ - {0x114, VMODE_640_870_75P}, /* Portrait Monochrome */ - {0x221, VMODE_512_384_60}, /* 12" RGB*/ - {0x331, VMODE_1280_1024_75}, /* 21" RGB (Radius) */ - {0x334, VMODE_1280_1024_75}, /* 21" mono (Radius) */ - {0x335, VMODE_1280_1024_75}, /* 21" mono */ - {0x40A, VMODE_640_480_60I}, /* NTSC */ - {0x51E, VMODE_640_870_75P}, /* Portrait RGB */ - {0x603, VMODE_832_624_75}, /* 12"-16" multiscan */ - {0x60b, VMODE_1024_768_70}, /* 13"-19" multiscan */ - {0x623, VMODE_1152_870_75}, /* 13"-21" multiscan */ - {0x62b, VMODE_640_480_67}, /* 13"/14" RGB */ - {0x700, VMODE_640_480_50I}, /* PAL */ - {0x714, VMODE_640_480_60I}, /* NTSC */ - {0x717, VMODE_800_600_75}, /* VGA */ - {0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */ - {0x730, VMODE_768_576_50I}, /* PAL (Alternate) */ - {0x73a, VMODE_1152_870_75}, /* 3rd party 19" */ - {0x73f, VMODE_640_480_67}, /* no sense lines connected at all */ - {-1, VMODE_640_480_60}, /* catch-all, must be last */ +struct pll_ct { + u8 pll_ref_div; + u8 pll_gen_cntl; + u8 mclk_fb_div; + u8 pll_vclk_cntl; + u8 vclk_post_div; + u8 vclk_fb_div; + u8 pll_ext_cntl; + u32 dsp_config; /* Mach64 GTB DSP */ + u32 dsp_on_off; /* Mach64 GTB DSP */ }; -static int map_monitor_sense(int sense) -{ - struct mon_map *map; - for (map = monitor_map; map->sense >= 0; ++map) - if (map->sense == sense) - break; - return map->vmode; -} + /* + * The Hardware parameters for each card + */ + +struct atyfb_par { + struct crtc crtc; + union { + struct pll_gx gx; + struct pll_ct ct; + } pll; + u32 accel_flags; +}; struct aty_cmap_regs { u8 windex; @@ -240,27 +157,6 @@ u8 cntl; }; -typedef struct aty_regvals { - u32 offset[3]; /* first pixel address */ - - u32 crtc_h_sync_strt_wid[3]; /* depth dependent */ - u32 crtc_gen_cntl[3]; - u32 mem_cntl[3]; - - u32 crtc_h_tot_disp; /* mode dependent */ - u32 crtc_v_tot_disp; - u32 crtc_v_sync_strt_wid; - u32 crtc_off_pitch; - - u8 clock_val[2]; /* vals for 20 and 21 */ -} aty_regvals; - -struct rage_regvals { - u32 h_total, h_sync_start, h_sync_width; - u32 v_total, v_sync_start, v_sync_width; - u32 h_sync_neg, v_sync_neg; -}; - struct pci_mmap_map { unsigned long voff; unsigned long poff; @@ -272,18 +168,18 @@ #define DEFAULT_CURSOR_BLINK_RATE (20) struct aty_cursor { - int enable; - int on; - int vbl_cnt; - int blink_rate; - u32 offset; - struct { - u16 x, y; - } pos, hot, size; - u32 color[2]; - u8 bits[8][64]; - u8 mask[8][64]; - struct timer_list *timer; + int enable; + int on; + int vbl_cnt; + int blink_rate; + u32 offset; + struct { + u16 x, y; + } pos, hot, size; + u32 color[2]; + u8 bits[8][64]; + u8 mask[8][64]; + struct timer_list *timer; }; struct fb_info_aty { @@ -292,144 +188,49 @@ unsigned long ati_regbase; unsigned long frame_buffer_phys; unsigned long frame_buffer; + struct display disp; + struct display_switch dispsw; struct pci_mmap_map *mmap_map; struct aty_cursor *cursor; - u8 chip_class; - u8 pixclock_lim_8; /* ps, <= 8 bpp */ - u8 pixclock_lim_hi; /* ps, > 8 bpp */ - u32 total_vram; struct aty_cmap_regs *aty_cmap_regs; struct { u8 red, green, blue, pad; } palette[256]; struct atyfb_par default_par; struct atyfb_par current_par; -}; - -#ifdef CONFIG_ATARI -static unsigned int mach64_count __initdata = 0; -static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; -static unsigned long phys_size[FB_MAX] __initdata = { 0, }; -static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; -#endif - -static int aty_vram_reqd(const struct atyfb_par *par); -static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info); - -#include "ati-gx.h" -#include "ati-gt.h" -#include "ati-vt.h" - -static struct aty_regvals *aty_gt_reg_init[20] = { - NULL, NULL, NULL, NULL, - &aty_gt_reg_init_5, - &aty_gt_reg_init_6, - NULL, NULL, - &aty_gt_reg_init_9, - &aty_gt_reg_init_10, - &aty_gt_reg_init_11, - &aty_gt_reg_init_12, - &aty_gt_reg_init_13, - &aty_gt_reg_init_14, - &aty_gt_reg_init_15, - NULL, - &aty_gt_reg_init_17, - &aty_gt_reg_init_18, - NULL, - &aty_gt_reg_init_20 -}; - -static struct aty_regvals *aty_gx_reg_init[20] = { - NULL, NULL, NULL, NULL, - &aty_gx_reg_init_6, - &aty_gx_reg_init_6, - NULL, NULL, NULL, NULL, NULL, NULL, - &aty_gx_reg_init_13, - &aty_gx_reg_init_14, - &aty_gx_reg_init_15, - NULL, - &aty_gx_reg_init_17, - &aty_gx_reg_init_18, - NULL, - &aty_gx_reg_init_20 -}; - -static struct aty_regvals *aty_vt_reg_init[21] = { - NULL, NULL, NULL, NULL, - &aty_vt_reg_init_5, - &aty_vt_reg_init_6, - NULL, NULL, NULL, - &aty_vt_reg_init_10, - &aty_vt_reg_init_11, - &aty_vt_reg_init_12, - &aty_vt_reg_init_13, - &aty_vt_reg_init_14, - &aty_vt_reg_init_15, - NULL, - &aty_vt_reg_init_17, - &aty_vt_reg_init_18, - &aty_vt_reg_init_19, - &aty_vt_reg_init_20 -}; - - -#define CLASS_GX 1 -#define CLASS_CT 2 -#define CLASS_VT 3 -#define CLASS_GT 4 - -struct aty_features { - u16 pci_id; + u32 total_vram; + u32 pll_per; + u32 mclk_per; u16 chip_type; - const char *name; - u8 chip_class; - u8 pixclock_lim_8; /* MHz, <= 8 bpp (not sure about these limits!) */ - u8 pixclock_lim_hi; /* MHz, > 8 bpp (not sure about these limits!) */ -} aty_features[] __initdata = { - /* mach64GX family */ - { 0x4758, 0x00d7, "mach64GX (ATI888GX00)", CLASS_GX, 135, 80 }, - { 0x4358, 0x0057, "mach64CX (ATI888CX00)", CLASS_GX, 135, 80 }, - - /* mach64CT family */ - { 0x4354, 0x4354, "mach64CT (ATI264CT)", CLASS_CT, 135, 80 }, - { 0x4554, 0x4554, "mach64ET (ATI264ET)", CLASS_CT, 135, 80 }, - - /* mach64CT family / mach64VT class */ - { 0x5654, 0x5654, "mach64VT (ATI264VT)", CLASS_VT, 160, 135 }, - { 0x5655, 0x5655, "mach64VTB (ATI264VTB)", CLASS_VT, 160, 135 }, - { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)", CLASS_VT, 160, 135 }, - - /* mach64CT family / mach64GT (3D RAGE) class */ - { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)", CLASS_GT, 240, 240 }, - { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)", CLASS_GT, 240, 240 }, - { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)", CLASS_GT, 240, 240 }, - { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)", CLASS_GT, 240, 240 }, - { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)", CLASS_GT, 240, 240 }, - { 0x4754, 0x4754, "3D RAGE (GT)", CLASS_GT, 200, 200 }, - { 0x4755, 0x4755, "3D RAGE II+ (GTB)", CLASS_GT, 200, 200 }, - { 0x4756, 0x4756, "3D RAGE IIC", CLASS_GT, 200, 200 }, - { 0x4c47, 0x4c47, "3D RAGE LT", CLASS_GT, 200, 200 }, +#define Gx info->chip_type + u8 chip_rev; +#define Rev info->chip_rev + u8 bus_type; + u8 ram_type; + u8 dac_type; + u8 clk_type; + u8 mem_refresh_rate; +#ifdef __sparc__ + u8 open; + u8 mmaped; + int vtconsole; + int consolecnt; +#endif }; /* - * Interface used by the world + * Frame buffer device API */ -void atyfb_init(void); -#ifdef CONFIG_FB_OF -void atyfb_of_init(struct device_node *dp); -#endif -void atyfb_setup(char *options, int *ints); - static int atyfb_open(struct fb_info *info, int user); static int atyfb_release(struct fb_info *info, int user); static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); + struct fb_info *fb); static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -446,23 +247,50 @@ * Interface to the low level console driver */ -static int atyfbcon_switch(int con, struct fb_info *info); -static int atyfbcon_updatevar(int con, struct fb_info *info); -static void atyfbcon_blank(int blank, struct fb_info *info); +static int atyfbcon_switch(int con, struct fb_info *fb); +static int atyfbcon_updatevar(int con, struct fb_info *fb); +static void atyfbcon_blank(int blank, struct fb_info *fb); /* * Text console acceleration */ +static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); #ifdef FBCON_HAS_CFB8 static struct display_switch fbcon_aty8; +static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); #endif #ifdef FBCON_HAS_CFB16 static struct display_switch fbcon_aty16; +static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); +#endif +#ifdef FBCON_HAS_CFB24 +static struct display_switch fbcon_aty24; +static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); #endif #ifdef FBCON_HAS_CFB32 static struct display_switch fbcon_aty32; +static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); #endif @@ -476,12 +304,72 @@ static char *strtoke(char *s, const char *ct); #endif +static void reset_engine(const struct fb_info_aty *info); +static void init_engine(const struct atyfb_par *par, + const struct fb_info_aty *info); +static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info); +static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); +static void aty_set_crtc(const struct fb_info_aty *info, + const struct crtc *crtc); +static int aty_var_to_crtc(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct crtc *crtc); +static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp); +static int aty_crtc_to_var(const struct crtc *crtc, + struct fb_var_screeninfo *var); +static void aty_set_pll_gx(const struct fb_info_aty *info, + const struct pll_gx *pll); +static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, + struct pll_gx *pll); +static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, + struct pll_gx *pll); +static int aty_pll_gx_to_var(const struct pll_gx *pll, + struct fb_var_screeninfo *var); +static void aty_set_pll_ct(const struct fb_info_aty *info, + const struct pll_ct *pll); +static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, + u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div, + u8 bpp, struct pll_ct *pll); +static int aty_var_to_pll_ct(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct pll_ct *pll); +static int aty_pll_ct_to_var(const struct pll_ct *pll, + struct fb_var_screeninfo *var); +static void atyfb_set_par(const struct atyfb_par *par, + struct fb_info_aty *info); +static int atyfb_decode_var(const struct fb_var_screeninfo *var, + struct atyfb_par *par, + const struct fb_info_aty *info); +static int atyfb_encode_var(struct fb_var_screeninfo *var, + const struct atyfb_par *par, + const struct fb_info_aty *info); +static void set_off_pitch(struct atyfb_par *par, + const struct fb_info_aty *info); +static int encode_fix(struct fb_fix_screeninfo *fix, + const struct atyfb_par *par, + const struct fb_info_aty *info); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); + u_int *transp, struct fb_info *fb); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); + u_int transp, struct fb_info *fb); static void do_install_cmap(int con, struct fb_info *info); +#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +static int read_aty_sense(const struct fb_info_aty *info); +#endif + + + /* + * Interface used by the world + */ + +void atyfb_init(void); +#ifdef CONFIG_FB_OF +void atyfb_of_init(struct device_node *dp); +#endif +void atyfb_setup(char *options, int *ints); + +static int currcon = 0; static struct fb_ops atyfb_ops = { atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var, @@ -493,64 +381,110 @@ #endif }; +static char atyfb_name[16] = "ATY Mach64"; +static char fontname[40] __initdata = { 0 }; + +static const u32 ref_clk_per = 1000000000000ULL/14318180; + +#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +#endif + +#ifdef CONFIG_ATARI +static unsigned int mach64_count __initdata = 0; +static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; +static unsigned long phys_size[FB_MAX] __initdata = { 0, }; +static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; +#endif + + +static struct aty_features { + u16 pci_id; + u16 chip_type; + const char *name; +} aty_features[] __initdata = { + /* mach64GX family */ + { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" }, + { 0x4358, 0x0057, "mach64CX (ATI888CX00)" }, + + /* mach64CT family */ + { 0x4354, 0x4354, "mach64CT (ATI264CT)" }, + { 0x4554, 0x4554, "mach64ET (ATI264ET)" }, + + /* mach64CT family / mach64VT class */ + { 0x5654, 0x5654, "mach64VT (ATI264VT)" }, + { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" }, +/* { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */ + + /* mach64CT family / mach64GT (3D RAGE) class */ + { 0x4c54, 0x4c54, "3D RAGE LT" }, + { 0x4c47, 0x4c47, "3D RAGE LG" }, + { 0x4754, 0x4754, "3D RAGE (GT)" }, + { 0x4755, 0x4755, "3D RAGE II+ (GTB)" }, +/* { 0x4756, 0x4756, "3D RAGE IIC" }, */ + { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" }, + { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" }, + { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, + { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" }, + { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, +}; -static inline int aty_vram_reqd(const struct atyfb_par *par) -{ - return (par->vxres*par->vyres) << par->hw.gx.cmode; -} static inline u32 aty_ld_le32(volatile unsigned int regindex, - struct fb_info_aty *info) + const struct fb_info_aty *info) { unsigned long temp; u32 val; -#ifdef __powerpc__ +#if defined(__powerpc__) temp = info->ati_regbase; - asm("lwbrx %0,%1,%2": "=r"(val):"r"(regindex), "r"(temp)); -#else -#ifdef __sparc__v9__ + asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp)); +#elif defined(__sparc_v9__) temp = info->ati_regbase + regindex; asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL)); #else temp = info->ati_regbase+regindex; val = le32_to_cpu(*((volatile u32 *)(temp))); #endif -#endif return val; } static inline void aty_st_le32(volatile unsigned int regindex, u32 val, - struct fb_info_aty *info) + const struct fb_info_aty *info) { unsigned long temp; -#ifdef __powerpc__ +#if defined(__powerpc__) temp = info->ati_regbase; - asm("stwbrx %0,%1,%2": : "r"(val), "r"(regindex), "r"(temp):"memory"); -#else -#ifdef __sparc__v9__ + asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) : + "memory"); +#elif defined(__sparc_v9__) temp = info->ati_regbase + regindex; - asm("stwa %0, [%1] %2" : "r" (val), "r" (temp), "i" (ASI_PL) : "memory"); + asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory"); #else temp = info->ati_regbase+regindex; *((volatile u32 *)(temp)) = cpu_to_le32(val); #endif -#endif } static inline u8 aty_ld_8(volatile unsigned int regindex, - struct fb_info_aty *info) + const struct fb_info_aty *info) { return *(volatile u8 *)(info->ati_regbase+regindex); } static inline void aty_st_8(volatile unsigned int regindex, u8 val, - struct fb_info_aty *info) + const struct fb_info_aty *info) { *(volatile u8 *)(info->ati_regbase+regindex) = val; } + + /* + * Generic Mach64 routines + */ + /* * All writes to draw engine registers are automatically routed through a * 32-bit-wide, 16-entry-deep command FIFO ... @@ -559,19 +493,19 @@ * (from Chapter 5 of the Mach64 Programmer's Guide) */ -static inline void wait_for_fifo(u16 entries, struct fb_info_aty *info) +static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info) { while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > ((u32)(0x8000 >> entries))); } -static inline void wait_for_idle(struct fb_info_aty *info) +static inline void wait_for_idle(const struct fb_info_aty *info) { wait_for_fifo(16, info); while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0); } -static void reset_engine(struct fb_info_aty *info) +static void reset_engine(const struct fb_info_aty *info) { /* reset engine */ aty_st_le32(GEN_TEST_CNTL, @@ -585,20 +519,19 @@ BUS_FIFO_ERR_ACK, info); } -static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) +static void init_engine(const struct atyfb_par *par, + const struct fb_info_aty *info) { u32 pitch_value; /* determine modal information from global mode structure */ - pitch_value = par->vxres; + pitch_value = par->crtc.vxres; -#if 0 - if (par->hw.gx.cmode == CMODE_24) { + if (par->crtc.bpp == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ /* horizontal coordinates and widths must be adjusted */ pitch_value = pitch_value * 3; } -#endif /* Reset engine, enable, and clear any engine errors */ reset_engine(info); @@ -655,7 +588,7 @@ /* set scissors to modal size */ aty_st_le32(SC_LEFT, 0, info); aty_st_le32(SC_TOP, 0, info); - aty_st_le32(SC_BOTTOM, par->vyres-1, info); + aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info); aty_st_le32(SC_RIGHT, pitch_value-1, info); /* set background color to minimum value (usually BLACK) */ @@ -684,48 +617,18 @@ /* set pixel depth */ wait_for_fifo(2, info); - switch(par->hw.gx.cmode) { -#ifdef FBCON_HAS_CFB8 - case CMODE_8: - aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP | - BYTE_ORDER_LSB_TO_MSB, - info); - aty_st_le32(DP_CHAIN_MASK, 0x8080, info); - break; -#endif -#ifdef FBCON_HAS_CFB16 - case CMODE_16: - aty_st_le32(DP_PIX_WIDTH, HOST_15BPP | SRC_15BPP | DST_15BPP | - BYTE_ORDER_LSB_TO_MSB, - info); - aty_st_le32(DP_CHAIN_MASK, 0x4210, info); - break; -#endif -#if 0 - case CMODE_24: - aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP | - BYTE_ORDER_LSB_TO_MSB, - info); - aty_st_le32(DP_CHAIN_MASK, 0x8080, info); - break; -#endif -#ifdef FBCON_HAS_CFB32 - case CMODE_32: - aty_st_le32(DP_PIX_WIDTH, HOST_32BPP | SRC_32BPP | DST_32BPP | - BYTE_ORDER_LSB_TO_MSB, info); - aty_st_le32(DP_CHAIN_MASK, 0x8080, info); - break; -#endif - } + aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info); + aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info); + /* insure engine is idle before leaving */ wait_for_idle(info); } -static void aty_st_514(int offset, u8 val, struct fb_info_aty *info) +static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info) { aty_st_8(DAC_CNTL, 1, info); /* right addr byte */ - aty_st_8(DAC_W_INDEX, offset & 0xff, info); + aty_st_8(DAC_W_INDEX, offset & 0xff, info); /* left addr byte */ aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info); eieio(); @@ -734,7 +637,7 @@ aty_st_8(DAC_CNTL, 0, info); } -static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info) +static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) { /* write addr byte */ aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); @@ -745,28 +648,28 @@ aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); } -static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info) +#if 0 /* ecd debug */ +static u8 aty_ld_pll(int offset, const struct fb_info_aty *info) { - int v = vmode - 1; + u8 val; - switch (info->chip_class) { - case CLASS_GX: - return aty_gx_reg_init[v]; - break; - case CLASS_CT: - case CLASS_VT: - return aty_vt_reg_init[v]; - break; - case CLASS_GT: - return aty_gt_reg_init[v]; - break; - default: - /* should NOT happen */ - return NULL; - } + /* write addr byte */ + aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); + eieio(); + /* read the register value */ + val = aty_ld_8(CLOCK_CNTL + 2, info); + eieio(); + return val; } +#endif /* ecd debug */ + +#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) + + /* + * Apple monitor sense + */ -static int read_aty_sense(struct fb_info_aty *info) +static int read_aty_sense(const struct fb_info_aty *info) { int sense, i; @@ -800,50 +703,13 @@ return sense; } -static void RGB514_Program(int cmode, struct fb_info_aty *info) -{ - typedef struct { - u8 pixel_dly; - u8 misc2_cntl; - u8 pixel_rep; - u8 pixel_cntl_index; - u8 pixel_cntl_v1; - } RGB514_DAC_Table; - - static RGB514_DAC_Table RGB514DAC_Tab[8] = { - {0, 0x41, 0x03, 0x71, 0x45}, /* 8bpp */ - {0, 0x45, 0x04, 0x0c, 0x01}, /* 555 */ - {0, 0x45, 0x06, 0x0e, 0x00}, /* XRGB */ - }; - RGB514_DAC_Table *pDacProgTab; - - pDacProgTab = &RGB514DAC_Tab[cmode]; - - aty_st_514(0x90, 0x00, info); - aty_st_514(0x04, pDacProgTab->pixel_dly, info); - aty_st_514(0x05, 0x00, info); - - aty_st_514(0x2, 0x1, info); - aty_st_514(0x71, pDacProgTab->misc2_cntl, info); - aty_st_514(0x0a, pDacProgTab->pixel_rep, info); - - aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1, - info); -} - -static void set_off_pitch(const struct atyfb_par *par, - struct fb_info_aty *info) -{ - u32 pitch, offset; +#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */ - pitch = par->vxres>>3; - offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<hw.gx.cmode; - aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset, info); -} +/* ------------------------------------------------------------------------- */ -/* - * Hardware Cursor support. - */ + /* + * Hardware Cursor support. + */ static u8 cursor_pixel_map[2] = { 0, 15 }; static u8 cursor_color_map[2] = { 0, 0xff }; @@ -870,6 +736,11 @@ if (!c) return; +#ifdef __sparc__ + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + for (i = 0; i < 2; i++) { c->color[i] = (u32)red[i] << 24; c->color[i] |= (u32)green[i] << 16; @@ -880,7 +751,6 @@ wait_for_fifo(2, fb); aty_st_le32(CUR_CLR0, c->color[0], fb); aty_st_le32(CUR_CLR1, c->color[1], fb); - wait_for_idle(fb); } static void @@ -893,6 +763,11 @@ if (!c) return; +#ifdef __sparc__ + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + ram = (u8 *)(fb->frame_buffer + c->offset); for (y = 0; y < c->size.y; y++) { @@ -922,6 +797,11 @@ if (!c) return; +#ifdef __sparc__ + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + if (c->on) { x = c->pos.x - c->hot.x; if (x < 0) { @@ -952,7 +832,6 @@ aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE, fb); } - wait_for_idle(fb); } static void @@ -986,6 +865,11 @@ if (!c) return; +#ifdef __sparc__ + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + x *= d->fontwidth; y *= d->fontheight; if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on) @@ -1061,425 +945,799 @@ } -static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info) -{ - int i, j = 0, hres; - struct aty_regvals *init = get_aty_struct(par->hw.gx.vmode, info); - int vram_type = aty_ld_le32(CONFIG_STAT0, info) & 7; - - if (init == 0) /* paranoia, shouldn't get here */ - panic("aty: display mode %d not supported", par->hw.gx.vmode); - - info->current_par = *par; - hres = vmode_attrs[par->hw.gx.vmode-1].hres; - - if (info->chip_class != CLASS_GT) { - i = aty_ld_le32(CRTC_GEN_CNTL, info); - aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN, info); - } - - if (info->chip_class == CLASS_GX) { - i = aty_ld_le32(GEN_TEST_CNTL, info); - aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN, info); - } - - switch (info->chip_class) { - case CLASS_GX: - RGB514_Program(par->hw.gx.cmode, info); - wait_for_idle(info); - aty_st_514(0x06, 0x02, info); - aty_st_514(0x10, 0x01, info); - aty_st_514(0x70, 0x01, info); - aty_st_514(0x8f, 0x1f, info); - aty_st_514(0x03, 0x00, info); - aty_st_514(0x05, 0x00, info); - aty_st_514(0x20, init->clock_val[0], info); - aty_st_514(0x21, init->clock_val[1], info); - break; - case CLASS_CT: - case CLASS_VT: - aty_st_pll(VPLL_CNTL, 0xb5, info); - aty_st_pll(PLL_REF_DIV, 0x2d, info); - aty_st_pll(PLL_GEN_CNTL, 0x14, info); - aty_st_pll(MCLK_FB_DIV, 0xbd, info); - aty_st_pll(PLL_VCLK_CNTL, 0x0b, info); - aty_st_pll(VCLK_POST_DIV, init->clock_val[0], info); - aty_st_pll(VCLK0_FB_DIV, init->clock_val[1], info); - aty_st_pll(VCLK1_FB_DIV, 0xd6, info); - aty_st_pll(VCLK2_FB_DIV, 0xee, info); - aty_st_pll(VCLK3_FB_DIV, 0xf8, info); - aty_st_pll(PLL_EXT_CNTL, 0x0, info); - aty_st_pll(PLL_TEST_CTRL, 0x0, info); - aty_st_pll(PLL_TEST_COUNT, 0x0, info); - break; - case CLASS_GT: - if (vram_type == 5) { - aty_st_pll(MPLL_CNTL, 0xcd, info); - aty_st_pll(VPLL_CNTL, - par->hw.gx.vmode >= VMODE_1024_768_60 ? 0xd3 - : 0xd5, - info); - aty_st_pll(PLL_REF_DIV, 0x21, info); - aty_st_pll(PLL_GEN_CNTL, 0x44, info); - aty_st_pll(MCLK_FB_DIV, 0xe8, info); - aty_st_pll(PLL_VCLK_CNTL, 0x03, info); - aty_st_pll(VCLK_POST_DIV, init->offset[0], info); - aty_st_pll(VCLK0_FB_DIV, init->offset[1], info); - aty_st_pll(VCLK1_FB_DIV, 0x8e, info); - aty_st_pll(VCLK2_FB_DIV, 0x9e, info); - aty_st_pll(VCLK3_FB_DIV, 0xc6, info); - aty_st_pll(PLL_EXT_CNTL, init->offset[2], info); - aty_st_pll(DLL_CNTL, 0xa6, info); - aty_st_pll(VFC_CNTL, 0x1b, info); - } else { - aty_st_pll(VPLL_CNTL, 0xd5, info); - aty_st_pll(PLL_REF_DIV, 0x21, info); - aty_st_pll(PLL_GEN_CNTL, 0xc4, info); - aty_st_pll(MCLK_FB_DIV, 0xda, info); - aty_st_pll(PLL_VCLK_CNTL, 0x03, info); - /* offset actually holds clock values */ - aty_st_pll(VCLK_POST_DIV, init->offset[0], info); - aty_st_pll(VCLK0_FB_DIV, init->offset[1], info); - aty_st_pll(VCLK1_FB_DIV, 0x8e, info); - aty_st_pll(VCLK2_FB_DIV, 0x9e, info); - aty_st_pll(VCLK3_FB_DIV, 0xc6, info); - aty_st_pll(PLL_TEST_CTRL, 0x0, info); - aty_st_pll(PLL_EXT_CNTL, init->offset[2], info); - aty_st_pll(DLL_CNTL, 0xa0, info); - aty_st_pll(VFC_CNTL, 0x1b, info); - } - break; - } - aty_ld_8(DAC_REGS, info); /* clear counter */ - wait_for_idle(info); - aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp, info); - aty_st_le32(CRTC_H_SYNC_STRT_WID, - init->crtc_h_sync_strt_wid[par->hw.gx.cmode], info); - aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp, info); - aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid, info); +/* ------------------------------------------------------------------------- */ - aty_st_8(CLOCK_CNTL, 0, info); - aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info); + /* + * CRTC programming + */ +static void aty_set_crtc(const struct fb_info_aty *info, + const struct crtc *crtc) +{ + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info); aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); + aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info); + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info); +} - set_off_pitch(par, info); - - switch (info->chip_class) { - case CLASS_GX: - /* The magic constant below translates into: - * 5 = No RDY delay, 1 wait st for mem write, increment during - * burst transfer - * 9 = DAC access delayed, 1 wait state for DAC - * 0 = Disables interupts for FIFO errors - * e = Allows FIFO to generate 14 wait states before generating - * error - * 1 = DAC snooping disabled, ROM disabled - * 0 = ROM page at 0 (disabled so doesn't matter) - * f = 15 ROM wait states (disabled so doesn't matter) - * f = 15 BUS wait states (I'm not sure this applies to PCI bus - * types) - * at some point it would be good to experiment with bench marks to - * if we can gain some speed by fooling with the wait states etc. - */ - aty_st_le32(BUS_CNTL, 0x890e20f1 /* 0x590e10ff */, info); - j = 0x47012100; - j = 0x47052100; - break; - - case CLASS_VT: - if (vram_type == 4) { - /* - * What to do here? - The contents of MEM_CNTL do not - * seem to match my documentation, and touching this - * register makes the output unusable. - * (green bars across the screen and similar effects). - * - * Eddie C. Dost (ecd@skynet.be) - */ - j = 0x87010184; - break; - } - /* fallthrough */ +static int aty_var_to_crtc(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct crtc *crtc) +{ + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 left, right, upper, lower, hslen, vslen, sync, vmode; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol; + u32 pix_width, dp_pix_width, dp_chain_mask; + + /* input */ + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + xoffset = var->xoffset; + yoffset = var->yoffset; + bpp = var->bits_per_pixel; + left = var->left_margin; + right = var->right_margin; + upper = var->upper_margin; + lower = var->lower_margin; + hslen = var->hsync_len; + vslen = var->vsync_len; + sync = var->sync; + vmode = var->vmode; + + /* convert (and round up) and validate */ + xres = (xres+7) & ~7; + xoffset = (xoffset+7) & ~7; + vxres = (vxres+7) & ~7; + if (vxres < xres+xoffset) + vxres = xres+xoffset; + h_disp = xres/8-1; + if (h_disp > 0xff) + FAIL("h_disp too large"); + h_sync_strt = h_disp+(right/8); + if (h_sync_strt > 0x1ff) + FAIL("h_sync_start too large"); + h_sync_dly = right & 7; + h_sync_wid = (hslen+7)/8; + if (h_sync_wid > 0x1f) + FAIL("h_sync_wid too large"); + h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8; + if (h_total > 0x1ff) + FAIL("h_total too large"); + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + + if (vyres < yres+yoffset) + vyres = yres+yoffset; + v_disp = yres-1; + if (v_disp > 0x7ff) + FAIL("v_disp too large"); + v_sync_strt = v_disp+lower; + if (v_sync_strt > 0x7ff) + FAIL("v_sync_strt too large"); + v_sync_wid = vslen; + if (v_sync_wid > 0x1f) + FAIL("v_sync_wid too large"); + v_total = v_sync_strt+v_sync_wid+upper; + if (v_total > 0x7ff) + FAIL("v_total too large"); + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + if (bpp <= 8) { + bpp = 8; + pix_width = CRTC_PIX_WIDTH_8BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else if (bpp <= 16) { + bpp = 16; + pix_width = CRTC_PIX_WIDTH_15BPP; + dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x4210; + } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { + bpp = 24; + pix_width = CRTC_PIX_WIDTH_24BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else if (bpp <= 32) { + bpp = 32; + pix_width = CRTC_PIX_WIDTH_32BPP; + dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; + } else + FAIL("invalid bpp"); - case CLASS_CT: - aty_st_le32(BUS_CNTL, 0x680000f9, info); - switch (info->total_vram) { - case 0x00100000: - aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->hw.gx.cmode], - info); - break; - case 0x00200000: - aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->hw.gx.cmode], - info); - break; - case 0x00400000: - aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->hw.gx.cmode], - info); - break; - default: - i = aty_ld_le32(MEM_CNTL, info) & 0x000F; - aty_st_le32(MEM_CNTL, - (init->mem_cntl[par->hw.gx.cmode] & - 0xFFFFFFF0) | i, - info); - } - j = 0x87010184; - break; + if (vxres*vyres*bpp/8 > info->total_vram) + FAIL("not enough video RAM"); - case CLASS_GT: - aty_st_le32(BUS_CNTL, 0x7b23a040, info); + if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + FAIL("invalid vmode"); - /* need to set DSP values !! assume sdram */ - i = init->crtc_gen_cntl[0] - (0x100000 * par->hw.gx.cmode); - if ( vram_type == 5 ) - i = init->crtc_gen_cntl[1] - (0x100000 * par->hw.gx.cmode); - aty_st_le32(DSP_CONFIG, i, info); - - i = aty_ld_le32(MEM_CNTL, info) & MEM_SIZE_ALIAS; - if ( vram_type == 5 ) { - i |= ((1 * par->hw.gx.cmode) << 26) | 0x4215b0; - aty_st_le32(DSP_ON_OFF, - sgram_dsp[par->hw.gx.vmode-1][par->hw.gx.cmode], - info); + /* output */ + crtc->vxres = vxres; + crtc->vyres = vyres; + crtc->xoffset = xoffset; + crtc->yoffset = yoffset; + crtc->bpp = bpp; + crtc->h_tot_disp = h_total | (h_disp<<16); + crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | + ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | + (h_sync_pol<<21); + crtc->v_tot_disp = v_total | (v_disp<<16); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); + crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + crtc->gen_cntl = pix_width | CRTC_EXT_DISP_EN | CRTC_ENABLE; + if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) || + ((Gx == VT_CHIP_ID) && !(Rev & 0x03)) || + ((Gx == GT_CHIP_ID) && !(Rev & 0x03))) { + /* Not VTB/GTB */ + /* FIXME: magic FIFO values */ + crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; + } + crtc->dp_pix_width = dp_pix_width; + crtc->dp_chain_mask = dp_chain_mask; - /* aty_st_le32(CLOCK_CNTL, 8192, info); */ - } else { - i |= ((1 * par->hw.gx.cmode) << 26) | 0x300090; - aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->hw.gx.cmode], - info); - } - aty_st_le32(MEM_CNTL, i, info); - aty_st_le32(EXT_MEM_CNTL, 0x5000001, info); + return 0; +} - /* if (info->total_vram > 0x400000) - i |= 0x538; this not been verified on > 4Megs!! */ +static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp) +{ + static struct { + u8 pixel_dly; + u8 misc2_cntl; + u8 pixel_rep; + u8 pixel_cntl_index; + u8 pixel_cntl_v1; + } tab[3] = { + { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */ + { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */ + { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */ + }; + int i; - j = 0x86010102; + switch (bpp) { + case 8: + default: + i = 0; + break; + case 16: + i = 1; + break; + case 32: + i = 2; break; } + aty_st_514(0x90, 0x00, info); /* VRAM Mask Low */ + aty_st_514(0x04, tab[i].pixel_dly, info); /* Horizontal Sync Control */ + aty_st_514(0x05, 0x00, info); /* Power Management */ + aty_st_514(0x02, 0x01, info); /* Misc Clock Control */ + aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */ + aty_st_514(0x0a, tab[i].pixel_rep, info); /* Pixel Format */ + aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info); + /* Misc Control 2 / 16 BPP Control / 32 BPP Control */ +} + +static int aty_crtc_to_var(const struct crtc *crtc, + struct fb_var_screeninfo *var) +{ + u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol; + u32 pix_width; + + /* input */ + h_total = crtc->h_tot_disp & 0x1ff; + h_disp = (crtc->h_tot_disp>>16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | + ((crtc->h_sync_strt_wid>>4) & 0x100); + h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; + h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; + v_total = crtc->v_tot_disp & 0x7ff; + v_disp = (crtc->v_tot_disp>>16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + + /* convert */ + xres = (h_disp+1)*8; + yres = v_disp+1; + left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; + right = (h_sync_strt-h_disp)*8; + hslen = h_sync_wid*8; + upper = v_total-v_sync_strt-v_sync_wid; + lower = v_sync_strt-v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT); - /* These magic constants (variable j) are harder to figure out - * on the vt chipset bit 2 set makes the screen brighter - * and bit 15 makes the screen black! But nothing else - * seems to matter for the vt DAC_CNTL - */ - aty_st_le32(DAC_CNTL, j, info); - aty_st_8(DAC_MASK, 0xff, info); - - switch (par->hw.gx.cmode) { - case CMODE_16: - i = CRTC_PIX_WIDTH_15BPP; break; - /*case CMODE_24: */ - case CMODE_32: - i = CRTC_PIX_WIDTH_32BPP; break; - case CMODE_8: + switch (pix_width) { +#if 0 + case CRTC_PIX_WIDTH_4BPP: + bpp = 4; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_8BPP: + bpp = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ + bpp = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; +#if 0 + case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ + bpp = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ + bpp = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ + bpp = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; default: - i = CRTC_PIX_WIDTH_8BPP; break; + FAIL("Invalid pixel width"); } - if (info->chip_class != CLASS_GT) { - aty_st_le32(CRTC_INT_CNTL, 0x00000002, info); - aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE, - info); /* gui_en block_en */ - i |= init->crtc_gen_cntl[par->hw.gx.cmode]; - } - /* Gentlemen, start your crtc engine */ - aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info); - - /* Initialize the graphics engine */ - if (par->accel & FB_ACCELF_TEXT) - init_engine(par, info); + /* output */ + var->xres = xres; + var->yres = yres; + var->xres_virtual = crtc->vxres; + var->yres_virtual = crtc->vyres; + var->bits_per_pixel = bpp; + var->xoffset = crtc->xoffset; + var->yoffset = crtc->yoffset; + var->left_margin = left; + var->right_margin = right; + var->upper_margin = upper; + var->lower_margin = lower; + var->hsync_len = hslen; + var->vsync_len = vslen; + var->sync = sync; + var->vmode = FB_VMODE_NONINTERLACED; -#ifdef CONFIG_FB_COMPAT_XPMAC - if (console_fb_info == &info->fb_info) { - display_info.height = vmode_attrs[par->hw.gx.vmode-1].vres; - display_info.width = vmode_attrs[par->hw.gx.vmode-1].hres; - display_info.depth = 8<hw.gx.cmode; - display_info.pitch = par->vxres<hw.gx.cmode; - display_info.mode = par->hw.gx.vmode; - strcpy(display_info.name, atyfb_name); - display_info.fb_address = info->frame_buffer_phys; - if (info->chip_class == CLASS_VT) - display_info.fb_address += init->offset[par->hw.gx.cmode]; - display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; - display_info.cmap_data_address = info->ati_regbase_phys+0xc1; - display_info.disp_reg_address = info->ati_regbase_phys; - } -#endif /* CONFIG_FB_COMPAT_XPMAC */ + return 0; } +/* ------------------------------------------------------------------------- */ /* - * Open/Release the frame buffer device + * PLL programming (Mach64 GX family) + * + * FIXME: use function pointer tables instead of switch statements */ -static int atyfb_open(struct fb_info *info, int user) +static void aty_set_pll_gx(const struct fb_info_aty *info, + const struct pll_gx *pll) +{ + switch (info->clk_type) { + case CLK_ATI18818_1: + aty_st_8(CLOCK_CNTL, pll->m, info); + break; + case CLK_IBMRGB514: + aty_st_514(0x06, 0x02, info); /* DAC Operation */ + aty_st_514(0x10, 0x01, info); /* PLL Control 1 */ + aty_st_514(0x70, 0x01, info); /* Misc Control 1 */ + aty_st_514(0x8f, 0x1f, info); /* PLL Ref. Divider Input */ + aty_st_514(0x03, 0x00, info); /* Sync Control */ + aty_st_514(0x05, 0x00, info); /* Power Management */ + aty_st_514(0x20, pll->m, info); /* F0 / M0 */ + aty_st_514(0x21, pll->m, info); /* F1 / N0 */ + break; + } +} + +static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, + struct pll_gx *pll) +{ + /* + * FIXME: use real calculations instead of using fixed values from the old + * driver + */ + static struct { + u32 ps_lim; /* pixclock period rounding limit (arbitrary) */ + u8 mode; /* (prescsaler << 4) | Select */ + u8 prog; /* ref_div_count */ + } ATI18818_clocks[] = { + { 7500, 0x0B, 1 }, /* 7407.4 ps = 135.00 MHz */ + { 9000, 0x0A, 1 }, /* 7936.5 ps = 126.00 MHz */ + { 11000, 0x09, 1 }, /* 10000.0 ps = 100.00 MHz */ + { 12800, 0x0D, 1 }, /* 12500.0 ps = 80.00 MHz */ + { 13500, 0x0E, 1 }, /* 13333.3 ps = 75.00 MHz */ +/* { 14000, 0x03, 2 },*/ /* 13888.8 ps = 72.00 MHz */ + { 15000, 0x1B, 1 }, /* 14814.8 ps = 67.50 MHz */ + { 15500, 0x0F, 1 }, /* 15384.6 ps = 65.00 MHz */ + { 16000, 0x1A, 1 }, /* 15873.0 ps = 63.00 MHz */ +/* { 16000, 0x02, 2 },*/ /* 15873.0 ps = 63.00 MHz */ +/* { 18000, 0x01, 2 },*/ /* 17655.4 ps = 56.64 MHz */ +/* { 19900, 0x00, 2 },*/ /* 19860.9 ps = 50.35 MHz */ + { 20000, 0x07, 1 }, /* 20000.0 ps = 50.00 MHz */ + { 20300, 0x06, 1 }, /* 20202.0 ps = 49.50 MHz */ + { 22500, 0x05, 1 }, /* 22271.2 ps = 44.90 MHz */ + { 25000, 0x04, 1 }, /* 25000.0 ps = 40.00 MHz */ +/* { 28000, 0x03, 1 },*/ /* 27777.8 ps = 36.00 MHz */ + { 30000, 0x2B, 1 }, /* 29629,6 ps = 33.75 MHz */ + { 31000, 0x1F, 1 }, /* 30769.2 ps = 32.50 MHz */ + { 32000, 0x2A, 1 }, /* 31746.0 ps = 31.50 MHz */ +/* { 32000, 0x02, 1 },*/ /* 31746.0 ps = 31.50 MHz */ +/* { 36000, 0x01, 1 },*/ /* 35310.7 ps = 28.32 MHz */ +/* { 39900, 0x00, 1 },*/ /* 39714.1 ps = 25.18 MHz */ + { 40000, 0x17, 1 }, /* 40000.0 ps = 25.00 MHz */ + { 40600, 0x16, 1 }, /* 40404.0 ps = 24.75 MHz */ + { 45000, 0x15, 1 }, /* 44543.4 ps = 22.45 MHz */ + { 50000, 0x14, 1 }, /* 50000.0 ps = 20.00 MHz */ +/* { 56000, 0x13, 1 },*/ /* 55555.5 ps = 18.00 MHz */ + { 62000, 0x2F, 1 }, /* 61538.8 ps = 16.25 MHz */ +/* { 64000, 0x12, 1 },*/ /* 63492.0 ps = 15.75 MHz */ + }; + int set; + for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks); + set++) + if (var->pixclock <= ATI18818_clocks[set].ps_lim) { + pll->m = ATI18818_clocks[set].mode; + pll->n = ATI18818_clocks[set].prog; + return 0; + } + return -EINVAL; +} + +static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, + struct pll_gx *pll) { /* - * Nothing, only a usage count for the moment + * FIXME: use real calculations instead of using fixed values from the old + * driver */ + static struct { + u32 limit; /* pixlock rounding limit (arbitrary) */ + u8 m; /* (df<<6) | vco_div_count */ + u8 n; /* ref_div_count */ + } RGB514_clocks[7] = { + { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */ + { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */ + { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */ + { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */ + { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */ + { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */ + { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */ + }; + int i; - MOD_INC_USE_COUNT; - return(0); + for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++) + if (var->pixclock <= RGB514_clocks[i].limit) { + pll->m = RGB514_clocks[i].m; + pll->n = RGB514_clocks[i].n; + return 0; + } + return -EINVAL; } -static int atyfb_release(struct fb_info *info, int user) + /* FIXME: ATI18818?? */ + +static int aty_pll_gx_to_var(const struct pll_gx *pll, + struct fb_var_screeninfo *var) { - MOD_DEC_USE_COUNT; - return(0); -} + u8 df, vco_div_count, ref_div_count; + df = pll->m >> 6; + vco_div_count = pll->m & 0x3f; + ref_div_count = pll->n; -static int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, struct fb_info_aty *info) -{ - struct aty_regvals *init; + var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + return 0; +} - strcpy(fix->id, atyfb_name); - init = get_aty_struct(par->hw.gx.vmode, info); - /* - * FIXME: This will cause problems on non-GT chips, because the frame - * buffer must be aligned to a page - */ - fix->smem_start = (char *)info->frame_buffer_phys; - if (info->chip_class == CLASS_VT) - fix->smem_start += init->offset[par->hw.gx.cmode]; - fix->smem_len = (u32)info->total_vram; -#ifdef __LITTLE_ENDIAN /* - * Last page of 8 MB little-endian aperture is MMIO - * FIXME: we should use the auxillary aperture instead so we can acces the - * full 8 MB of video RAM on 8 MB boards + * PLL programming (Mach64 CT family) */ - if (fix->smem_len > 0x800000-PAGE_SIZE) - fix->smem_len = 0x800000-PAGE_SIZE; -#endif - /* - * Reg Block 0 (CT-compatible block) is at ati_regbase_phys - * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 - */ - switch (info->chip_class) { - case CLASS_GX: - fix->mmio_start = (char *)info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64GX; - break; - case CLASS_CT: - fix->mmio_start = (char *)info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64CT; - break; - case CLASS_VT: - fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64VT; - break; - case CLASS_GT: - fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64GT; - break; - default: - fix->mmio_start = NULL; - fix->mmio_len = 0; - fix->accel = 0; + +static void aty_set_pll_ct(const struct fb_info_aty *info, + const struct pll_ct *pll) +{ +#if 0 /* ecd debug */ +printk("PLL_REF_DIV: %02x (%02x)\n", + pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info)); +printk("PLL_GEN_CNTL: %02x (%02x)\n", + pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info)); +printk("MCLK_FB_DIV: %02x (%02x)\n", + pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info)); +printk("PLL_VCLK_CNTL: %02x (%02x)\n", + pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info)); +printk("VCLK_POST_DIV: %02x (%02x)\n", + pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info)); +printk("VCLK0_FB_DIV: %02x (%02x)\n", + pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info)); +printk("PLL_EXT_CNTL: %02x (%02x)\n", + pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info)); +#endif /* ecd debug */ + aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info); + aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info); + aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info); + aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info); + aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info); + aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info); + aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info); + + if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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 == VU_CHIP_ID)) { + 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); + } +} + +static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, + u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div, + u8 bpp, struct pll_ct *pll) +{ + u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on; + u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size; + + /* xclocks_per_row<<11 */ + xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/ + (vclk_fb_div*mclk_post_div*bpp); + if (xclks_per_row < (1<<11)) + FAIL("Dotclock to high"); + fifo_size = 24; + dsp_precision = 0; + y = (xclks_per_row*fifo_size)>>11; + while (y) { + y >>= 1; + dsp_precision++; + } + dsp_precision -= 5; + /* fifo_off<<6 */ + fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6); + + if (info->total_vram > 1*1024*1024) { + if (info->ram_type >= SDRAM) { + /* >1 MB SDRAM */ + dsp_loop_latency = 8; + page_size = 8; + } else { + /* >1 MB DRAM */ + dsp_loop_latency = 6; + page_size = 9; + } + } else { + if (info->ram_type >= SDRAM) { + /* <2 MB SDRAM */ + dsp_loop_latency = 9; + page_size = 10; + } else { + /* <2 MB DRAM */ + dsp_loop_latency = 8; + page_size = 10; + } } - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->line_length = par->vxres<hw.gx.cmode; - fix->visual = par->hw.gx.cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_TRUECOLOR; - fix->ywrapstep = 0; - fix->xpanstep = 8; - fix->ypanstep = 1; + /* fifo_on<<6 */ + if (xclks_per_row >= (page_size<<11)) + fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5); + else + fifo_on = (3*page_size)<<6; + dsp_xclks_per_row = xclks_per_row>>dsp_precision; + dsp_on = fifo_on>>dsp_precision; + dsp_off = fifo_off>>dsp_precision; + + pll->dsp_config = (dsp_xclks_per_row & 0x3fff) | + ((dsp_loop_latency & 0xf)<<16) | + ((dsp_precision & 7)<<20); + pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16); return 0; } +static int aty_var_to_pll_ct(const struct fb_info_aty *info, + const struct fb_var_screeninfo *var, + struct pll_ct *pll) +{ + u32 vclk_per, q, x; /* x is a workaround for sparc64-linux-gcc */ + u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl; + u8 mclk_fb_div, mclk_post_div, mpostdiv = 0; + u8 vclk_fb_div, vclk_post_div, vpostdiv = 0; + int err; -static int decode_var(struct fb_var_screeninfo *var, - struct atyfb_par *par, struct fb_info_aty *info) -{ - int xres = var->xres; - int yres = var->yres; - int bpp = var->bits_per_pixel; - struct aty_regvals *init; - - /* This should support more video modes */ - - if (xres <= 512 && yres <= 384) - par->hw.gx.vmode = VMODE_512_384_60; /* 512x384, 60Hz */ - else if (xres <= 640 && yres <= 480) - par->hw.gx.vmode = VMODE_640_480_67; /* 640x480, 67Hz */ - else if (xres <= 640 && yres <= 870) - par->hw.gx.vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ - else if (xres <= 768 && yres <= 576) - par->hw.gx.vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */ - else if (xres <= 800 && yres <= 600) - par->hw.gx.vmode = VMODE_800_600_75; /* 800x600, 75Hz */ - else if (xres <= 832 && yres <= 624) - par->hw.gx.vmode = VMODE_832_624_75; /* 832x624, 75Hz */ - else if (xres <= 1024 && yres <= 768) - par->hw.gx.vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ - else if (xres <= 1152 && yres <= 870) - par->hw.gx.vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ - else if (xres <= 1280 && yres <= 960) - par->hw.gx.vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ - else if (xres <= 1280 && yres <= 1024) - par->hw.gx.vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ - else - return -EINVAL; + x = x; /* x is a workaround for sparc64-linux-gcc */ - xres = vmode_attrs[par->hw.gx.vmode-1].hres; - yres = vmode_attrs[par->hw.gx.vmode-1].vres; + pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ - if (var->xres_virtual <= xres) - par->vxres = xres; + vclk_per = var->pixclock; + pll_ref_div = info->pll_per*2*255/ref_clk_per; + + /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ + q = ref_clk_per*pll_ref_div*4/info->mclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) + FAIL("mclk out of range"); + else if (q < 32*8) + mclk_post_div = 8; + else if (q < 64*8) + mclk_post_div = 4; + else if (q < 128*8) + mclk_post_div = 2; else - par->vxres = (var->xres_virtual+7) & ~7; - if (var->yres_virtual <= yres) - par->vyres = yres; + mclk_post_div = 1; + mclk_fb_div = q*mclk_post_div/8; + + /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ + q = ref_clk_per*pll_ref_div*4/vclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) + FAIL("vclk out of range"); + else if (q < 32*8) + vclk_post_div = 8; + else if (q < 64*8) + vclk_post_div = 4; + else if (q < 128*8) + vclk_post_div = 2; else - par->vyres = var->yres_virtual; + vclk_post_div = 1; + vclk_fb_div = q*vclk_post_div/8; - par->xoffset = (var->xoffset+7) & ~7; - par->yoffset = var->yoffset; - if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres) - return -EINVAL; + if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div, + vclk_post_div, var->bits_per_pixel, pll))) + return err; - if (bpp <= 8) - par->hw.gx.cmode = CMODE_8; - else if (bpp <= 16) - par->hw.gx.cmode = CMODE_16; - else if (bpp <= 32) - par->hw.gx.cmode = CMODE_32; + if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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 == VU_CHIP_ID)) && (info->ram_type >= SDRAM)) + pll_gen_cntl = 0x04; else - return -EINVAL; + pll_gen_cntl = 0x84; - if (var->accel_flags & FB_ACCELF_TEXT) - par->accel = FB_ACCELF_TEXT; + switch (mclk_post_div) { + case 1: + mpostdiv = 0; + break; + case 2: + mpostdiv = 1; + break; + case 3: + mpostdiv = 4; + break; + case 4: + mpostdiv = 2; + break; + case 8: + mpostdiv = 3; + break; + } + pll_gen_cntl |= mpostdiv<<4; /* mclk */ + + if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)) + pll_ext_cntl = 0; else - par->accel = 0; + pll_ext_cntl = mpostdiv; /* xclk == mclk */ - if (aty_vram_reqd(par) > info->total_vram) - return -EINVAL; + switch (vclk_post_div) { + case 1: + vpostdiv = 0; + break; + case 2: + vpostdiv = 1; + break; + case 3: + vpostdiv = 0; + pll_ext_cntl |= 0x10; + break; + case 4: + vpostdiv = 2; + break; + case 6: + vpostdiv = 2; + pll_ext_cntl |= 0x10; + break; + case 8: + vpostdiv = 3; + break; + case 12: + vpostdiv = 3; + pll_ext_cntl |= 0x10; + break; + } + vclk_post_div = vpostdiv; + + pll->pll_ref_div = pll_ref_div; + pll->pll_gen_cntl = pll_gen_cntl; + pll->mclk_fb_div = mclk_fb_div; + pll->vclk_post_div = vclk_post_div; + pll->vclk_fb_div = vclk_fb_div; + pll->pll_ext_cntl = pll_ext_cntl; + return 0; +} - /* Check if we know about the wanted video mode */ - init = get_aty_struct(par->hw.gx.vmode, info); - if (init == NULL || init->crtc_h_sync_strt_wid[par->hw.gx.cmode] == 0 || - (info->chip_class != CLASS_GT && - init->crtc_gen_cntl[par->hw.gx.cmode] == 0) || - (info->chip_class == CLASS_GT && - (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 && - init->crtc_gen_cntl[1] == 0)) +static int aty_pll_ct_to_var(const struct pll_ct *pll, + struct fb_var_screeninfo *var) +{ + u8 pll_ref_div = pll->pll_ref_div; + u8 vclk_fb_div = pll->vclk_fb_div; + u8 vclk_post_div = pll->vclk_post_div; + u8 pll_ext_cntl = pll->pll_ext_cntl; + static u8 vclk_post_div_tab[] = { + 1, 2, 4, 8, + 3, 0, 6, 12 + }; + u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 1) | + (vclk_post_div & 3)]; + if (vpostdiv == 0) return -EINVAL; + var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2; + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void atyfb_set_par(const struct atyfb_par *par, + struct fb_info_aty *info) +{ + u32 i; + + info->current_par = *par; + + aty_set_crtc(info, &par->crtc); + aty_st_8(CLOCK_CNTL, 0, info); + aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info); + + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { + switch (info->dac_type) { + case DAC_IBMRGB514: + aty_set_dac_514(info, par->crtc.bpp); + break; + case DAC_ATI68860_B: + /* FIXME */ + break; + } + aty_set_pll_gx(info, &par->pll.gx); + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x47052100, info); + } else { + aty_set_pll_ct(info, &par->pll.ct); + i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff; + if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))) + i |= info->mem_refresh_rate << 20; + switch (par->crtc.bpp) { + case 8: + case 24: + i |= 0x00000000; + break; + case 16: + i |= 0x04000000; + break; + case 32: + i |= 0x08000000; + break; + } + if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else { + /* GT */ + aty_st_le32(DAC_CNTL, 0x86010102, info); + aty_st_le32(BUS_CNTL, 0x7b23a040, info); + aty_st_le32(EXT_MEM_CNTL, 0x5000001, info); + } + aty_st_le32(MEM_CNTL, i, info); + } + aty_st_8(DAC_MASK, 0xff, info); + + /* Initialize the graphics engine */ + if (par->accel_flags & FB_ACCELF_TEXT) + init_engine(par, info); + +#ifdef CONFIG_FB_COMPAT_XPMAC + if (console_fb_info == &info->fb_info) { + struct fb_var_screeninfo var; + int vmode, cmode; + display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; + display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; + display_info.depth = par->crtc.bpp; + display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; + atyfb_encode_var(&var, par, info); + if (mac_var_to_vmode(&var, &vmode, &cmode)) + display_info.mode = 0; + else + display_info.mode = vmode; + strcpy(display_info.name, atyfb_name); + display_info.fb_address = info->frame_buffer_phys; + display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; + display_info.cmap_data_address = info->ati_regbase_phys+0xc1; + display_info.disp_reg_address = info->ati_regbase_phys; + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +static int atyfb_decode_var(const struct fb_var_screeninfo *var, + struct atyfb_par *par, + const struct fb_info_aty *info) +{ + int err; + + if ((err = aty_var_to_crtc(info, var, &par->crtc))) + return err; + if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID)) + switch (info->clk_type) { + case CLK_ATI18818_1: + err = aty_var_to_pll_18818(var, &par->pll.gx); + break; + case CLK_IBMRGB514: + err = aty_var_to_pll_514(var, &par->pll.gx); + break; + } + else + err = aty_var_to_pll_ct(info, var, &par->pll.ct); + if (err) + return err; + + if (var->accel_flags & FB_ACCELF_TEXT) + par->accel_flags = FB_ACCELF_TEXT; + else + par->accel_flags = 0; #if 0 if (!fbmon_valid_timings(pixclock, htotal, vtotal, info)) @@ -1489,197 +1747,192 @@ return 0; } -static int encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - struct fb_info_aty *info) +static int atyfb_encode_var(struct fb_var_screeninfo *var, + const struct atyfb_par *par, + const struct fb_info_aty *info) { - int vmode = par->hw.gx.vmode; - int cmode = par->hw.gx.cmode; - struct aty_regvals *init = get_aty_struct(vmode, info); - u_int h_total, h_disp; - u_int h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u_int v_total, v_disp; - u_int v_sync_strt, v_sync_wid, v_sync_pol; - u_int xtalin, vclk = 0; - u8 pll_ref_div, vclk_fb_div, vclk_post_div, pll_ext_cntl; + int err; memset(var, 0, sizeof(struct fb_var_screeninfo)); - if (!init) - return -EINVAL; - var->xres = vmode_attrs[vmode-1].hres; - var->yres = vmode_attrs[vmode-1].vres; - var->xres_virtual = par->vxres; - var->yres_virtual = par->vyres; - var->xoffset = par->xoffset; - var->yoffset = par->yoffset; - var->grayscale = 0; - switch (cmode) { - case CMODE_8: - var->bits_per_pixel = 8; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CMODE_16: /* RGB 555 */ - var->bits_per_pixel = 16; - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CMODE_32: /* RGB 888 */ - var->bits_per_pixel = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - var->nonstd = 0; - var->activate = 0; + if ((err = aty_crtc_to_var(&par->crtc, var))) + return err; + if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID)) + err = aty_pll_gx_to_var(&par->pll.gx, var); + else + err = aty_pll_ct_to_var(&par->pll.ct, var); + if (err) + return err; + var->height = -1; var->width = -1; - var->vmode = FB_VMODE_NONINTERLACED; - var->accel_flags = par->accel; + var->accel_flags = par->accel_flags; + + return 0; +} + + + +static void set_off_pitch(struct atyfb_par *par, + const struct fb_info_aty *info) +{ + u32 xoffset = par->crtc.xoffset; + u32 yoffset = par->crtc.yoffset; + u32 vxres = par->crtc.vxres; + u32 bpp = par->crtc.bpp; + + par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info); +} + + + /* + * Open/Release the frame buffer device + */ + +static int atyfb_open(struct fb_info *info, int user) - h_total = (init->crtc_h_tot_disp<<3) & 0xff8; - h_disp = (init->crtc_h_tot_disp>>13) & 0x7f8; - h_sync_strt = ((init->crtc_h_sync_strt_wid[cmode]<<3) & 0x7f8) | - ((init->crtc_h_sync_strt_wid[cmode]>>1) & 0x800); - h_sync_dly = (init->crtc_h_sync_strt_wid[cmode]>>8) & 0x7; - h_sync_wid = (init->crtc_h_sync_strt_wid[cmode]>>13) & 0xf8; - h_sync_pol = (init->crtc_h_sync_strt_wid[cmode]>>21) & 0x1; - - v_total = init->crtc_v_tot_disp & 0x7ff; - v_disp = (init->crtc_v_tot_disp>>16) & 0x7ff; - v_sync_strt = init->crtc_v_sync_strt_wid & 0x7ff; - v_sync_wid = (init->crtc_v_sync_strt_wid>>16) & 0x1f; - v_sync_pol = (init->crtc_v_sync_strt_wid>>21) & 0x1; - - var->left_margin = (h_total+8)-h_sync_strt-h_sync_wid; - var->right_margin = h_sync_strt-(h_disp+8); - var->upper_margin = (v_total+1)-v_sync_strt-v_sync_wid; - var->lower_margin = v_sync_strt-(v_disp+1); - var->hsync_len = h_sync_wid; - var->vsync_len = v_sync_wid; - var->sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT); - - xtalin = 69841; /* 14.31818 MHz */ - switch (info->chip_class) { - case CLASS_GX: - { - /* haven't read the IBM RGB514 PDF yet, so just guesses */ - static u32 gx_vclk[VMODE_MAX] = { - 0, /* vmode 1 */ - 0, /* vmode 2 */ - 0, /* vmode 3 */ - 0, /* vmode 4 */ - 39722, /* vmode 5 (25.175 MHz) */ - 33333, /* vmode 6 (30 MHz) */ - 0, /* vmode 7 */ - 0, /* vmode 8 */ - 27778, /* vmode 9 (36 MHz) */ - 25000, /* vmode 10 (40 MHz) */ - 20000, /* vmode 11 (50 MHz) */ - 20000, /* vmode 12 (50 MHz) */ - 17544, /* vmode 13 (57 MHz) */ - 15385, /* vmode 14 (65 MHz) */ - 13333, /* vmode 15 (75 MHz) */ - 0, /* vmode 16 */ - 12821, /* vmode 17 (78 MHz) */ - 10000, /* vmode 18 (100 MHz) */ - 7937, /* vmode 19 (126 MHz) */ - 7407 /* vmode 20 (135 MHz) */ - }; - vclk = gx_vclk[vmode-1]; - } - break; - case CLASS_CT: - case CLASS_GT: - case CLASS_VT: - if (info->chip_class == CLASS_GT) { - pll_ref_div = 0x21; - vclk_post_div = init->offset[0]; - vclk_fb_div = init->offset[1]; - pll_ext_cntl = init->offset[2]; - } else { - pll_ref_div = 0x2d; - vclk_post_div = init->clock_val[0]; - vclk_fb_div = init->clock_val[1]; - pll_ext_cntl = 0x0; - } - vclk = xtalin*pll_ref_div; - switch (vclk_post_div & 3) { - case 0: - vclk *= (pll_ext_cntl & 0x10) ? 3 : 1; - break; - case 1: - if (pll_ext_cntl & 0x10) - return -EINVAL; - vclk *= 2; - break; - case 2: - vclk *= (pll_ext_cntl & 0x10) ? 6 : 4; - break; - case 3: - vclk *= (pll_ext_cntl & 0x10) ? 12 : 8; - break; - } - vclk /= 2*vclk_fb_div; - break; +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + + if (user) { + if (fb->open) + return -EBUSY; + fb->mmaped = 0; + fb->open = 1; + fb->vtconsole = -1; + } else { + fb->consolecnt++; } - var->pixclock = vclk; +#endif + MOD_INC_USE_COUNT; + return(0); +} - return 0; +static int atyfb_release(struct fb_info *info, int user) +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + + if (user) { + if (fb->vtconsole != -1) + vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; + fb->open = 0; + fb->mmaped = 0; + fb->vtconsole = -1; + } else { + fb->consolecnt--; + } +#endif + MOD_DEC_USE_COUNT; + return(0); } -static void init_par(struct atyfb_par *par, int vmode, int cmode) +static int encode_fix(struct fb_fix_screeninfo *fix, + const struct atyfb_par *par, + const struct fb_info_aty *info) { - par->hw.gx.vmode = vmode; - par->hw.gx.cmode = cmode; - par->vxres = vmode_attrs[vmode-1].hres; - par->vyres = vmode_attrs[vmode-1].vres; - par->xoffset = 0; - par->yoffset = 0; - par->accel = FB_ACCELF_TEXT; + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, atyfb_name); + fix->smem_start = (char *)info->frame_buffer_phys; + fix->smem_len = (u32)info->total_vram; + +#ifdef __LITTLE_ENDIAN + /* + * Last page of 8 MB little-endian aperture is MMIO + * FIXME: we should use the auxiliary aperture instead so we can acces the + * full 8 MB of video RAM on 8 MB boards + */ + if (fix->smem_len > 0x800000-GUI_RESERVE) + fix->smem_len = 0x800000-GUI_RESERVE; +#endif + /* + * Reg Block 0 (CT-compatible block) is at ati_regbase_phys + * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 + */ + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { + fix->mmio_start = (char *)info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64GX; + } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { + fix->mmio_start = (char *)info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64CT; + } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { + fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64VT; + } else { + fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64GT; + } + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->line_length = par->crtc.vxres*par->crtc.bpp/8; + fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + fix->ywrapstep = 0; + fix->xpanstep = 8; + fix->ypanstep = 1; + + return 0; } +struct fb_var_screeninfo default_var = { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +#ifdef __sparc__ +struct fb_var_screeninfo default_var_1024x768 __initdata = { + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; + +struct fb_var_screeninfo default_var_1152x900 __initdata = { + /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */ + 1152, 900, 1152, 900, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; + +struct fb_var_screeninfo default_var_1280x1024 __initdata = { + /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; +#endif + + /* * Get the Fixed Part of the Display */ static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + const struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; if (con == -1) - par = info2->default_par; + par = info->default_par; else - decode_var(&fb_display[con].var, &par, info2); - encode_fix(fix, &par, info2); + atyfb_decode_var(&fb_display[con].var, &par, info); + encode_fix(fix, &par, info); return 0; } @@ -1689,12 +1942,12 @@ */ static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + const struct fb_info_aty *info = (struct fb_info_aty *)fb; if (con == -1) - encode_var(var, &info2->default_par, (struct fb_info_aty *)info); + atyfb_encode_var(var, &info->default_par, info); else *var = fb_display[con].var; return 0; @@ -1706,9 +1959,9 @@ */ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; struct display *display; int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; @@ -1717,12 +1970,12 @@ if (con >= 0) display = &fb_display[con]; else - display = &fb_disp; /* used during initialization */ + display = fb->disp; /* used during initialization */ - if ((err = decode_var(var, &par, info2))) + if ((err = atyfb_decode_var(var, &par, info))) return err; - encode_var(var, &par, (struct fb_info_aty *)info); + atyfb_encode_var(var, &par, (struct fb_info_aty *)info); if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres = display->var.xres; @@ -1737,8 +1990,8 @@ oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; - encode_fix(&fix, &par, info2); - display->screen_base = (char *)info2->frame_buffer; + encode_fix(&fix, &par, info); + display->screen_base = (char *)info->frame_buffer; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1748,20 +2001,25 @@ display->can_soft_blank = 1; display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; - switch (par.hw.gx.cmode) { + switch (par.crtc.bpp) { #ifdef FBCON_HAS_CFB8 - case CMODE_8: - display->dispsw = accel ? &fbcon_aty8 : &fbcon_cfb8; + case 8: + *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 - case CMODE_16: - display->dispsw = accel ? &fbcon_aty16 : &fbcon_cfb16; + case 16: + *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; break; #endif #ifdef FBCON_HAS_CFB32 - case CMODE_32: - display->dispsw = accel ? &fbcon_aty32 : &fbcon_cfb32; + case 32: + *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; break; #endif default: @@ -1769,19 +2027,19 @@ break; } display->scrollmode = accel ? 0 : SCROLL_YREDRAW; - if (info->changevar) - (*info->changevar)(con); - if (info2->cursor) { - display->dispsw->cursor = atyfb_cursor; - display->dispsw->set_font = atyfb_set_font; + if (info->fb_info.changevar) + (*info->fb_info.changevar)(con); + if (info->cursor) { + display->dispsw->cursor = atyfb_cursor; + display->dispsw->set_font = atyfb_set_font; } } if (con == currcon) - atyfb_set_par(&par, info2); + atyfb_set_par(&par, info); if (oldbpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; - do_install_cmap(con, info); + do_install_cmap(con, &info->fb_info); } } @@ -1796,21 +2054,21 @@ */ static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; u32 xres, yres, xoffset, yoffset; - struct atyfb_par *par = &info2->current_par; + struct atyfb_par *par = &info->current_par; - xres = vmode_attrs[par->hw.gx.vmode-1].hres; - yres = vmode_attrs[par->hw.gx.vmode-1].vres; + xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; + yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; xoffset = (var->xoffset+7) & ~7; yoffset = var->yoffset; - if (xoffset+xres > par->vxres || yoffset+yres > par->vyres) + if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) return -EINVAL; - par->xoffset = xoffset; - par->yoffset = yoffset; - set_off_pitch(par, info2); + par->crtc.xoffset = xoffset; + par->crtc.yoffset = yoffset; + set_off_pitch(par, info); return 0; } @@ -1965,6 +2223,18 @@ vma->vm_file = file; file->f_count++; vma->vm_flags |= VM_IO; + + if (!fb->mmaped) { + int lastconsole = 0; + + if (info->display_fg) + lastconsole = info->display_fg->vc_num; + fb->mmaped = 1; + if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { + fb->vtconsole = lastconsole; + vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + } + } return 0; } #endif /* __sparc__ */ @@ -1977,179 +2247,206 @@ { u32 chip_id; u32 i; - int j, k, sense; + int j, k; struct fb_var_screeninfo var; - struct aty_regvals *init; + struct display *disp; const char *chipname = NULL; - u8 rev; + int pll, mclk; +#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) + int sense; +#endif info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + Gx = chip_id & CFG_CHIP_TYPE; + Rev = (chip_id & CFG_CHIP_REV)>>24; for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++) - if (aty_features[j].chip_type == (chip_id & CFG_CHIP_TYPE)) { + if (aty_features[j].chip_type == Gx) { chipname = aty_features[j].name; - info->chip_class = aty_features[j].chip_class; - info->pixclock_lim_8 = 1000000/aty_features[j].pixclock_lim_8; - info->pixclock_lim_hi = 1000000/aty_features[j].pixclock_lim_hi; + break; } if (!chipname) { - printk("atyfb: Unknown Mach64 0x%04x\n", chip_id & CFG_CHIP_TYPE); + printk("atyfb: Unknown mach64 0x%04x\n", Gx); return 0; } else - printk("atyfb: %s [", chipname); - rev = (chip_id & CFG_CHIP_REV)>>24; - switch ((rev>>3) & 7) { - case MACH64_FND_SGS: - printk("SGS"); - break; - case MACH64_FND_NEC: - printk("NEC"); - break; - case MACH64_FND_UMC: - printk("UMC"); - break; + printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev); + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { + info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07; + info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07; + /* FIXME: clockchip/RAMDAC probing? */ +#ifdef CONFIG_ATARI + info->dac_type = DAC_ATI68860_B; + info->clk_type = CLK_ATI18818_1; +#else + info->dac_type = DAC_IBMRGB514; + info->clk_type = CLK_IBMRGB514; +#endif + /* FIXME */ + pll = 135; + mclk = 50; + } else { + info->bus_type = PCI; + info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); + info->dac_type = DAC_INTERNAL; + info->clk_type = CLK_INTERNAL; + if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { + pll = 135; + mclk = 60; + } else { + mclk = info->ram_type >= SDRAM ? 67 : 63; + if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) { + /* VTA3 */ + pll = 170; + } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) || + (Rev == 0x48))) || + ((Gx == VT_CHIP_ID) && ((Rev == 0x01) || + (Rev == 0x9a))) || + (Gx == VU_CHIP_ID)) { + /* VTA4 or VTB */ + pll = 200; + } else if (Gx == VT_CHIP_ID) { + /* other VT */ + pll = 135; + mclk = 63; + } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) { + /* RAGE II */ + pll = 170; + } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) || + (Gx == GU_CHIP_ID)) { + /* RAGE II+ */ + pll = 200; + } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || + (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || + (Gx == GQ_CHIP_ID)) { + /* RAGE PRO */ + pll = 230; + } else { + /* other RAGE */ + pll = 135; + mclk = 63; + } + } } - printk(" %c%d]\n", 'A'+(rev & 7), rev>>6); + if (mclk < 44) + info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ + else if (mclk < 50) + info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ + else if (mclk < 55) + info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ + else if (mclk < 66) + info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ + else if (mclk < 75) + info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ + else if (mclk < 80) + info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ + else if (mclk < 100) + info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ + else + info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ + printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk); + info->pll_per = 1000000/pll; + info->mclk_per = 1000000/mclk; i = aty_ld_le32(MEM_CNTL, info); - if (info->chip_class != CLASS_GT) - switch (i & MEM_SIZE_ALIAS) { + if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || + ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_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)) + switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ case MEM_SIZE_512K: info->total_vram = 0x80000; break; case MEM_SIZE_1M: info->total_vram = 0x100000; break; - case MEM_SIZE_2M: + case MEM_SIZE_2M_GTB: info->total_vram = 0x200000; break; - case MEM_SIZE_4M: + case MEM_SIZE_4M_GTB: info->total_vram = 0x400000; break; - case MEM_SIZE_6M: + case MEM_SIZE_6M_GTB: info->total_vram = 0x600000; break; - case MEM_SIZE_8M: + case MEM_SIZE_8M_GTB: info->total_vram = 0x800000; break; default: info->total_vram = 0x80000; } else - switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ + switch (i & MEM_SIZE_ALIAS) { case MEM_SIZE_512K: info->total_vram = 0x80000; break; case MEM_SIZE_1M: info->total_vram = 0x100000; break; - case MEM_SIZE_2M_GTB: + case MEM_SIZE_2M: info->total_vram = 0x200000; break; - case MEM_SIZE_4M_GTB: + case MEM_SIZE_4M: info->total_vram = 0x400000; break; - case MEM_SIZE_6M_GTB: + case MEM_SIZE_6M: info->total_vram = 0x600000; break; - case MEM_SIZE_8M_GTB: + case MEM_SIZE_8M: info->total_vram = 0x800000; break; default: info->total_vram = 0x80000; } -#ifdef CONFIG_ATARI /* this is definately not the wrong way to set this */ - if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) { - /* protect GUI-regs if complete Aperture is VRAM */ - info->total_vram -= 0x00001000; - } -#endif -#if 0 - printk("aty_init: regbase = %lx, frame_buffer = %lx, total_vram = %x\n", - info->ati_regbase, info->frame_buffer, info->total_vram); -#endif + if (info->bus_type == ISA) + if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) { + /* protect GUI-regs if complete Aperture is VRAM */ + info->total_vram -= GUI_RESERVE; + } - sense = read_aty_sense(info); -#if 0 - printk("monitor sense = %x\n", sense); -#endif #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); - init = get_aty_struct(default_vmode, info); - if (default_vmode <= 0 || default_vmode > VMODE_MAX || init == 0) + if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_CHOOSE; } - if (default_vmode == VMODE_CHOOSE) - default_vmode = map_monitor_sense(sense); -#else /* !CONFIG_PMAC && !CONFIG_CHRP */ - if (default_vmode == VMODE_NVRAM) - default_vmode = map_monitor_sense(sense); -#endif /* !CONFIG_PMAC && !CONFIG_CHRP */ - - if (!(init = get_aty_struct(default_vmode, info))) + if (default_vmode == VMODE_CHOOSE) { + sense = read_aty_sense(info); + default_vmode = mac_map_monitor_sense(sense); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; - - /* - * Reduce the pixel size if we don't have enough VRAM. - */ - if (default_cmode == CMODE_NVRAM) -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) default_cmode = nvram_read_byte(NV_CMODE); -#else /* !CONFIG_PMAC && !CONFIG_CHRP */ - default_cmode = CMODE_8; -#endif /* !CONFIG_PMAC && !CONFIG_CHRP */ if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; - - init_par(&info->default_par, default_vmode, default_cmode); - while (aty_vram_reqd(&info->default_par) > info->total_vram) { - while (default_cmode > CMODE_8 && - aty_vram_reqd(&info->default_par) > info->total_vram) { - --default_cmode; - init_par(&info->default_par, default_vmode, default_cmode); - } - /* - * Adjust the video mode smaller if there still is not enough VRAM - */ - if (aty_vram_reqd(&info->default_par) > info->total_vram) - do { - default_vmode--; - init_par(&info->default_par, default_vmode, default_cmode); - init = get_aty_struct(default_vmode, info); - } while ((init == 0) && - (default_vmode > VMODE_640_480_60)); - } - - if (info->chip_class == CLASS_GT && - (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 - && init->crtc_gen_cntl[1] == 0) { - default_vmode = VMODE_640_480_67; - default_cmode = CMODE_8; - init_par(&info->default_par, default_vmode, default_cmode); - } - - switch (info->chip_class) { - case CLASS_GX: - strcat(atyfb_name, "GX"); - break; - case CLASS_CT: - strcat(atyfb_name, "CT"); - break; - case CLASS_VT: - strcat(atyfb_name, "VT"); - break; - case CLASS_GT: - strcat(atyfb_name, "GT"); - break; + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; +#else /* !CONFIG_PMAC && !CONFIG_CHRP */ + var = default_var; +#endif /* !CONFIG_PMAC && !CONFIG_CHRP */ + var.accel_flags |= FB_ACCELF_TEXT; + if (atyfb_decode_var(&var, &info->default_par, info)) { + printk("atyfb: can't set default video mode\n"); + return 0; } + + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) + strcat(atyfb_name, "GX"); + else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) + strcat(atyfb_name, "CT"); + else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) + strcat(atyfb_name, "VT"); + else + strcat(atyfb_name, "GT"); + + disp = &info->disp; + strcpy(info->fb_info.modename, atyfb_name); info->fb_info.node = -1; info->fb_info.fbops = &atyfb_ops; - info->fb_info.disp = &fb_disp; - info->fb_info.fontname[0] = '\0'; + info->fb_info.disp = disp; + strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &atyfbcon_switch; info->fb_info.updatevar = &atyfbcon_updatevar; @@ -2162,13 +2459,16 @@ info->palette[j].blue = default_blu[k]; } - if (info->chip_class == CLASS_VT || info->chip_class == CLASS_GT) { + if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_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 == VU_CHIP_ID)) { info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); - memset(info->cursor, 0, sizeof(*info->cursor)); + if (info->cursor) + memset(info->cursor, 0, sizeof(*info->cursor)); } - atyfb_set_par(&info->default_par, info); - encode_var(&var, &info->default_par, info); + disp->dispsw = &info->dispsw; atyfb_set_var(&var, -1, &info->fb_info); if (register_framebuffer(&info->fb_info) < 0) @@ -2188,14 +2488,16 @@ struct pci_dev *pdev; struct fb_info_aty *info; unsigned long addr; - int i, j; - u16 tmp; #ifdef __sparc__ extern int con_is_present(void); + u32 chip_id; + int i, j; /* Do not attach when we have a serial console. */ if (!con_is_present()) - return; + return; +#else + u16 tmp; #endif for (pdev = pci_devices; pdev; pdev = pdev->next) { @@ -2236,7 +2538,7 @@ /* nothing */; j = i + 1; - info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); + info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); if (!info->mmap_map) { printk("atyfb_init: can't alloc mmap_map\n"); kfree(info); @@ -2284,8 +2586,8 @@ /* * Fix PROMs idea of MEM_CNTL settings... */ - tmp = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE; - if (tmp == VT_CHIP_ID) { + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE; + if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) { u32 mem = aty_ld_le32(MEM_CNTL, info); switch (mem & 0x0f) { case 3: @@ -2318,34 +2620,35 @@ int height = prom_getintdefault(node, "height", 768); int depth = prom_getintdefault(node, "depth", 8); - switch (depth) { - case 8: - default_cmode = CMODE_8; + switch (width) { + case 1024: + if (height == 768) + default_var = default_var_1024x768; break; - case 16: - default_cmode = CMODE_16; + case 1152: + if (height == 900) + default_var = default_var_1152x900; break; - case 32: - default_cmode = CMODE_32; + case 1280: + if (height == 1024) + default_var = default_var_1280x1024; break; default: break; } - switch (width) { - case 1024: - if (height == 768) - default_vmode = VMODE_1024_768_75; + switch (depth) { + case 8: + default_var.bits_per_pixel = 8; break; - case 1152: - if (height == 870) - default_vmode = VMODE_1152_870_75; + case 16: + default_var.bits_per_pixel = 16; break; - case 1280: - if (height == 960) - default_vmode = VMODE_1280_960_75; - else if (height == 1024) - default_vmode = VMODE_1280_1024_75; + case 24: + default_var.bits_per_pixel = 24; + break; + case 32: + default_var.bits_per_pixel = 32; break; default: break; @@ -2354,9 +2657,6 @@ #else /* __sparc__ */ - info->ati_regbase = (unsigned long) - ioremap(0x7ff000 + addr, 0x1000) + 0xc00; - info->ati_regbase_phys = 0x7ff000 + addr; info->ati_regbase = (unsigned long) ioremap(info->ati_regbase_phys, 0x1000); @@ -2388,7 +2688,7 @@ if (!aty_init(info, "PCI")) { if (info->mmap_map) kfree(info->mmap_map); - kfree(info); + kfree(info); } } } @@ -2500,39 +2800,51 @@ __initfunc(void atyfb_setup(char *options, int *ints)) { char *this_opt; - int vmode; - int depth; + if (!options || !*options) return; for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } +#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) if (!strncmp(this_opt, "vmode:", 6)) { - vmode = simple_strtoul(this_opt+6, NULL, 0); + int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) default_vmode = vmode; } else if (!strncmp(this_opt, "cmode:", 6)) { - depth = simple_strtoul(this_opt+6, NULL, 0); + int depth = simple_strtoul(this_opt+6, NULL, 0); switch (depth) { case 8: - default_cmode = CMODE_8; + default_cmode = 0; break; case 15: case 16: - default_cmode = CMODE_16; + default_cmode = 1; break; case 24: case 32: - default_cmode = CMODE_32; + default_cmode = 2; break; } } +#endif #ifdef CONFIG_ATARI /* * Why do we need this silly Mach64 argument? * We are already here because of mach64= so its redundant. */ - else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { + if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { static unsigned char m64_num; static char mach64_str[80]; strncpy(mach64_str, this_opt+7, 80); @@ -2595,39 +2907,48 @@ } #endif /* CONFIG_ATARI */ -static int atyfbcon_switch(int con, struct fb_info *info) +static int atyfbcon_switch(int con, struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - atyfb_getcolreg, info); + atyfb_getcolreg, fb); + + /* Erase HW Cursor */ + if (info->cursor) + atyfb_cursor(&fb_display[currcon], CM_ERASE, + info->cursor->pos.x, info->cursor->pos.y); + currcon = con; - decode_var(&fb_display[con].var, &par, info2); - atyfb_set_par(&par, info2); + + atyfb_decode_var(&fb_display[con].var, &par, info); + atyfb_set_par(&par, info); + /* Install new colormap */ - do_install_cmap(con, info); + do_install_cmap(con, fb); + /* Install hw cursor */ - if (info2->cursor) { - aty_set_cursor_color(info2, cursor_pixel_map, cursor_color_map, + if (info->cursor) { + aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map, cursor_color_map, cursor_color_map); - aty_set_cursor_shape(info2); + aty_set_cursor_shape(info); } - return 0; + return 1; } /* * Update the `var' structure (called by fbcon.c) */ -static int atyfbcon_updatevar(int con, struct fb_info *info) +static int atyfbcon_updatevar(int con, struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; - info2->current_par.yoffset = fb_display[con].var.yoffset; - set_off_pitch(&info2->current_par, info2); + info->current_par.crtc.yoffset = fb_display[con].var.yoffset; + set_off_pitch(&info->current_par, info); return 0; } @@ -2635,12 +2956,12 @@ * Blank the display. */ -static void atyfbcon_blank(int blank, struct fb_info *info) +static void atyfbcon_blank(int blank, struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; - gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info2); + gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); if (blank > 0) switch (blank-1) { case VESA_NO_BLANKING: @@ -2658,7 +2979,7 @@ } else gen_cntl &= ~(0x4c); - aty_st_8(CRTC_GEN_CNTL, gen_cntl, info2); + aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); } @@ -2668,15 +2989,15 @@ */ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) + u_int *transp, struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; if (regno > 255) return 1; - *red = info2->palette[regno].red; - *green = info2->palette[regno].green; - *blue = info2->palette[regno].blue; + *red = info->palette[regno].red; + *green = info->palette[regno].green; + *blue = info->palette[regno].blue; return 0; } @@ -2688,36 +3009,41 @@ */ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) + u_int transp, struct fb_info *fb) { - struct fb_info_aty *info2 = (struct fb_info_aty *)info; + struct fb_info_aty *info = (struct fb_info_aty *)fb; int i, scale; if (regno > 255) return 1; - info2->palette[regno].red = red; - info2->palette[regno].green = green; - info2->palette[regno].blue = blue; - i = aty_ld_8(DAC_CNTL, info2) & 0xfc; - if (info2->chip_class == CLASS_GT) + info->palette[regno].red = red; + info->palette[regno].green = green; + info->palette[regno].blue = blue; + i = aty_ld_8(DAC_CNTL, info) & 0xfc; + if ((Gx == GT_CHIP_ID) || (Gx == GU_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)) i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ - aty_st_8(DAC_CNTL, i, info2); - aty_st_8(DAC_REGS + DAC_MASK, 0xff, info2); + aty_st_8(DAC_CNTL, i, info); + aty_st_8(DAC_REGS + DAC_MASK, 0xff, info); eieio(); - scale = ((info2->chip_class != CLASS_GX) && - (info2->current_par.hw.gx.cmode == CMODE_16)) ? 3 : 0; - info2->aty_cmap_regs->windex = regno << scale; + scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && + (info->current_par.crtc.bpp == 16)) ? 3 : 0; + info->aty_cmap_regs->windex = regno << scale; eieio(); - info2->aty_cmap_regs->lut = red << scale; + info->aty_cmap_regs->lut = red << scale; eieio(); - info2->aty_cmap_regs->lut = green << scale; + info->aty_cmap_regs->lut = green << scale; eieio(); - info2->aty_cmap_regs->lut = blue << scale; + info->aty_cmap_regs->lut = blue << scale; eieio(); if (regno < 16) { #ifdef FBCON_HAS_CFB16 fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; #endif +#ifdef FBCON_HAS_CFB24 + fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno; +#endif #ifdef FBCON_HAS_CFB32 fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; @@ -2765,14 +3091,15 @@ if (!width || !height) return; - pitch_value = info->current_par.vxres; -#if 0 - if (par->hw.gx.cmode == CMODE_24) { + pitch_value = info->current_par.crtc.vxres; + if (info->current_par.crtc.bpp == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ /* horizontal coordinates and widths must be adjusted */ - pitch_value = pitch_value * 3; + pitch_value *= 3; + srcx *= 3; + dstx *= 3; + width *= 3; } -#endif if (srcy < dsty) { dsty += height - 1; @@ -2806,6 +3133,13 @@ if (!width || !height) return; + if (info->current_par.crtc.bpp == 24) { + /* In 24 bpp, the engine is in 8 bpp - this requires that all */ + /* horizontal coordinates and widths must be adjusted */ + dstx *= 3; + width *= 3; + } + wait_for_fifo(3, info); aty_st_le32(DP_FRGD_CLR, color, info); aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, @@ -2823,6 +3157,13 @@ static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + sx *= p->fontwidth; sy *= p->fontheight; dx *= p->fontwidth; @@ -2837,7 +3178,15 @@ static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - u32 bgx = attr_bgcol_ec(p, conp); + u32 bgx; +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + + bgx = attr_bgcol_ec(p, conp); bgx |= (bgx << 8); bgx |= (bgx << 16); @@ -2854,13 +3203,28 @@ static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb8_putc(conp, p, c, yy, xx); } static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx) + const unsigned short *s, int count, int yy, + int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb8_putcs(conp, p, s, count, yy, xx); } @@ -2868,7 +3232,7 @@ static struct display_switch fbcon_aty8 = { fbcon_cfb8_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty8_putc, fbcon_aty8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins, - FONTWIDTH(8) + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; #endif @@ -2876,20 +3240,73 @@ static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb16_putc(conp, p, c, yy, xx); } static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx) + const unsigned short *s, int count, int yy, + int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb16_putcs(conp, p, s, count, yy, xx); } static struct display_switch fbcon_aty16 = { fbcon_cfb16_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty16_putc, - fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#ifdef FBCON_HAS_CFB24 +static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + + wait_for_idle((struct fb_info_aty *)p->fb_info); + fbcon_cfb24_putc(conp, p, c, yy, xx); +} + +static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx) +{ +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + + wait_for_idle((struct fb_info_aty *)p->fb_info); + fbcon_cfb24_putcs(conp, p, s, count, yy, xx); +} + +static struct display_switch fbcon_aty24 = { + fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_aty24_putc, + fbcon_aty24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; #endif @@ -2897,19 +3314,35 @@ static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb32_putc(conp, p, c, yy, xx); } static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx) + const unsigned short *s, int count, int yy, + int xx) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); + + if (fb->mmaped && currcon == fb->vtconsole) + return; +#endif + wait_for_idle((struct fb_info_aty *)p->fb_info); fbcon_cfb32_putcs(conp, p, s, count, yy, xx); } static struct display_switch fbcon_aty32 = { fbcon_cfb32_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty32_putc, - fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; #endif diff -u --recursive --new-file v2.1.111/linux/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c --- v2.1.111/linux/drivers/video/bwtwofb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/bwtwofb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,222 @@ +/* $Id: bwtwofb.c,v 1.1 1998/07/21 14:50:48 jj Exp $ + * bwtwofb.c: BWtwo frame buffer driver + * + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 Pavel Machek (pavel@ucw.cz) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sbusfb.h" +#include +#ifndef __sparc_v9__ +#include +#endif + +#include "fbcon-mfb.h" + +/* OBio addresses for the bwtwo registers */ +#define BWTWO_REGISTER_OFFSET 0x400000 + +struct bw2_regs { + struct bt_regs bt; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; +}; + +/* Status Register Constants */ +#define BWTWO_SR_RES_MASK 0x70 +#define BWTWO_SR_1600_1280 0x50 +#define BWTWO_SR_1152_900_76_A 0x40 +#define BWTWO_SR_1152_900_76_B 0x60 +#define BWTWO_SR_ID_MASK 0x0f +#define BWTWO_SR_ID_MONO 0x02 +#define BWTWO_SR_ID_MONO_ECL 0x03 +#define BWTWO_SR_ID_MSYNC 0x04 + +/* Control Register Constants */ +#define BWTWO_CTL_ENABLE_INTS 0x80 +#define BWTWO_CTL_ENABLE_VIDEO 0x40 +#define BWTWO_CTL_ENABLE_TIMING 0x20 +#define BWTWO_CTL_ENABLE_CURCMP 0x10 +#define BWTWO_CTL_XTAL_MASK 0x0C +#define BWTWO_CTL_DIVISOR_MASK 0x03 + +/* Status Register Constants */ +#define BWTWO_STAT_PENDING_INT 0x80 +#define BWTWO_STAT_MSENSE_MASK 0x70 +#define BWTWO_STAT_ID_MASK 0x0f + +static struct sbus_mmap_map bw2_mmap_map[] = { + { 0, 0, SBUS_MMAP_FBSIZE(1) }, + { 0, 0, 0 } +}; + +static void bw2_blank (struct fb_info_sbusfb *fb) +{ + fb->s.bw2.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO; +} + +static void bw2_unblank (struct fb_info_sbusfb *fb) +{ + fb->s.bw2.regs->control |= BWTWO_CTL_ENABLE_VIDEO; +} + +static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) +{ + p->screen_base += ((y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin)) >> 3; +} + +static u8 bw2regs_1600[] __initdata = { + 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, + 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, + 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x21, 0 +}; + +static u8 bw2regs_ecl[] __initdata = { + 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c, + 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23, + 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 bw2regs_analog[] __initdata = { + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13, + 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 bw2regs_76hz[] __initdata = { + 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, + 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x24, 0 +}; + +static u8 bw2regs_66hz[] __initdata = { + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static char idstring[60] __initdata = { 0 }; + +__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb)) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct display *disp = &fb->disp; + struct fbtype *type = &fb->type; +#ifdef CONFIG_SUN4 + unsigned long phys = SUN4_300_BWTWO_PHYSADDR; +#else + unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; +#endif + +#ifndef FBCON_HAS_MFB + return NULL; +#endif + + if (!fb->s.bw2.regs) { + fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0, + sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0); + if (!prom_getbool(fb->prom_node, "width")) { + /* Ugh, broken PROM didn't initialize us. + * Let's deal with this ourselves. + */ + u8 status, mon; + u8 *p; + int sizechange = 0; + + status = fb->s.bw2.regs->status; + mon = status & BWTWO_SR_RES_MASK; + switch (status & BWTWO_SR_ID_MASK) { + case BWTWO_SR_ID_MONO_ECL: + if (mon == BWTWO_SR_1600_1280) { + p = bw2regs_1600; + fb->type.fb_width = 1600; + fb->type.fb_height = 1280; + sizechange = 1; + } else + p = bw2regs_ecl; + break; + case BWTWO_SR_ID_MONO: + p = bw2regs_analog; + break; + case BWTWO_SR_ID_MSYNC: + if (mon == BWTWO_SR_1152_900_76_A || + mon == BWTWO_SR_1152_900_76_B) + p = bw2regs_76hz; + else + p = bw2regs_66hz; + break; + default: + prom_printf("bw2: can't handle SR %02x\n", + status); + prom_halt(); + return NULL; /* fool gcc. */ + } + for ( ; *p; p += 2) + ((u8 *)fb->s.bw2.regs)[p[0]] = p[1]; + } + } + + strcpy(fb->info.modename, "BWtwo"); + strcpy(fix->id, "BWtwo"); + fix->line_length = fb->var.xres_virtual>>3; + + disp->scrollmode = SCROLL_YREDRAW; + if (!disp->screen_base) + disp->screen_base = (char *)sparc_alloc_io(phys, 0, + type->fb_size, "bw2_ram", fb->iospace, 0); + disp->screen_base += (fix->line_length * fb->y_margin + fb->x_margin) >> 3; + fb->dispsw = fbcon_mfb; + fix->visual = FB_VISUAL_MONO01; + + fb->blank = bw2_blank; + fb->unblank = bw2_unblank; + fb->margins = bw2_margins; + + fb->physbase = phys; + fb->mmap_map = bw2_mmap_map; + +#ifdef __sparc_v9__ + sprintf(idstring, "bwtwo at %016lx", phys); +#else + sprintf(idstring, "bwtwo at %x.%08lx", fb->iospace, phys); +#endif + + return idstring; +} diff -u --recursive --new-file v2.1.111/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c --- v2.1.111/linux/drivers/video/cgsixfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/cgsixfb.c Sun Jul 26 14:40:19 1998 @@ -1,4 +1,4 @@ -/* $Id: cgsixfb.c,v 1.4 1998/07/21 10:36:53 jj Exp $ +/* $Id: cgsixfb.c,v 1.7 1998/07/22 12:44:59 jj Exp $ * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -237,8 +237,8 @@ do { i = fbc->s; } while (i & 0x10000000); - fbc->fg = attr_bg_col_ec(conp); - fbc->bg = attr_bg_col_ec(conp); + fbc->fg = attr_bgcol_ec(p,conp); + fbc->bg = attr_bgcol_ec(p,conp); fbc->pixelm = ~(0); fbc->alu = 0xea80ff00; fbc->s = 0; @@ -264,7 +264,7 @@ } while (i < 0 && (i & 0x20000000)); } -static void cg6_fill(struct fb_info_sbusfb *fb, int s, +static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s, int count, unsigned short *boxes) { int i; @@ -273,8 +273,8 @@ do { i = fbc->s; } while (i & 0x10000000); - fbc->fg = attr_bg_col(s); - fbc->bg = attr_bg_col(s); + fbc->fg = attr_bgcol(p,s); + fbc->bg = attr_bgcol(p,s); fbc->pixelm = ~(0); fbc->alu = 0xea80ff00; fbc->s = 0; @@ -301,11 +301,15 @@ if (p->fontheightlog) { y = fb->y_margin + (yy << p->fontheightlog); - i = ((c & 0xff) << p->fontheightlog); + i = ((c & p->charmask) << p->fontheightlog); } else { y = fb->y_margin + (yy * p->fontheight); - i = (c & 0xff) * p->fontheight; + i = (c & p->charmask) * p->fontheight; } +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + fd = p->fontdata + i; + x = fb->x_margin + xx * 8; +#else if (p->fontwidth <= 8) fd = p->fontdata + i; else @@ -314,11 +318,12 @@ x = fb->x_margin + (xx << p->fontwidthlog); else x = fb->x_margin + (xx * p->fontwidth); +#endif do { i = fbc->s; } while (i & 0x10000000); - fbc->fg = attr_fg_col(c); - fbc->bg = attr_bg_col(c); + fbc->fg = attr_fgcol(p,c); + fbc->bg = attr_bgcol(p,c); fbc->mode = 0x140000; fbc->alu = 0xe880fc30; fbc->pixelm = ~(0); @@ -330,15 +335,19 @@ fbc->x0 = x; fbc->x1 = x + p->fontwidth - 1; fbc->y0 = y; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif for (i = 0; i < p->fontheight; i++) fbc->font = *fd++ << 24; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { for (i = 0; i < p->fontheight; i++) { fbc->font = *(u16 *)fd << 16; fd += 2; } } +#endif } static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, @@ -352,8 +361,8 @@ do { i = fbc->s; } while (i & 0x10000000); - fbc->fg = attr_fg_col(*s); - fbc->bg = attr_bg_col(*s); + fbc->fg = attr_fgcol(p,*s); + fbc->bg = attr_bgcol(p,*s); fbc->mode = 0x140000; fbc->alu = 0xe880fc30; fbc->pixelm = ~(0); @@ -362,15 +371,21 @@ fbc->pm = 0xff; x = fb->x_margin; y = fb->y_margin; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + x += xx * 8; +#else if (p->fontwidthlog) x += (xx << p->fontwidthlog); else x += xx * p->fontwidth; +#endif if (p->fontheightlog) y += (yy << p->fontheightlog); else y += (yy * p->fontheight); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif while (count >= 4) { count -= 4; fbc->incx = 0; @@ -379,20 +394,23 @@ fbc->x1 = (x += 4 * p->fontwidth) - 1; fbc->y0 = y; if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); + fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); } else { - fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight); + fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth == 8) { +#endif for (i = 0; i < p->fontheight; i++) fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) << 8)) << 8)) << 8); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { for (i = 0; i < p->fontheight; i++) fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) @@ -408,17 +426,18 @@ fbc->x1 = (x += 2 * p->fontwidth) - 1; fbc->y0 = y; if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1)); - fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1)); + fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); + fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); } else { - fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1); - fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1); + fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); + fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); } for (i = 0; i < p->fontheight; i++) { fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth); fd1 += 2; fd2 += 2; } } +#endif } while (count) { count--; @@ -428,13 +447,16 @@ fbc->x1 = (x += p->fontwidth) - 1; fbc->y0 = y; if (p->fontheightlog) - i = ((*s++ & 0xff) << p->fontheightlog); + i = ((*s++ & p->charmask) << p->fontheightlog); else - i = ((*s++ & 0xff) * p->fontheight); + i = ((*s++ & p->charmask) * p->fontheight); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif fd1 = p->fontdata + i; for (i = 0; i < p->fontheight; i++) fbc->font = *fd1++ << 24; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { fd1 = p->fontdata + (i << 1); for (i = 0; i < p->fontheight; i++) { @@ -442,6 +464,7 @@ fd1 += 2; } } +#endif } } @@ -466,7 +489,6 @@ static void cg6_restore_palette (struct fb_info_sbusfb *fb) { struct bt_regs *bt = fb->s.cg6.bt; - int i; bt->addr = 0; bt->color_map = 0xffffffff; @@ -592,10 +614,7 @@ strcpy(fb->info.modename, "CGsix"); strcpy(fix->id, "CGsix"); - fix->smem_start = (char *)phys + CG6_RAM_OFFSET; fix->line_length = fb->var.xres_virtual; - fix->mmio_start = (char *)phys + CG6_FBC_OFFSET; - fix->mmio_len = PAGE_SIZE; fix->accel = FB_ACCEL_SUN_CGSIX; var->accel_flags = FB_ACCELF_TEXT; @@ -648,7 +667,12 @@ default: p = "i386"; break; } - sprintf(idstring, "cgsix at %02x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, + sprintf(idstring, +#ifdef __sparc_v9__ + "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys, +#else + "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, +#endif (fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK, p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK); diff -u --recursive --new-file v2.1.111/linux/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c --- v2.1.111/linux/drivers/video/cgthreefb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/cgthreefb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,247 @@ +/* $Id: cgthreefb.c,v 1.1 1998/07/21 14:50:47 jj Exp $ + * cgthreefb.c: CGthree frame buffer driver + * + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sbusfb.h" +#include + +#include "fbcon-cfb8.h" + +/* Control Register Constants */ +#define CG3_CR_ENABLE_INTS 0x80 +#define CG3_CR_ENABLE_VIDEO 0x40 +#define CG3_CR_ENABLE_TIMING 0x20 +#define CG3_CR_ENABLE_CURCMP 0x10 +#define CG3_CR_XTAL_MASK 0x0c +#define CG3_CR_DIVISOR_MASK 0x03 + +/* Status Register Constants */ +#define CG3_SR_PENDING_INT 0x80 +#define CG3_SR_RES_MASK 0x70 +#define CG3_SR_1152_900_76_A 0x40 +#define CG3_SR_1152_900_76_B 0x60 +#define CG3_SR_ID_MASK 0x0f +#define CG3_SR_ID_COLOR 0x01 +#define CG3_SR_ID_MONO 0x02 +#define CG3_SR_ID_MONO_ECL 0x03 + +enum cg3_type { + CG3_AT_66HZ = 0, + CG3_AT_76HZ, + CG3_RDI +}; + +struct cg3_regs { + struct bt_regs cmap; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; +}; + +/* Offset of interesting structures in the OBIO space */ +#define CG3_REGS_OFFSET 0x400000 +#define CG3_RAM_OFFSET 0x800000 + +static struct sbus_mmap_map cg3_mmap_map[] = { + { CG3_MMAP_OFFSET, CG3_RAM_OFFSET, SBUS_MMAP_FBSIZE(1) }, + { 0, 0, 0 } +}; + +/* The cg3 palette is loaded with 4 color values at each time */ +/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */ + +#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */ +#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */ + +static void cg3_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +{ + struct bt_regs *bt = &fb->s.cg3.regs->cmap; + u32 *i; + int steps; + + i = (((u32 *)fb->color_map) + D4M3(index)); + steps = D4M3(index+count-1) - D4M3(index)+3; + + *(volatile u8 *)&bt->addr = (u8)D4M4(index); + while (steps--) + bt->color_map = *i++; +} + +static void cg3_blank (struct fb_info_sbusfb *fb) +{ + fb->s.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO; +} + +static void cg3_unblank (struct fb_info_sbusfb *fb) +{ + fb->s.cg3.regs->control |= CG3_CR_ENABLE_VIDEO; +} + +static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) +{ + p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin); +} + +static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */ + 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, + 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x20, 0 +}; + +static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */ + 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, + 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, + 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x24, 0 +}; + +static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */ + 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10, + 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51, + 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01, + 0x10, 0x22, 0 +}; + +static u8 *cg3_regvals[] __initdata = { + cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi +}; + +static u_char cg3_dacvals[] __initdata = { + 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0 +}; + +static char idstring[60] __initdata = { 0 }; + +__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb)) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct display *disp = &fb->disp; + struct fbtype *type = &fb->type; + unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; + int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL; + +#ifndef FBCON_HAS_CFB8 + return NULL; +#endif + + if (!fb->s.cg3.regs) { + fb->s.cg3.regs = (struct cg3_regs *)sparc_alloc_io(phys+CG3_REGS_OFFSET, 0, + sizeof(struct cg3_regs), "cg3_regs", fb->iospace, 0); + if (cgRDI) { + char buffer[40]; + char *p; + int ww, hh; + + *buffer = 0; + prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer)); + if (*buffer) { + ww = simple_strtoul (buffer, &p, 10); + if (ww && *p == 'x') { + hh = simple_strtoul (p + 1, &p, 10); + if (hh && *p == '-') { + if (type->fb_width != ww || type->fb_height != hh) { + type->fb_width = ww; + type->fb_height = hh; + return SBUSFBINIT_SIZECHANGE; + } + } + } + } + } + } + + strcpy(fb->info.modename, "CGthree"); + strcpy(fix->id, "CGthree"); + fix->line_length = fb->var.xres_virtual; + + disp->scrollmode = SCROLL_YREDRAW; + if (!disp->screen_base) + disp->screen_base = (char *)sparc_alloc_io(phys+CG3_RAM_OFFSET, 0, + type->fb_size, "cg3_ram", fb->iospace, 0); + disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; + fb->dispsw = fbcon_cfb8; + + fb->margins = cg3_margins; + fb->loadcmap = cg3_loadcmap; + fb->blank = cg3_blank; + fb->unblank = cg3_unblank; + + fb->physbase = phys; + fb->mmap_map = cg3_mmap_map; + +#ifdef __sparc_v9__ + sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys); +#else + sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys); +#endif + + if (!prom_getbool(fb->prom_node, "width")) { + /* Ugh, broken PROM didn't initialize us. + * Let's deal with this ourselves. + */ + enum cg3_type type; + u8 *p; + + if (cgRDI) + type = CG3_RDI; + else { + u8 status = fb->s.cg3.regs->status, mon; + if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) { + mon = status & CG3_SR_RES_MASK; + if (mon == CG3_SR_1152_900_76_A || + mon == CG3_SR_1152_900_76_B) + type = CG3_AT_76HZ; + else + type = CG3_AT_66HZ; + } else { + prom_printf("cgthree: can't handle SR %02x\n", + status); + prom_halt(); + return NULL; /* fool gcc. */ + } + } + + for (p = cg3_regvals[type]; *p; p += 2) + ((u8 *)fb->s.cg3.regs)[p[0]] = p[1]; + + for (p = cg3_dacvals; *p; p += 2) { + *(volatile u8 *)&fb->s.cg3.regs->cmap.addr = p[0]; + *(volatile u8 *)&fb->s.cg3.regs->cmap.control = p[1]; + } + } + + return idstring; +} diff -u --recursive --new-file v2.1.111/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c --- v2.1.111/linux/drivers/video/clgenfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/clgenfb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,2122 @@ +/* + * Based on retz3fb.c and clgen.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fbcon.h" + +#include "fbcon.h" +#include "fbcon-mfb.h" +#include "fbcon-cfb8.h" +#include "fbcon-cfb16.h" +#include "fbcon-cfb24.h" +#include "fbcon-cfb32.h" + +#include "clgenfb.h" + +#define CLGEN_VERSION "1.4 ?" +/* #define DEBUG if(1) */ +#define DEBUG if(0) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +/* zorro IDs */ +#define ZORRO_PROD_HELFRICH_SD64_RAM 0x08930A00 +#define ZORRO_PROD_HELFRICH_SD64_REG 0x08930B00 +#define ZORRO_PROD_HELFRICH_PICCOLO_RAM 0x08930500 +#define ZORRO_PROD_HELFRICH_PICCOLO_REG 0x08930600 +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM 0x08770B00 +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG 0x08770C00 +#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM 0x08910200 +#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG 0x08910100 +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 0x08771800 + +/* board types */ +#define BT_NONE 0 +#define BT_SD64 1 +#define BT_PICCOLO 2 +#define BT_PICASSO 3 +#define BT_SPECTRUM 4 +#define BT_PICASSO4 5 + +#define MAX_NUM_BOARDS 7 + +#define TRUE 1 +#define FALSE 0 + +struct clgenfb_par +{ + struct fb_var_screeninfo var; + + __u32 line_length; /* in BYTES! */ + __u32 visual; + __u32 type; + + long freq; + long nom; + long den; + long div; + + long HorizRes; /* The x resolution in pixel */ + long HorizTotal; + long HorizDispEnd; + long HorizBlankStart; + long HorizBlankEnd; + long HorizSyncStart; + long HorizSyncEnd; + + long VertRes; /* the physical y resolution in scanlines */ + long VertTotal; + long VertDispEnd; + long VertSyncStart; + long VertSyncEnd; + long VertBlankStart; + long VertBlankEnd; +}; + +/* info about board */ +struct clgenfb_info +{ + struct fb_info_gen gen; + + int keyRAM; /* RAM, REG zorro board keys */ + int keyREG; + unsigned long fbmem; + volatile unsigned char *regs; + unsigned long mem; + unsigned long size; + int btype; + int smallboard; + unsigned char SFR; /* Shadow of special function register */ + + struct clgenfb_par currentmode; +}; + +static struct display disp; + +static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */ +static struct clgenfb_info *fb_info=NULL; /* pointer to current board */ + +/* + * Predefined Video Modes + */ + +static struct fb_videomode clgenfb_predefined[] __initdata = +{ + { "Autodetect", /* autodetect mode */ + { 0 } + }, + + { "640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */ + { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 40000, 32, 32, 33, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + }, + + /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */ + /* + Modeline from XF86Config: + Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805 + */ + { + "1024x768", + { + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + } +}; + +#define NUM_TOTAL_MODES arraysize(clgenfb_predefined) +static struct fb_var_screeninfo clgenfb_default; + +/* + * Frame Buffer Name + */ + +static char clgenfb_name[16] = "CLgen"; + +/****************************************************************************/ +/**** BEGIN PROTOTYPES ******************************************************/ + +/*--- Interface used by the world ------------------------------------------*/ +void clgenfb_init(void); +void clgenfb_setup(char *options, int *ints); +int clgenfb_open(struct fb_info *info, int user); +int clgenfb_release(struct fb_info *info, int user); +int clgenfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + +/* function table of the above functions */ +static struct fb_ops clgenfb_ops = +{ + clgenfb_open, + clgenfb_release, + fbgen_get_fix, /* using the generic functions */ + fbgen_get_var, /* makes things much easier... */ + fbgen_set_var, + fbgen_get_cmap, + fbgen_set_cmap, + fbgen_pan_display, + clgenfb_ioctl, + NULL +}; + +/*--- Hardware Specific Routines -------------------------------------------*/ +static void clgen_detect(void); +static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par, + struct fb_info_gen *info); +static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par, + struct fb_info_gen *info); +static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par, + struct fb_info_gen *info); +static void clgen_get_par(void *par, struct fb_info_gen *info); +static void clgen_set_par(const void *par, struct fb_info_gen *info); +static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info); +static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int clgen_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info); +static int clgen_blank(int blank_mode, struct fb_info_gen *info); + +static struct display_switch *clgen_get_dispsw(const void *par, + struct fb_info_gen *info); + +/* function table of the above functions */ +static struct fbgen_hwswitch clgen_hwswitch = +{ + clgen_detect, + clgen_encode_fix, + clgen_decode_var, + clgen_encode_var, + clgen_get_par, + clgen_set_par, + clgen_getcolreg, + clgen_setcolreg, + clgen_pan_display, + clgen_blank, + clgen_get_dispsw +}; + +/* Text console acceleration */ + +#ifdef FBCON_HAS_CFB8 +static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, + int dy, int dx, int height, int width); +static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, + int sy, int sx, int height, int width); + +static struct display_switch fbcon_clgen_8 = { + fbcon_cfb8_setup, + fbcon_clgen8_bmove, + fbcon_clgen8_clear, + fbcon_cfb8_putc, + fbcon_cfb8_putcs, + fbcon_cfb8_revc, + NULL, + NULL, + fbcon_cfb8_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + + + +/*--- Internal routines ----------------------------------------------------*/ +static void init_vgachip(void); +static void switch_monitor(int on); + +static void WGen( int regnum, unsigned char val ); +static unsigned char RGen( int regnum ); +static void WSeq( unsigned char regnum, unsigned char val ); +static unsigned char RSeq( unsigned char regnum ); +static void WCrt( unsigned char regnum, unsigned char val ); +static unsigned char RCrt( unsigned char regnum ); +static void WGfx( unsigned char regnum, unsigned char val ); +static unsigned char RGfx( unsigned char regnum ); +static void WAttr( unsigned char regnum, unsigned char val ); +static void AttrOn( void ); +static unsigned char RAttr( unsigned char regnum ); +static void WHDR( unsigned char val ); +static unsigned char RHDR( void ); +static void WSFR( unsigned char val ); +static void WSFR2( unsigned char val ); +static void WClut( unsigned char regnum, unsigned char red, + unsigned char green, + unsigned char blue ); +static void RClut( unsigned char regnum, unsigned char *red, + unsigned char *green, + unsigned char *blue ); +static void clgen_WaitBLT( void ); +static void clgen_BitBLT (u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length); +static void clgen_RectFill (u_short x, u_short y, + u_short width, u_short height, + u_char color, u_short line_length); + +static void bestclock(long freq, long *best, + long *nom, long *den, + long *div, long maxfreq); + +/*** END PROTOTYPES ********************************************************/ +/*****************************************************************************/ +/*** BEGIN Interface Used by the World ***************************************/ + +static int opencount = 0; + +/*--- Open /dev/fbx ---------------------------------------------------------*/ +int clgenfb_open(struct fb_info *info, int user) +{ + MOD_INC_USE_COUNT; + if (opencount++ == 0) switch_monitor(1); + return 0; +} + +/*--- Close /dev/fbx --------------------------------------------------------*/ +int clgenfb_release(struct fb_info *info, int user) +{ + if (--opencount == 0) switch_monitor(0); + MOD_DEC_USE_COUNT; + return 0; +} + +/*--- handle /dev/fbx ioctl calls ------------------------------------------*/ +int clgenfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + printk(">clgenfb_ioctl()\n"); + /* Nothing exciting here... */ + printk("clgen_detect()\n"); + printk("id, clgenfb_name); + + fix->smem_start = (char*)_info->fbmem; + + /* monochrome: only 1 memory plane */ + /* 8 bit and above: Use whole memory area */ + fix->smem_len = _par->var.bits_per_pixel == 1 ? _info->size / 4 + : _info->size; + fix->type = _par->type; + fix->type_aux = 0; + fix->visual = _par->visual; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = _par->line_length; + fix->mmio_start = (char *)_info->regs; + fix->mmio_len = 0x10000; + fix->accel = FB_ACCEL_NONE; + + return 0; +} + +static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par, + struct fb_info_gen *info) +{ + long freq; + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + int nom,den; /* translyting from pixels->bytes */ + int i; + static struct + { + int xres,yres; + } + modes[] = { {1600,1280}, {1280,1024}, {1024,768}, + {800,600}, {640,480}, {-1,-1} }; + + struct clgenfb_par *_par = (struct clgenfb_par *)par; + + fb_info = (struct clgenfb_info*)info; + printk("clgen_decode_var()\n"); + + printk("Requested: %dx%dx%d\n", var->xres,var->yres,var->bits_per_pixel); + printk(" virtual: %dx%d\n", var->xres_virtual,var->yres_virtual); + printk(" offset: (%d,%d)\n", var->xoffset, var->yoffset); + printk("grayscale: %d\n", var->grayscale); +#if 0 + printk(" activate: 0x%x\n", var->activate); + printk(" pixclock: %d\n", var->pixclock); + printk(" htiming: %d;%d %d\n", var->left_margin,var->right_margin,var->hsync_len); + printk(" vtiming: %d;%d %d\n", var->upper_margin,var->lower_margin,var->vsync_len); + printk(" sync: 0x%x\n", var->sync); + printk(" vmode: 0x%x\n", var->vmode); +#endif + + _par->var = *var; + + switch (var->bits_per_pixel) + { + case 1: nom = 4; den = 8; break; /* 8 pixel per byte, only 1/4th of mem usable */ + case 8: nom = 1; den = 1; break; /* 1 pixel == 1 byte */ + case 16: nom = 2; den = 1; break; /* 2 bytes per pixel */ + case 24: nom = 3; den = 1; break; /* 3 bytes per pixel */ + case 32: nom = 4; den = 1; break; /* 4 bytes per pixel */ + default: + printk("clgen: mode %dx%dx%d rejected...color depth not supported.\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (_par->var.xres*nom/den * _par->var.yres > fb_info->size) + { + printk("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + /* use highest possible virtual resolution */ + if (_par->var.xres_virtual == -1 && + _par->var.xres_virtual == -1) + { + printk("clgen: using maximum available virtual resolution\n"); + for (i=0; modes[i].xres != -1; i++) + { + if (modes[i].xres*nom/den * modes[i].yres < fb_info->size/2) + break; + } + if (modes[i].xres == -1) + { + printk("clgen: could not find a virtual resolution that fits into video memory!!\n"); + return -EINVAL; + } + _par->var.xres_virtual = modes[i].xres; + _par->var.yres_virtual = modes[i].yres; + + printk("clgen: virtual resolution set to maximum of %dx%d\n", + _par->var.xres_virtual, _par->var.yres_virtual); + } + else if (_par->var.xres_virtual == -1) + { + } + else if (_par->var.yres_virtual == -1) + { + } + + if (_par->var.xoffset < 0) _par->var.xoffset = 0; + if (_par->var.yoffset < 0) _par->var.yoffset = 0; + + /* truncate xoffset and yoffset to maximum if too high */ + if (_par->var.xoffset > _par->var.xres_virtual-_par->var.xres) + _par->var.xoffset = _par->var.xres_virtual-_par->var.xres -1; + + if (_par->var.yoffset > _par->var.yres_virtual-_par->var.yres) + _par->var.yoffset = _par->var.yres_virtual-_par->var.yres -1; + + switch (var->bits_per_pixel) + { + case 1: + _par->line_length = _par->var.xres_virtual / 8; + _par->visual = FB_VISUAL_MONO10; + break; + + case 8: + _par->line_length = _par->var.xres_virtual; + _par->visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + _par->line_length = _par->var.xres_virtual * 2; + _par->visual = FB_VISUAL_DIRECTCOLOR; + break; + + case 24: + _par->line_length = _par->var.xres_virtual * 3; + _par->visual = FB_VISUAL_DIRECTCOLOR; + break; + + case 32: + _par->line_length = _par->var.xres_virtual * 4; + _par->visual = FB_VISUAL_DIRECTCOLOR; + break; + } + _par->type = FB_TYPE_PACKED_PIXELS; + + /* convert from ps to kHz */ + freq = 1000000000 / var->pixclock; + + DEBUG printk("desired pixclock: %ld kHz\n", freq); + + /* the SD64/P4 have a higher max. videoclock */ + bestclock(freq, &_par->freq, &_par->nom, &_par->den, &_par->div, + fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4 + ? 140000 : 90000); + + DEBUG printk("Best possible values for given frequency: best: %ld kHz nom: %ld den: %ld div: %ld\n", + _par->freq, _par->nom, _par->den, _par->div); + + xres = _par->var.xres; + hfront = _par->var.right_margin; + hsync = _par->var.hsync_len; + hback = _par->var.left_margin; + + yres = _par->var.yres; + vfront = _par->var.lower_margin; + vsync = _par->var.vsync_len; + vback = _par->var.upper_margin; + + if (_par->var.vmode & FB_VMODE_DOUBLE) + { + yres *= 2; + vfront *= 2; + vsync *= 2; + vback *= 2; + } + else if (_par->var.vmode & FB_VMODE_INTERLACED) + { + yres = ++yres / 2; + vfront = ++vfront / 2; + vsync = ++vsync / 2; + vback = ++vback / 2; + } + + _par->HorizRes = xres; + _par->HorizTotal = (xres + hfront + hsync + hback)/8 - 5; + _par->HorizDispEnd = xres/8 - 1; + _par->HorizBlankStart = xres/8; + _par->HorizBlankEnd = _par->HorizTotal+5; /* does not count with "-5" */ + _par->HorizSyncStart = (xres + hfront)/8 + 1; + _par->HorizSyncEnd = (xres + hfront + hsync)/8 + 1; + + _par->VertRes = yres; + _par->VertTotal = yres + vfront + vsync + vback -2; + _par->VertDispEnd = yres - 1; + _par->VertBlankStart = yres; + _par->VertBlankEnd = _par->VertTotal; + _par->VertSyncStart = yres + vfront - 1; + _par->VertSyncEnd = yres + vfront + vsync - 1; + + if (_par->VertTotal >= 1024) + { + printk(KERN_WARNING "clgen: ERROR: VerticalTotal >= 1024; special treatment required! (TODO)\n"); + return -EINVAL; + } + + return 0; +} + + +static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par, + struct fb_info_gen *info) +{ + *var = ((struct clgenfb_par*)par)->var; + return 0; +} + +/* get current video mode */ +static void clgen_get_par(void *par, struct fb_info_gen *info) +{ + struct clgenfb_par *_par = (struct clgenfb_par*)par; + struct clgenfb_info*_info = (struct clgenfb_info*)fb_info; + + *_par = _info->currentmode; +} + +/************************************************************************* + clgen_set_par() + + actually writes the values for a new video mode into the hardware, +**************************************************************************/ +static void clgen_set_par(const void *par, struct fb_info_gen *info) +{ + unsigned char tmp; + int offset = 0; + struct clgenfb_par *_par = (struct clgenfb_par*)par; + + printk(KERN_INFO">clgen_set_par()\n"); + printk(KERN_INFO"Requested mode: %dx%dx%d\n", + _par->var.xres, _par->var.yres, _par->var.bits_per_pixel); + printk(KERN_INFO"pixclock: %d\n", _par->var.pixclock); + + fb_info = (struct clgenfb_info *)info; + + /* unlock register CRT0..CRT7 */ + WCrt(CRT11, 0x20); /* previously: 0x00) */ + + /* if DEBUG is set, all parameters get output before writing */ + DEBUG printk("CRT0: %ld\n", _par->HorizTotal); + WCrt(CRT0, _par->HorizTotal); + + DEBUG printk("CRT1: %ld\n", _par->HorizDispEnd); + WCrt(CRT1, _par->HorizDispEnd); + + DEBUG printk("CRT2: %ld\n", _par->HorizBlankStart); + WCrt(CRT2, _par->HorizBlankStart); + + DEBUG printk("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /* + 128: Compatible read */ + WCrt(CRT3, 128 + (_par->HorizBlankEnd % 32)); + + DEBUG printk("CRT4: %ld\n", _par->HorizSyncStart); + WCrt(CRT4, _par->HorizSyncStart); + + tmp = _par->HorizSyncEnd % 32; + if (_par->HorizBlankEnd & 32) + tmp += 128; + DEBUG printk("CRT5: %d\n", tmp); + WCrt(CRT5, tmp); + + DEBUG printk("CRT6: %ld\n", _par->VertTotal & 0xff); + WCrt(CRT6, (_par->VertTotal & 0xff)); + + tmp = 16; /* LineCompare bit #9 */ + if (_par->VertTotal & 256) tmp |= 1; + if (_par->VertDispEnd & 256) tmp |= 2; + if (_par->VertSyncStart & 256) tmp |= 4; + if (_par->VertBlankStart & 256) tmp |= 8; + if (_par->VertTotal & 512) tmp |= 32; + if (_par->VertDispEnd & 512) tmp |= 64; + if (_par->VertSyncStart & 512) tmp |= 128; + DEBUG printk("CRT7: %d\n", tmp); + WCrt(CRT7, tmp); + + tmp = 0x40; /* LineCompare bit #8 */ + if (_par->VertBlankStart & 512) tmp |= 0x20; + if (_par->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; + DEBUG printk("CRT9: %d\n", tmp); + WCrt(CRT9, tmp); + + DEBUG printk("CRT10: %ld\n", _par->VertSyncStart & 0xff); + WCrt(CRT10, (_par->VertSyncStart & 0xff)); + + DEBUG printk("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16); + WCrt(CRT11, (_par->VertSyncEnd % 16 + 64 + 32)); + + DEBUG printk("CRT12: %ld\n", _par->VertDispEnd & 0xff); + WCrt(CRT12, (_par->VertDispEnd & 0xff)); + + DEBUG printk("CRT15: %ld\n", _par->VertBlankStart & 0xff); + WCrt(CRT15, (_par->VertBlankStart & 0xff)); + + DEBUG printk("CRT16: %ld\n", _par->VertBlankEnd & 0xff); + WCrt(CRT16, (_par->VertBlankEnd & 0xff)); + + DEBUG printk("CRT18: 0xff\n"); + WCrt(CRT18, 0xff); + + tmp = 0; + if (_par->var.vmode & FB_VMODE_INTERLACED) tmp |= 1; + if (_par->HorizBlankEnd & 64) tmp |= 16; + if (_par->HorizBlankEnd & 128) tmp |= 32; + if (_par->VertBlankEnd & 256) tmp |= 64; + if (_par->VertBlankEnd & 512) tmp |= 128; + + DEBUG printk("CRT1a: %d\n", tmp); + WCrt(CRT1A, tmp); + + /* set VCLK0 */ + /* hardware RefClock: 14.31818 MHz */ + /* formula: VClk = (OSC * N) / (D * (1+P)) */ + /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ + + WSeq(SEQRB, _par->nom); + tmp = _par->den<<1; + if (_par->div != 0) tmp |= 1; + + if (fb_info->btype == BT_SD64) + tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ + + WSeq(SEQR1B, tmp); + + WCrt(CRT17, 0xc3); /* mode control: CRTC enable, ROTATE(?), 16bit address wrap, no compat. */ + +/* HAEH? WCrt(CRT11, 0x20); * previously: 0x00 unlock CRT0..CRT7 */ + + /* don't know if it would hurt to also program this if no interlaced */ + /* mode is used, but I feel better this way.. :-) */ + if (_par->var.vmode & FB_VMODE_INTERLACED) + WCrt(CRT19, _par->HorizTotal / 2); + else + WCrt(CRT19, 0x00); /* interlace control */ + + WSeq(SEQR3, 0); + + /* adjust horizontal/vertical sync type (low/high) */ + tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */ + if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40; + if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80; + WGen(MISC_W, tmp); + + WCrt(CRT8, 0); /* Screen A Preset Row-Scan register */ + WCrt(CRTA, 0); /* text cursor on and start line */ + WCrt(CRTB, 31); /* text cursor end line */ + + /* programming for different color depths */ + if (_par->var.bits_per_pixel == 1) + { + DEBUG printk(KERN_INFO "clgen: preparing for 1 bit deep display\n"); +#if 0 + /* restore first 2 color registers for mono mode */ + WClut( 0, 0x00, 0x00, 0x00); /* background: black */ + WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */ +#endif + WGfx(GR5, 0); /* mode register */ + + /* Extended Sequencer Mode */ + switch(fb_info->btype) + { + case BT_SD64: + /* setting the SEQRF on SD64 is not necessary (only during init) */ + DEBUG printk(KERN_INFO "(for SD64)\n"); + WSeq(SEQR7, 0xf0); + WSeq(SEQR1F, 0x1a); /* MCLK select */ + break; + + case BT_PICCOLO: + DEBUG printk(KERN_INFO "(for Piccolo)\n"); + WSeq(SEQR7, 0x80); +/* ### ueberall 0x22? */ + WSeq(SEQR1F, 0x22); /* ##vorher 1c MCLK select */ + WSeq(SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ + break; + + case BT_PICASSO: + DEBUG printk(KERN_INFO "(for Picasso)\n"); + WSeq(SEQR7, 0x20); + WSeq(SEQR1F, 0x22); /* ##vorher 22 MCLK select */ + WSeq(SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */ + break; + + case BT_SPECTRUM: + DEBUG printk(KERN_INFO "(for Spectrum)\n"); + WSeq(SEQR7, 0x80); +/* ### ueberall 0x22? */ + WSeq(SEQR1F, 0x22); /* ##vorher 1c MCLK select */ + WSeq(SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */ + break; + + case BT_PICASSO4: + DEBUG printk(KERN_INFO "(for Picasso 4)\n"); + WSeq(SEQR7, 0x20); +/* WSeq(SEQR1F, 0x1c); */ +/* SEQRF not being set here... WSeq(SEQRF, 0xd0); */ + break; + + default: + printk(KERN_WARNING "clgen: unknown Board\n"); + break; + } + + WGen(M_3C6,0x01); /* pixel mask: pass-through for first plane */ + WHDR(0); /* hidden dac reg: nothing special */ + WSeq(SEQR4, 0x06); /* memory mode: odd/even, ext. memory */ + WSeq(SEQR2, 0x01); /* plane mask: only write to first plane */ + offset = _par->var.xres_virtual / 16; + } + else if (_par->var.bits_per_pixel == 8) + { + DEBUG printk(KERN_INFO "clgen: preparing for 8 bit deep display\n"); + switch(fb_info->btype) + { + case BT_SD64: + WSeq(SEQR7, 0xf1); /* Extended Sequencer Mode: 256c col. mode */ + WSeq(SEQR1F, 0x1d); /* MCLK select */ + break; + + case BT_PICCOLO: + WSeq(SEQR7, 0x81); + WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_PICASSO: + WSeq(SEQR7, 0x21); + WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_SPECTRUM: + WSeq(SEQR7, 0x81); + WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */ + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + break; + + case BT_PICASSO4: + WSeq(SEQR7, 0x21); + WSeq(SEQRF, 0xb8); /* ### INCOMPLETE!! */ +/* WSeq(SEQR1F, 0x1c); */ + break; + + default: + printk(KERN_WARNING "clgen: unknown Board\n"); + break; + } + + WGfx(GR5, 64); /* mode register: 256 color mode */ + WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */ + WHDR(0); /* hidden dac reg: nothing special */ + WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */ + WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = _par->var.xres_virtual / 8; + } + else if (_par->var.bits_per_pixel == 16) + { + DEBUG printk(KERN_INFO "clgen: preparing for 16 bit deep display\n"); + switch(fb_info->btype) + { + case BT_SD64: + WSeq(SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */ + WSeq(SEQR1F, 0x1e); /* MCLK select */ + break; + + case BT_PICCOLO: + WSeq(SEQR7, 0x87); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO: + WSeq(SEQR7, 0x27); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_SPECTRUM: + WSeq(SEQR7, 0x87); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO4: + WSeq(SEQR7, 0x27); +/* WSeq(SEQR1F, 0x1c); */ + break; + + default: + printk(KERN_WARNING "CLGEN: unknown Board\n"); + break; + } + + WGfx(GR5, 64); /* mode register: 256 color mode */ + WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */ + WHDR(0xa0); /* hidden dac reg: nothing special */ + WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */ + WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = _par->var.xres_virtual / 4; + } + else if (_par->var.bits_per_pixel == 32) + { + DEBUG printk(KERN_INFO "clgen: preparing for 24/32 bit deep display\n"); + switch(fb_info->btype) + { + case BT_SD64: + WSeq(SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */ + WSeq(SEQR1F, 0x1e); /* MCLK select */ + break; + + case BT_PICCOLO: + WSeq(SEQR7, 0x85); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO: + WSeq(SEQR7, 0x25); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_SPECTRUM: + WSeq(SEQR7, 0x85); + WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */ + WSeq(SEQR1F, 0x22); /* MCLK select */ + break; + + case BT_PICASSO4: + WSeq(SEQR7, 0x25); +/* WSeq(SEQR1F, 0x1c); */ + break; + + default: + printk(KERN_WARNING "clgen: unknown Board\n"); + break; + } + + WGfx(GR5, 64); /* mode register: 256 color mode */ + WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */ + WHDR(0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */ + WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */ + WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */ + offset = _par->var.xres_virtual / 4; + } + else + printk(KERN_ERR "clgen: What's this?? requested color depth == %d.\n", + _par->var.bits_per_pixel); + + WCrt(CRT13, offset & 0xff); + tmp = 0x22; + if (offset & 0x100) tmp |= 0x10; /* offset overflow bit */ + + WCrt(CRT1B,tmp); /* screen start addr #16-18, fastpagemode cycles */ + + if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4) + WCrt(CRT1D, 0x00); /* screen start address bit 19 */ + + WCrt(CRTE, 0); /* text cursor location high */ + WCrt(CRTF, 0); /* text cursor location low */ + WCrt(CRT14, 0); /* underline row scanline = at very bottom */ + + WAttr(AR10, 1); /* controller mode */ + WAttr(AR11, 0); /* overscan (border) color */ + WAttr(AR12, 15); /* color plane enable */ + WAttr(AR33, 0); /* pixel panning */ + WAttr(AR14, 0); /* color select */ + + /* [ EGS: SetOffset(); ] */ + /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ + AttrOn(); + + WGfx(GR0, 0); /* set/reset register */ + WGfx(GR1, 0); /* set/reset enable */ + WGfx(GR2, 0); /* color compare */ + WGfx(GR3, 0); /* data rotate */ + WGfx(GR4, 0); /* read map select */ + WGfx(GR6, 1); /* miscellaneous register */ + WGfx(GR7, 15); /* color don't care */ + WGfx(GR8, 255); /* bit mask */ + + WSeq(SEQR12, 0x0); /* graphics cursor attributes: nothing special */ + + /* finally, turn on everything - turn off "FullBandwidth" bit */ + /* also, set "DotClock%2" bit where requested */ + tmp = 0x01; + +/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ? + if (var->vmode & FB_VMODE_CLOCK_HALVE) + tmp |= 0x08; +*/ + + WSeq(SEQR1, tmp); + DEBUG printk("SEQR1: %d\n", tmp); + +#if 0 + DEBUG printk(KERN_INFO "clgen: clearing display..."); + clgen_RectFill(0, 0, _par->HorizRes, _par->VertRes, 0, _par->line_length); + clgen_WaitBLT(); + DEBUG printk("done.\n"); +#endif + + fb_info->currentmode = *_par; + + printk("virtual offset: (%d,%d)\n", _par->var.xoffset,_par->var.yoffset); + /* pan to requested offset */ + clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen*)fb_info); + + DEBUG printk(" 255 || regno < 0) + return (1); + + fb_info = (struct clgenfb_info *)info; + + RClut(regno, &bred, &bgreen, &bblue); + + *red = (u_int)bred; + *green = (u_int)bgreen; + *blue = (u_int)bblue; + *transp = 0; + return (0); +} + +static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + if (regno > 255 || regno < 0) + return (1); + + fb_info = (struct clgenfb_info *)info; + + /* "transparent" stuff is completely ignored. */ + WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff)); + + return (0); +} + +/************************************************************************* + clgen_pan_display() + + performs display panning - provided hardware permits this +**************************************************************************/ +static int clgen_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) +{ + int xoffset = 0; + int yoffset = 0; + unsigned long base; + unsigned char tmp = 0, tmp2 = 0, xpix; + + fb_info = (struct clgenfb_info*)fb_info; + + /* no range checks for xoffset and yoffset, */ + /* as fbgen_pan_display has already done this */ + + fb_info->currentmode.var.xoffset = var->xoffset; + fb_info->currentmode.var.yoffset = var->yoffset; + + xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8; + yoffset = var->yoffset; + + base = yoffset * fb_info->currentmode.line_length + xoffset; + + if (fb_info->currentmode.var.bits_per_pixel == 1) + { + /* base is already correct */ + xpix = (unsigned char)(var->xoffset % 8); + } + else + { + base /= 4; + xpix = (unsigned char)((xoffset % 4) * 2); + } + + /* lower 8 + 8 bits of screen start address */ + WCrt(CRTD, (unsigned char)(base & 0xff)); + WCrt(CRTC, (unsigned char)(base >> 8)); + + /* construct bits 16, 17 and 18 of screen start address */ + if (base & 0x10000) tmp |= 0x01; + if (base & 0x20000) tmp |= 0x04; + if (base & 0x40000) tmp |= 0x08; + + tmp2 = (RCrt(CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */ + WCrt(CRT1B, tmp2); + /* construct bit 19 of screen start address (only on SD64) */ + if (fb_info->btype == BT_SD64 || + fb_info->btype == BT_PICASSO4) + { + tmp2 = 0; + if (base & 0x80000) tmp2 = 0x80; + WCrt(CRT1D, tmp2); + } + + /* write pixel panning value to AR33; this does not quite work in 8bpp */ + /* ### Piccolo..? Will this work? */ + if (fb_info->currentmode.var.bits_per_pixel == 1) + WAttr(AR33, xpix); + + return(0); +} + + +static int clgen_blank(int blank_mode, struct fb_info_gen *info) +{ + unsigned char val; + printk(">clgen_blank(%d)\n",blank_mode); + + fb_info = (struct clgenfb_info *)info; + + val = RSeq(SEQR1); + if (blank_mode) + WSeq(SEQR1, val | 0x20); /* set "FullBandwidth" bit */ + else + WSeq(SEQR1, val & 0xdf); /* clear "FullBandwidth" bit */ + + printk("init_vgachip()\n"); + + /* reset board globally */ + switch(fb_info->btype) + { + case BT_SD64: WSFR(0x1f); udelay(500); WSFR(0x4f); udelay(500); break; + case BT_PICCOLO: WSFR(0x01); udelay(500); WSFR(0x51); udelay(500); break; + case BT_PICASSO: WSFR2(0xff); udelay(500); break; + case BT_SPECTRUM: WSFR(0x1f); udelay(500); WSFR(0x4f); udelay(500); break; + case BT_PICASSO4: + WCrt(CRT51, 0x00); /* disable flickerfixer */ + udelay(100000); + WGfx(GR2F, 0x00); /* from Klaus' NetBSD driver: */ + WGfx(GR33, 0x00); /* put blitter into 542x compat */ + WGfx(GR31, 0x00); /* mode */ + break; + + default: + printk(KERN_ERR "clgen: Warning: Unknown board type\n"); + break; + } + + /* "pre-set" a RAMsize; if the test succeeds, double it */ + if (fb_info->btype == BT_SD64 || + fb_info->btype == BT_PICASSO4) + fb_info->size = 0x400000; + else + fb_info->size = 0x200000; + + /* assume it's a "large memory" board (2/4 MB) */ + fb_info->smallboard = FALSE; + + /* the P4 is not fully initialized here; I rely on it having been */ + /* inited under AmigaOS already, which seems to work just fine */ + /* (Klaus advised to do it this way) */ + + if (fb_info->btype != BT_PICASSO4) + { + WGen(VSSM, 0x10); /* EGS: 0x16 */ + WGen(POS102, 0x01); + WGen(VSSM, 0x08); /* EGS: 0x0e */ + + if(fb_info->btype != BT_SD64) + WGen(VSSM2, 0x01); + + WSeq(SEQR0, 0x03); /* reset sequencer logic */ + + WSeq(SEQR1, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */ + WGen(MISC_W, 0xc1); /* polarity (-/-), disable access to display memory, CRTC base address: color */ + +/* WGfx(GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */ + WSeq(SEQR6, 0x12); /* unlock all extension registers */ + + WGfx(GR31, 0x04); /* reset blitter */ + + if (fb_info->btype == BT_SD64) + { + WSeq(SEQRF, 0xb8); /* 4 MB Ram SD64, disable CRT fifo(!), 64 bit bus */ + } + else + { + WSeq(SEQR16, 0x0f); /* Perf. Tuning: Fix value..(?) */ + WSeq(SEQRF, 0xb0); /* 2 MB DRAM, 8level write buffer, 32bit bus */ + } + } + + WSeq(SEQR2, 0xff); /* plane mask: nothing */ + WSeq(SEQR3, 0x00); /* character map select: doesn't even matter in gx mode */ + WSeq(SEQR4, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */ + + /* controller-internal base address of video memory */ + switch(fb_info->btype) + { + case BT_SD64: WSeq(SEQR7, 0xf0); break; + case BT_PICCOLO: WSeq(SEQR7, 0x80); break; + case BT_SPECTRUM: WSeq(SEQR7, 0x80); break; + case BT_PICASSO: WSeq(SEQR7, 0x20); break; + case BT_PICASSO4: WSeq(SEQR7, 0x20); break; + } + +/* WSeq(SEQR8, 0x00);*/ /* EEPROM control: shouldn't be necessary to write to this at all.. */ + + WSeq(SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */ + WSeq(SEQR11, 0x00); /* graphics cursor Y position (..."... ) */ + WSeq(SEQR12, 0x00); /* graphics cursor attributes */ + WSeq(SEQR13, 0x00); /* graphics cursor pattern address */ + + /* writing these on a P4 might give problems.. */ + if (fb_info->btype != BT_PICASSO4) + { + WSeq(SEQR17, 0x00); /* configuration readback and ext. color */ + WSeq(SEQR18, 0x02); /* signature generator */ + } + + /* MCLK select etc. */ + switch(fb_info->btype) + { + case BT_PICCOLO: + case BT_PICASSO: + case BT_SPECTRUM: WSeq(SEQR1F, 0x22); break; + case BT_SD64: WSeq(SEQR1F, 0x20); break; + case BT_PICASSO4:/*WSeq(SEQR1F, 0x1c); */ break; + } + + WCrt(CRT8, 0x00); /* Screen A preset row scan: none */ + WCrt(CRTA, 0x20); /* Text cursor start: disable text cursor */ + WCrt(CRTB, 0x00); /* Text cursor end: - */ + WCrt(CRTC, 0x00); /* Screen start address high: 0 */ + WCrt(CRTD, 0x00); /* Screen start address low: 0 */ + WCrt(CRTE, 0x00); /* text cursor location high: 0 */ + WCrt(CRTF, 0x00); /* text cursor location low: 0 */ + + WCrt(CRT14, 0x00); /* Underline Row scanline: - */ + WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */ + WCrt(CRT18, 0x00); /* Line Compare: not needed */ + /* ### add 0x40 for text modes with > 30 MHz pixclock */ + WCrt(CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */ + + WGfx(GR0, 0x00); /* Set/Reset registes: - */ + WGfx(GR1, 0x00); /* Set/Reset enable: - */ + WGfx(GR2, 0x00); /* Color Compare: - */ + WGfx(GR3, 0x00); /* Data Rotate: - */ + WGfx(GR4, 0x00); /* Read Map Select: - */ + WGfx(GR5, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ + WGfx(GR6, 0x01); /* Miscellaneous: memory map base address, graphics mode */ + WGfx(GR7, 0x0f); /* Color Don't care: involve all planes */ + WGfx(GR8, 0xff); /* Bit Mask: no mask at all */ + WGfx(GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */ + + WGfx(GRC, 0xff); /* Color Key compare: - */ + WGfx(GRD, 0x00); /* Color Key compare mask: - */ + WGfx(GRE, 0x00); /* Miscellaneous control: - */ +/* WGfx(GR10, 0x00);*/ /* Background color byte 1: - */ +/* WGfx(GR11, 0x00); */ + + WAttr(AR0, 0x00); /* Attribute Controller palette registers: "identity mapping" */ + WAttr(AR1, 0x01); + WAttr(AR2, 0x02); + WAttr(AR3, 0x03); + WAttr(AR4, 0x04); + WAttr(AR5, 0x05); + WAttr(AR6, 0x06); + WAttr(AR7, 0x07); + WAttr(AR8, 0x08); + WAttr(AR9, 0x09); + WAttr(ARA, 0x0a); + WAttr(ARB, 0x0b); + WAttr(ARC, 0x0c); + WAttr(ARD, 0x0d); + WAttr(ARE, 0x0e); + WAttr(ARF, 0x0f); + + WAttr(AR10, 0x01); /* Attribute Controller mode: graphics mode */ + WAttr(AR11, 0x00); /* Overscan color reg.: reg. 0 */ + WAttr(AR12, 0x0f); /* Color Plane enable: Enable all 4 planes */ +/* ### WAttr(AR33, 0x00); * Pixel Panning: - */ + WAttr(AR14, 0x00); /* Color Select: - */ + + WGen(M_3C6, 0xff); /* Pixel mask: no mask */ + + WGen(MISC_W, 0xc3); /* polarity (-/-), enable display mem, CRTC i/o base = color */ + + WGfx(GR31, 0x04); /* BLT Start/status: Blitter reset */ + WGfx(GR31, 0x00); /* - " - : "end-of-reset" */ + + /* CLUT setup */ + WClut( 0, 0x00, 0x00, 0x00); /* background: black */ + WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */ + WClut( 2, 0x00, 0x80, 0x00); + WClut( 3, 0x00, 0x80, 0x80); + WClut( 4, 0x80, 0x00, 0x00); + WClut( 5, 0x80, 0x00, 0x80); + WClut( 6, 0x80, 0x40, 0x00); + WClut( 7, 0x80, 0x80, 0x80); + WClut( 8, 0x40, 0x40, 0x40); + WClut( 9, 0x40, 0x40, 0xc0); + WClut(10, 0x40, 0xc0, 0x40); + WClut(11, 0x40, 0xc0, 0xc0); + WClut(12, 0xc0, 0x40, 0x40); + WClut(13, 0xc0, 0x40, 0xc0); + WClut(14, 0xc0, 0xc0, 0x40); + WClut(15, 0xc0, 0xc0, 0xc0); + + /* the rest a grey ramp */ + { + int i; + + for (i = 16; i < 256; i++) + WClut(i, i, i, i); + } + + + /* misc... */ + WHDR(0); /* Hidden DAC register: - */ + +#if 0 + /* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */ + /* DRAM register has already been pre-set for "large", so it is*/ + /* only modified if we find that this is a "small" version */ + { + unsigned volatile char *ram = fb_info->fbmem; + int i, flag = 0; + + ram += (fb_info->size >> 1); + + for (i = 0; i < 256; i++) + ram[i] = (unsigned char)i; + + for (i = 0; i < 256; i++) + { + if (ram[i] != i) + flag = 1; + } + + /* if the DRAM test failed, halve RAM value */ + if (flag) + { + fb_info->size /= 2; + fb_info->smallboard = TRUE; + switch(fb_info->btype) + { + case BT_SD64: WSeq(SEQRF, 0x38); break; /* 2 MB Ram SD64 */ + case BT_PICASSO4: WSeq(SEQRF, 0x38); break; /* ### like SD64? */ + case BT_PICCOLO: + case BT_PICASSO: + case BT_SPECTRUM: WSeq(SEQRF, 0x30); break; /* 1 MB DRAM */ + default: + printk(KERN_WARNING "clgen: Uuhh..could not determine RAM size!\n"); + } + } + + } +#endif + printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size); + printk("btype == BT_PICASSO4) return; /* nothing to switch */ + if (fb_info->btype == BT_PICASSO) + { + if ((on && !IsOn) || (!on && IsOn)) + WSFR(0xff); + return; + } + if (on) + switch(fb_info->btype) + { + case BT_SD64: WSFR(fb_info->SFR | 0x21); break; + case BT_PICCOLO: WSFR(fb_info->SFR | 0x28); break; + case BT_SPECTRUM: WSFR(0x6f); break; + } + else + switch(fb_info->btype) + { + case BT_SD64: WSFR(fb_info->SFR & 0xde); break; + case BT_PICCOLO: WSFR(fb_info->SFR & 0xd7); break; + case BT_SPECTRUM: WSFR(0x4f); break; + } +} + +static struct display_switch *clgen_get_dispsw(const void *par, + struct fb_info_gen *info) +{ + struct clgenfb_par *_par = (struct clgenfb_par*) par; + + printk("clgen_get_dispsw(): "); + switch (_par->var.bits_per_pixel) + { +#ifdef FBCON_HAS_MFB + case 1: + printk("monochrome\n"); + return &fbcon_mfb; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + printk("8 bit color depth\n"); + return &fbcon_clgen_8; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + printk("16 bit color depth\n"); + return &fbcon_cfb16; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + printk("24 bit color depth\n"); + return &fbcon_cfb24; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + printk("32 bit color depth\n"); + return &fbcon_cfb32; +#endif + + default: + printk("unsupported color depth\n"); + return NULL; + } +} + +static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, + int dy, int dx, int height, int width) +{ + sx *= p->fontwidth; + sy *= p->fontheight; + dx *= p->fontwidth; + dy *= p->fontheight; + width *= p->fontwidth; + height *= p->fontheight; + + fb_info = (struct clgenfb_info*)p->fb_info; + + clgen_BitBLT((unsigned short)sx, (unsigned short)sy, + (unsigned short)dx, (unsigned short)dy, + (unsigned short)width, (unsigned short)height, + fb_info->currentmode.line_length); + clgen_WaitBLT(); +} + +static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, + int sy, int sx, int height, int width) +{ + unsigned short col; + + fb_info = (struct clgenfb_info*)p->fb_info; + + sx *= p->fontwidth; + sy *= p->fontheight; + width *= p->fontwidth; + height *= p->fontheight; + + col = attr_bgcol_ec(p, conp); + col &= 0xff; + + clgen_RectFill((unsigned short)sx, (unsigned short)sy, + (unsigned short)width,(unsigned short)height, + col, fb_info->currentmode.line_length); + clgen_WaitBLT(); +} + + +/********************************************************************/ +/* clgenfb_init() - master initialization function */ +/********************************************************************/ +__initfunc(void clgenfb_init(void)) +{ + const struct ConfigDev *cd = NULL; + const struct ConfigDev *cd2 = NULL; + int err; + int btype; + int key,key2; + unsigned long board_addr,board_size; + + printk(">clgenfb_init()\n"); + printk(KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n"); + + btype = -1; + + if ((key = zorro_find(ZORRO_PROD_HELFRICH_SD64_RAM, 0, 0))) + { + key2 = zorro_find(ZORRO_PROD_HELFRICH_SD64_REG, 0, 0); + btype = BT_SD64; + printk(KERN_INFO "clgen: SD64 board detected; "); + } + else if ((key = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_RAM, 0, 0))) + { + key2 = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_REG, 0, 0); + btype = BT_PICCOLO; + printk(KERN_INFO "clgen: Piccolo board detected; "); + } + else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, 0, 0))) + { + key2 = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, 0, 0); + btype = BT_PICASSO; + printk(KERN_INFO "clgen: Picasso II board detected; "); + } + else if ((key = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, 0, 0))) + { + key2 = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, 0, 0); + btype = BT_SPECTRUM; + printk(KERN_INFO "clgen: Spectrum board detected; "); + } + else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, 0, 0))) + { + btype = BT_PICASSO4; + printk(KERN_INFO "clgen: Picasso 4 board detected; "); + } + else + { + printk(KERN_NOTICE "clgen: no supported board found.\n"); + return; + } + + fb_info = &boards[0]; /* FIXME support multiple boards ...*/ + + fb_info->keyRAM = key; + fb_info->keyREG = key2; + fb_info->btype = btype; + + cd = zorro_get_board(key); + board_addr = (unsigned long)cd->cd_BoardAddr; + board_size = (unsigned long)cd->cd_BoardSize; + printk(" RAM (%lu MB) at $%lx, ", board_size/0x100000, board_addr); + + if (btype == BT_PICASSO4) + { + printk(" REG at $%lx\n", board_addr + 0x600000); + + /* To be precise, for the P4 this is not the */ + /* begin of the board, but the begin of RAM. */ + /* for P4, map in its address space in 2 chunks (### TEST! ) */ + /* (note the ugly hardcoded 16M number) */ + fb_info->regs = (unsigned char *)kernel_map(board_addr, 16777216, + KERNELMAP_NOCACHE_SER, NULL); + DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs); + fb_info->regs += 0x600000; + + fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216, + KERNELMAP_NOCACHE_SER, NULL); + DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem); + } + else + { + cd2 = zorro_get_board(key2); + printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr); + + if (board_addr > 0x01000000) + fb_info->fbmem = kernel_map(board_addr, board_size, + KERNELMAP_NOCACHE_SER, NULL); + else + fb_info->fbmem = ZTWO_VADDR(board_addr); + + /* set address for REG area of board */ + fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr); + + DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs); + DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem); + } + + init_vgachip(); + + /* set up a few more things, register framebuffer driver etc */ + fb_info->gen.parsize = sizeof(struct clgenfb_par); + fb_info->gen.fbhw = &clgen_hwswitch; + strcpy (fb_info->gen.info.modename, clgenfb_name); + fb_info->gen.info.node = -1; + fb_info->gen.info.fbops = &clgenfb_ops; + fb_info->gen.info.disp = &disp; + fb_info->gen.info.changevar = NULL; + fb_info->gen.info.switch_con = &fbgen_switch; + fb_info->gen.info.updatevar = &fbgen_update_var; + fb_info->gen.info.blank = &fbgen_blank; + + /* mark this board as "autoconfigured" */ + zorro_config_board(key, 0); + if (btype != BT_PICASSO4) + zorro_config_board(key2, 0); + + /* now that we know the board has been registered n' stuff, we */ + /* can finally initialize it to a default mode (640x480) */ + clgenfb_default = clgenfb_predefined[1].var; + clgenfb_default.activate = FB_ACTIVATE_NOW; + clgenfb_default.yres_virtual = 480*3; /* for fast scrolling (YPAN-Mode) */ + err = fbgen_do_set_var(&clgenfb_default, 1, &fb_info->gen); + + if (err) + return; + + disp.var = clgenfb_default; + fbgen_set_disp(-1, &fb_info->gen); + fbgen_install_cmap(0, &fb_info->gen); + + err = register_framebuffer(&fb_info->gen.info); + if (err) + { + printk(KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err); + return; + } + + printk("clgenfb_cleanup()\n"); + + fb_info = info; + + switch_monitor(0); + + zorro_unconfig_board(info->keyRAM, 0); + if (fb_info->btype != BT_PICASSO4) + zorro_unconfig_board(info->keyREG, 0); + + unregister_framebuffer(&info->gen.info); + printk("Framebuffer unregistered\n"); + printk("regs + regnum; + + if(fb_info->btype == BT_PICASSO) + { + /* Picasso II specific hack */ +/* if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */ + if (regnum == M_3C7_W || regnum == M_3C9) + reg += 0xfff; + } + + *reg = val; +} + +/*** RGen() - read out one of the external/general registers ***/ +unsigned char RGen(int regnum) +{ + unsigned volatile char *reg = fb_info->regs + regnum; + + if(fb_info->btype == BT_PICASSO) + { + /* Picasso II specific hack */ +/* if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */ + if (regnum == M_3C7_W || regnum == M_3C9) + reg += 0xfff; + } + + return *reg; +} + +/*** WSeq() - write into a register of the sequencer ***/ +void WSeq(unsigned char regnum, unsigned char val) +{ + fb_info->regs[SEQRX] = regnum; + fb_info->regs[SEQRX+1] = val; +} + +/*** RSeq() - read out one of the Sequencer registers ***/ +unsigned char RSeq(unsigned char regnum) +{ + fb_info->regs[SEQRX] = regnum; + return fb_info->regs[SEQRX+1]; +} + +/*** WCrt() - write into a register of the CRT controller ***/ +void WCrt(unsigned char regnum, unsigned char val) +{ + fb_info->regs[CRTX] = regnum; + fb_info->regs[CRTX+1] = val; +} + +/*** RCrt() - read out one of the CRT controller registers ***/ +unsigned char RCrt(unsigned char regnum) +{ + fb_info->regs[CRTX] = regnum; + return fb_info->regs[CRTX+1]; +} + +/*** WGfx() - write into a register of the Gfx controller ***/ +void WGfx(unsigned char regnum, unsigned char val) +{ + fb_info->regs[GRX] = regnum; + fb_info->regs[GRX+1] = val; +} + +/*** RGfx() - read out one of the Gfx controller registers ***/ +unsigned char RGfx(unsigned char regnum) +{ + fb_info->regs[GRX] = regnum; + return fb_info->regs[GRX+1]; +} + +/*** WAttr() - write into a register of the Attribute controller ***/ +void WAttr(unsigned char regnum, unsigned char val) +{ + /* if the next access to the attribute controller is a data write access, */ + /* simply write back the information that was already there before, so that */ + /* the next write access after that will be an index write. */ + if (RCrt(CRT24) & 0x80) + /* can't use WAttr() here - we would go into a recursive loop otherwise */ + fb_info->regs[ARX] = fb_info->regs[ARX+1]; + + if (RCrt(CRT24) & 0x80) + printk(KERN_WARNING "clgen: *** AttrIdx BAD!***\n"); + + /* now, first set index and after that the value - both to the same address (!) */ + fb_info->regs[ARX] = regnum; + fb_info->regs[ARX] = val; +} + +/*** AttrOn() - turn on VideoEnable for Attribute controller ***/ +void AttrOn() +{ + if (RCrt(CRT24) & 0x80) + /* if we're just in "write value" mode, write back the */ + /* same value as before to not modify anything */ + fb_info->regs[ARX] = fb_info->regs[ARX+1]; + + /* turn on video bit */ +/* fb_info->regs[ARX] = 0x20; */ + fb_info->regs[ARX] = 0x33; + + /* dummy write on Reg0 to be on "write index" mode next time */ + fb_info->regs[ARX] = 0x00; +} + +/*** RAttr() - read out a register of the Attribute controller ***/ +unsigned char RAttr(unsigned char regnum) +{ + /* (explanation see above in WAttr() ) */ + if (RCrt(CRT24) & 0x80) + fb_info->regs[ARX] = fb_info->regs[ARX+1]; + + fb_info->regs[ARX] = regnum; + return fb_info->regs[ARX+1]; +} + + +/*** WHDR() - write into the Hidden DAC register ***/ +/* as the HDR is the only extension register that requires special treatment + * (the other extension registers are accessible just like the "ordinary" + * registers of their functional group) here is a specialized routine for + * accessing the HDR + */ +void WHDR(unsigned char val) +{ + unsigned char dummy; + + if(fb_info->btype == BT_PICASSO) + { + /* Klaus' hint for correct access to HDR on some boards */ + /* first write 0 to pixel mask (3c6) */ + WGen(M_3C6, 0x00); udelay(200); + /* next read dummy from pixel address (3c8) */ + dummy = RGen(M_3C8); udelay(200); + } + + /* now do the usual stuff to access the HDR */ + + dummy = RGen(M_3C6); udelay(200); + dummy = RGen(M_3C6); udelay(200); + dummy = RGen(M_3C6); udelay(200); + dummy = RGen(M_3C6); udelay(200); + + WGen(M_3C6, val); udelay(200); + + if(fb_info->btype == BT_PICASSO) + { + /* now first reset HDR access counter */ + dummy = RGen(M_3C8); udelay(200); + + /* and at the end, restore the mask value */ + /* ## is this mask always 0xff? */ + WGen(M_3C6, 0xff); udelay(200); + } +} + +/*** RHDR() - read out the Hidden DAC register ***/ +/* I hope this does not break on the GD5428 - cannot test it. */ +/* (Is there any board for the Amiga that uses the 5428 ?) */ +unsigned char RHDR() +{ + unsigned char dummy; + + dummy = RGen(M_3C6); + dummy = RGen(M_3C6); + dummy = RGen(M_3C6); + dummy = RGen(M_3C6); + + return RGen(M_3C6); +} + + +/*** WSFR() - write to the "special function register" (SFR) ***/ +void WSFR(unsigned char val) +{ + fb_info->SFR = val; + fb_info->regs[0x8000] = val; +} + +/* The Picasso has a second register for switching the monitor bit */ +void WSFR2(unsigned char val) +{ + /* writing an arbitrary value to this one causes the monitor switcher */ + /* to flip to Amiga display */ + fb_info->SFR = val; + fb_info->regs[0x9000] = val; +} + +/*** WClut - set CLUT entry (range: 0..255 is automat. shifted to 0..63) ***/ +void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned int data = 0x3c9; + + /* address write mode register is not translated.. */ + fb_info->regs[0x3c8] = regnum; + + if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4) + { + /* but DAC data register IS, at least for Picasso II */ + if(fb_info->btype == BT_PICASSO) + data += 0xfff; + fb_info->regs[data] = (red >> 2); + fb_info->regs[data] = (green >> 2); + fb_info->regs[data] = (blue >> 2); + } + else + { + fb_info->regs[data] = (blue >> 2); + fb_info->regs[data] = (green >> 2); + fb_info->regs[data] = (red >> 2); + } +} + +/*** RClut - read CLUT entry and convert to 0..255 range ***/ +void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue) +{ + unsigned int data = 0x3c9; + + fb_info->regs[0x3c7] = regnum; + + if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4) + { + if(fb_info->btype == BT_PICASSO) + data += 0xfff; + *red = fb_info->regs[data] << 2; + *green = fb_info->regs[data] << 2; + *blue = fb_info->regs[data] << 2; + } + else + { + *blue = fb_info->regs[data] << 2; + *green = fb_info->regs[data] << 2; + *red = fb_info->regs[data] << 2; + } +} + + +/******************************************************************* + clgen_WaitBLT() + + Wait for the BitBLT engine to complete a possible earlier job +*********************************************************************/ + +void clgen_WaitBLT() +{ + /* now busy-wait until we're done */ + while (RGfx(GR31) & 0x08) + ; +} + +/******************************************************************* + clgen_BitBLT() + + perform accelerated "scrolling" +********************************************************************/ + +void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short line_length) +{ + u_short nwidth, nheight; + u_long nsrc, ndest; + u_char bltmode; + + nwidth = width - 1; + nheight = height - 1; + + bltmode = 0x00; + /* if source adr < dest addr, do the Blt backwards */ + if (cury <= desty) + { + if (cury == desty) + { + /* if src and dest are on the same line, check x */ + if (curx < destx) + bltmode |= 0x01; + } + else + bltmode |= 0x01; + } + + if (!bltmode) + { + /* standard case: forward blitting */ + nsrc = (cury * line_length) + curx; + ndest = (desty * line_length) + destx; + } + else + { + /* this means start addresses are at the end, counting backwards */ + nsrc = cury * line_length + curx + nheight * line_length + nwidth; + ndest = desty * line_length + destx + nheight * line_length + nwidth; + } + +// clgen_WaitBLT(); /* ### NOT OK for multiple boards! */ + + /* + run-down of registers to be programmed: + destination pitch + source pitch + BLT width/height + source start + destination start + BLT mode + BLT ROP + GR0 / GR1: "fill color" + start/stop + */ + + /* pitch: set to line_length */ + WGfx(GR24, line_length & 0xff); /* dest pitch low */ + WGfx(GR25, (line_length >> 8)); /* dest pitch hi */ + WGfx(GR26, line_length & 0xff); /* source pitch low */ + WGfx(GR27, (line_length >> 8)); /* source pitch hi */ + + /* BLT width: actual number of pixels - 1 */ + WGfx(GR20, nwidth & 0xff); /* BLT width low */ + WGfx(GR21, (nwidth >> 8)); /* BLT width hi */ + + /* BLT height: actual number of lines -1 */ + WGfx(GR22, nheight & 0xff); /* BLT height low */ + WGfx(GR23, (nheight >> 8)); /* BLT width hi */ + + /* BLT destination */ + WGfx(GR28, (u_char)(ndest & 0xff)); /* BLT dest low */ + WGfx(GR29, (u_char)(ndest >> 8)); /* BLT dest mid */ + WGfx(GR2A, (u_char)(ndest >> 16)); /* BLT dest hi */ + + /* BLT source */ + WGfx(GR2C, (u_char)(nsrc & 0xff)); /* BLT src low */ + WGfx(GR2D, (u_char)(nsrc >> 8)); /* BLT src mid */ + WGfx(GR2E, (u_char)(nsrc >> 16)); /* BLT src hi */ + + /* BLT mode */ + WGfx(GR30, bltmode); /* BLT mode */ + + /* BLT ROP: SrcCopy */ + WGfx(GR32, 0x0d); /* BLT ROP */ + + /* and finally: GO! */ + WGfx(GR31, 0x02); /* BLT Start/status */ +} + +/******************************************************************* + clgen_RectFill() + + perform accelerated rectangle fill +********************************************************************/ + +void clgen_RectFill (u_short x, u_short y, u_short width, u_short height, + u_char color, u_short line_length) +{ + u_short nwidth, nheight; + u_long ndest; + + nwidth = width - 1; + nheight = height - 1; + + ndest = (y * line_length) + x; + +// clgen_WaitBLT(); /* ### NOT OK for multiple boards! */ + + /* pitch: set to line_length */ + WGfx(GR24, line_length & 0xff); /* dest pitch low */ + WGfx(GR25, (line_length >> 8)); /* dest pitch hi */ + WGfx(GR26, line_length & 0xff); /* source pitch low */ + WGfx(GR27, (line_length >> 8)); /* source pitch hi */ + + /* BLT width: actual number of pixels - 1 */ + WGfx(GR20, nwidth & 0xff); /* BLT width low */ + WGfx(GR21, (nwidth >> 8)); /* BLT width hi */ + + /* BLT height: actual number of lines -1 */ + WGfx(GR22, nheight & 0xff); /* BLT height low */ + WGfx(GR23, (nheight >> 8)); /* BLT width hi */ + + /* BLT destination */ + WGfx(GR28, (u_char)(ndest & 0xff)); /* BLT dest low */ + WGfx(GR29, (u_char)(ndest >> 8)); /* BLT dest mid */ + WGfx(GR2A, (u_char)(ndest >> 16)); /* BLT dest hi */ + + /* BLT source: set to 0 (is a dummy here anyway) */ + WGfx(GR2C, 0x00); /* BLT src low */ + WGfx(GR2D, 0x00); /* BLT src mid */ + WGfx(GR2E, 0x00); /* BLT src hi */ + + /* This is a ColorExpand Blt, using the */ + /* same color for foreground and background */ + WGfx(GR0, color); /* foreground color */ + WGfx(GR1, color); /* background color */ + + /* BLT mode: color expand, Enable 8x8 copy (faster?) */ + WGfx(GR30, 0xc0); /* BLT mode */ + + /* BLT ROP: SrcCopy */ + WGfx(GR32, 0x0d); /* BLT ROP */ + + /* and finally: GO! */ + WGfx(GR31, 0x02); /* BLT Start/status */ +} + +/************************************************************************** + * bestclock() - determine closest possible clock lower(?) than the + * desired pixel clock + **************************************************************************/ +#define abs(x) ((x)<0 ? -(x) : (x)) +static void bestclock(long freq, long *best, long *nom, + long *den, long *div, long maxfreq) +{ + long n, h, d, f; + + *nom = 0; + *den = 0; + *div = 0; + + if (freq < 8000) + freq = 8000; + + if (freq > maxfreq) + freq = maxfreq; + + *best = 0; + f = freq * 10; + + for(n = 32; n < 128; n++) + { + d = (143181 * n) / f; + if ( (d >= 7) && (d <= 63) ) + { + if (d > 31) + d = (d / 2) * 2; + h = (14318 * n) / d; + if ( abs(h - freq) < abs(*best - freq) ) + { + *best = h; + *nom = n; + if (d < 32) + { + *den = d; + *div = 0; + } + else + { + *den = d / 2; + *div = 1; + } + } + } + d = ( (143181 * n)+f-1) / f; + if ( (d >= 7) && (d <= 63) ) + { + if (d > 31) + d = (d / 2) * 2; + h = (14318 * n) / d; + if ( abs(h - freq) < abs(*best - freq) ) + { + *best = h; + *nom = n; + if (d < 32) + { + *den = d; + *div = 0; + } + else + { + *den = d / 2; + *div = 1; + } + } + } + } +} + diff -u --recursive --new-file v2.1.111/linux/drivers/video/clgenfb.h linux/drivers/video/clgenfb.h --- v2.1.111/linux/drivers/video/clgenfb.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/clgenfb.h Sun Jul 26 14:40:19 1998 @@ -0,0 +1,175 @@ + +/* definitions for Piccolo/SD64 VGA controller chip */ +/* these definitions might most of the time also work */ +/* for other CL-GD542x/543x based boards.. */ + +/*** External/General Registers ***/ +#define POS102 0x102 /* POS102 register */ +#define VSSM 0x46e8 /* Adapter Sleep */ +#define VSSM2 0x3c3 /* Motherboard Sleep */ +#define MISC_W 0x3c2 /* Miscellaneous Output register, write */ +#define MISC_R 0x3cc /* Miscellaneous Output register, read */ +#define FC_W 0x3da /* Feature Control Register, write (color) */ +#define FC_R 0x3ca /* Feature Control Register, read */ +#define FEAT 0x3c2 /* Input Status Register 0 */ +#define STAT 0x3da /* Input Status Register 1, read-only */ +#define M_3C6 0x3c6 /* Pixel Mask */ +#define M_3C7_W 0x3c7 /* Pixel Address Read Mode (write) */ +#define M_3C7_R 0x3c7 /* DAC State (read-only */ +#define M_3C8 0x3c8 /* Pixel Address Write Mode */ +#define M_3C9 0x3c9 /* Pixel Data */ + +/*** VGA Sequencer Registers ***/ +#define SEQRX 0x3c4 /* Sequencer Index */ +#define SEQR0 0x0 /* Reset */ +#define SEQR1 0x1 /* Clocking Mode */ +#define SEQR2 0x2 /* Plane Mask / Write Pixel Extension */ +#define SEQR3 0x3 /* Character Map Select */ +#define SEQR4 0x4 /* Memory Mode */ +/* the following are from the "extension registers" group */ +#define SEQR6 0x6 /* Unlock ALL Extensions */ +#define SEQR7 0x7 /* Extended Sequencer Mode */ +#define SEQR8 0x8 /* EEPROM Control */ +#define SEQR9 0x9 /* Scratch Pad 0 (do not access!) */ +#define SEQRA 0xa /* Scratch Pad 1 (do not access!) */ +#define SEQRB 0xb /* VCLK0 Numerator */ +#define SEQRC 0xc /* VCLK1 Numerator */ +#define SEQRD 0xd /* VCLK2 Numerator */ +#define SEQRE 0xe /* VCLK3 Numerator */ +#define SEQRF 0xf /* DRAM Control */ +#define SEQR10 0x10 /* Graphics Cursor X Position */ +#define SEQR11 0x11 /* Graphics Cursor Y Position */ +#define SEQR12 0x12 /* Graphics Cursor Attributes */ +#define SEQR13 0x13 /* Graphics Cursor Pattern Address Offset */ +#define SEQR14 0x14 /* Scratch Pad 2 (CL-GD5426/'28 Only) (do not access!) */ +#define SEQR15 0x15 /* Scratch Pad 3 (CL-GD5426/'28 Only) (do not access!) */ +#define SEQR16 0x16 /* Performance Tuning (CL-GD5424/'26/'28 Only) */ +#define SEQR17 0x17 /* Configuration ReadBack and Extended Control (CL-GF5428 Only) */ +#define SEQR18 0x18 /* Signature Generator Control (Not CL-GD5420) */ +#define SEQR19 0x19 /* Signature Generator Result Low Byte (Not CL-GD5420) */ +#define SEQR1A 0x1a /* Signature Generator Result High Byte (Not CL-GD5420) */ +#define SEQR1B 0x1b /* VCLK0 Denominator and Post-Scalar Value */ +#define SEQR1C 0x1c /* VCLK1 Denominator and Post-Scalar Value */ +#define SEQR1D 0x1d /* VCLK2 Denominator and Post-Scalar Value */ +#define SEQR1E 0x1e /* VCLK3 Denominator and Post-Scalar Value */ +#define SEQR1F 0x1f /* BIOS ROM write enable and MCLK Select */ + +/*** CRT Controller Registers ***/ +#define CRTX 0x3d4 /* CRTC Index */ +#define CRT0 0x0 /* Horizontal Total */ +#define CRT1 0x1 /* Horizontal Display End */ +#define CRT2 0x2 /* Horizontal Blanking Start */ +#define CRT3 0x3 /* Horizontal Blabking End */ +#define CRT4 0x4 /* Horizontal Sync Start */ +#define CRT5 0x5 /* Horizontal Sync End */ +#define CRT6 0x6 /* Vertical Total */ +#define CRT7 0x7 /* Overflow */ +#define CRT8 0x8 /* Screen A Preset Row Scan */ +#define CRT9 0x9 /* Character Cell Height */ +#define CRTA 0xa /* Text Cursor Start */ +#define CRTB 0xb /* Text Cursor End */ +#define CRTC 0xc /* Screen Start Address High */ +#define CRTD 0xd /* Screen Start Address Low */ +#define CRTE 0xe /* Text Cursor Location High */ +#define CRTF 0xf /* Text Cursor Location Low */ +#define CRT10 0x10 /* Vertical Sync Start */ +#define CRT11 0x11 /* Vertical Sync End */ +#define CRT12 0x12 /* Vertical Display End */ +#define CRT13 0x13 /* Offset */ +#define CRT14 0x14 /* Underline Row Scan */ +#define CRT15 0x15 /* Vertical Blanking Start */ +#define CRT16 0x16 /* Vertical Blanking End */ +#define CRT17 0x17 /* Mode Control */ +#define CRT18 0x18 /* Line Compare */ +#define CRT22 0x22 /* Graphics Data Latches ReadBack */ +#define CRT24 0x24 /* Attribute Controller Toggle ReadBack */ +#define CRT26 0x26 /* Attribute Controller Index ReadBack */ +/* the following are from the "extension registers" group */ +#define CRT19 0x19 /* Interlace End */ +#define CRT1A 0x1a /* Interlace Control */ +#define CRT1B 0x1b /* Extended Display Controls */ +#define CRT1C 0x1c /* Sync adjust and genlock register */ +#define CRT1D 0x1d /* Overlay Extended Control register */ +#define CRT25 0x25 /* Part Status Register */ +#define CRT27 0x27 /* ID Register */ +#define CRT51 0x51 /* P4 disable "flicker fixer" */ + +/*** Graphics Controller Registers ***/ +#define GRX 0x3ce /* Graphics Controller Index */ +#define GR0 0x0 /* Set/Reset, Write Mode 5 Background Extension */ +#define GR1 0x1 /* Set/Reset Enable, Write Mode 4, 5 Foreground Ext. */ +#define GR2 0x2 /* Color Compare */ +#define GR3 0x3 /* Data Rotate */ +#define GR4 0x4 /* Read Map Select */ +#define GR5 0x5 /* Mode */ +#define GR6 0x6 /* Miscellaneous */ +#define GR7 0x7 /* Color Don't Care */ +#define GR8 0x8 /* Bit Mask */ +/* the following are from the "extension registers" group */ +#define GR9 0x9 /* Offset Register 0 */ +#define GRA 0xa /* Offset Register 1 */ +#define GRB 0xb /* Graphics Controller Mode Extensions */ +#define GRC 0xc /* Color Key (CL-GD5424/'26/'28 Only) */ +#define GRD 0xd /* Color Key Mask (CL-GD5424/'26/'28 Only) */ +#define GRE 0xe /* Miscellaneous Control (Cl-GD5428 Only) */ +#define GRF 0xf /* Display Compression Control register */ +#define GR10 0x10 /* 16-bit Pixel BG Color High Byte (Not CL-GD5420) */ +#define GR11 0x11 /* 16-bit Pixel FG Color High Byte (Not CL-GD5420) */ +#define GR12 0x12 /* Background Color Byte 2 Register */ +#define GR13 0x13 /* Foreground Color Byte 2 Register */ +#define GR14 0x14 /* Background Color Byte 3 Register */ +#define GR15 0x15 /* Foreground Color Byte 3 Register */ +/* the following are CL-GD5426/'28 specific blitter registers */ +#define GR20 0x20 /* BLT Width Low */ +#define GR21 0x21 /* BLT Width High */ +#define GR22 0x22 /* BLT Height Low */ +#define GR23 0x23 /* BLT Height High */ +#define GR24 0x24 /* BLT Destination Pitch Low */ +#define GR25 0x25 /* BLT Destination Pitch High */ +#define GR26 0x26 /* BLT Source Pitch Low */ +#define GR27 0x27 /* BLT Source Pitch High */ +#define GR28 0x28 /* BLT Destination Start Low */ +#define GR29 0x29 /* BLT Destination Start Mid */ +#define GR2A 0x2a /* BLT Destination Start High */ +#define GR2C 0x2c /* BLT Source Start Low */ +#define GR2D 0x2d /* BLT Source Start Mid */ +#define GR2E 0x2e /* BLT Source Start High */ +#define GR2F 0x2f /* Picasso IV Blitter compat mode..? */ +#define GR30 0x30 /* BLT Mode */ +#define GR31 0x31 /* BLT Start/Status */ +#define GR32 0x32 /* BLT Raster Operation */ +#define GR33 0x33 /* another P4 "compat" register.. */ +#define GR34 0x34 /* Transparent Color Select Low */ +#define GR35 0x35 /* Transparent Color Select High */ +#define GR38 0x38 /* Source Transparent Color Mask Low */ +#define GR39 0x39 /* Source Transparent Color Mask High */ + +/*** Attribute Controller Registers ***/ +#define ARX 0x3c0 /* Attribute Controller Index */ +#define AR0 0x0 /* Attribute Controller Palette Register 0 */ +#define AR1 0x1 /* Attribute Controller Palette Register 1 */ +#define AR2 0x2 /* Attribute Controller Palette Register 2 */ +#define AR3 0x3 /* Attribute Controller Palette Register 3 */ +#define AR4 0x4 /* Attribute Controller Palette Register 4 */ +#define AR5 0x5 /* Attribute Controller Palette Register 5 */ +#define AR6 0x6 /* Attribute Controller Palette Register 6 */ +#define AR7 0x7 /* Attribute Controller Palette Register 7 */ +#define AR8 0x8 /* Attribute Controller Palette Register 8 */ +#define AR9 0x9 /* Attribute Controller Palette Register 9 */ +#define ARA 0xa /* Attribute Controller Palette Register 10 */ +#define ARB 0xb /* Attribute Controller Palette Register 11 */ +#define ARC 0xc /* Attribute Controller Palette Register 12 */ +#define ARD 0xd /* Attribute Controller Palette Register 13 */ +#define ARE 0xe /* Attribute Controller Palette Register 14 */ +#define ARF 0xf /* Attribute Controller Palette Register 15 */ +#define AR10 0x10 /* Attribute Controller Mode Register */ +#define AR11 0x11 /* Overscan (Border) Color Register */ +#define AR12 0x12 /* Color Plane Enable Register */ +#define AR13 0x13 /* Pixel Panning Register */ +#define AR14 0x14 /* Color Select Register */ +#define AR33 0x33 /* The "real" Pixel Panning register (?) */ +#define AR34 0x34 /* *TEST* */ + +/*** Extension Registers ***/ +#define HDR 0x3c6 /* Hidden DAC Register (Not CL-GD5420) */ + diff -u --recursive --new-file v2.1.111/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c --- v2.1.111/linux/drivers/video/controlfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/controlfb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,997 @@ +/* + * controlfb.c -- frame buffer device for the PowerMac 'control' display + * + * Created 12 July 1998 by Dan Jacobowitz + * Copyright (C) 1998 Dan Jacobowitz + * + * Frame buffer structure from: + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * Hardware information from: + * control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FB_COMPAT_XPMAC +#include +#endif +#include +#include +#include +#include +#include + +#include "fbcon.h" +#include "fbcon-cfb8.h" +#include "fbcon-cfb16.h" +#include "fbcon-cfb32.h" + +#include "macmodes.h" +#include "controlfb.h" + +static int currcon = 0; +static int switching = 0; + +struct fb_par_control { + int vmode, cmode; + int xres, yres; + int vxres, vyres; + int xoffset, yoffset; +}; + +struct fb_info_control { + struct fb_info info; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + struct display disp; + struct fb_par_control par; + struct { + __u8 red, green, blue; + } palette[256]; + + struct cmap_regs *cmap_regs; + unsigned long cmap_regs_phys; + + struct control_regs *control_regs; + unsigned long control_regs_phys; + + __u8 *frame_buffer; + unsigned long frame_buffer_phys; + + int sense, control_use_bank2; + unsigned long total_vram; +}; + +/* + * Exported functions + */ +void control_init(void); +void control_of_init(struct device_node *dp); + +static int control_open(struct fb_info *info, int user); +static int control_release(struct fb_info *info, int user); +static int control_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int control_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int control_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int control_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int control_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); + +static int read_control_sense(struct fb_info_control *p); +static inline int control_vram_reqd(int video_mode, int color_mode); +static void set_control_clock(unsigned char *params); +static void control_set_hardware(struct fb_info_control *p); +static void control_par_to_all(struct fb_info_control *p, int init); +static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var); +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info); + +static void control_init_info(struct fb_info *info, struct fb_info_control *p); +static void control_par_to_display(struct fb_par_control *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p); +static void control_init_display(struct display *disp); +static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, + struct fb_info_control *p); +static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p); + +static struct fb_ops controlfb_ops = { + control_open, + control_release, + control_get_fix, + control_get_var, + control_set_var, + control_get_cmap, + control_set_cmap, + control_pan_display, + control_ioctl +}; + +static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info); +static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static void do_install_cmap(int con, struct fb_info *info); + + +__openfirmware + + +static int control_open(struct fb_info *info, int user) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int control_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int control_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_info_control *cp = (struct fb_info_control *) info; + + *fix = cp->fix; + return 0; +} + +static int control_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_control *cp = (struct fb_info_control *) info; + + *var = cp->var; + return 0; +} + +/* Sets everything according to var */ +static int control_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + struct display *disp; + struct fb_par_control par; + int depthchange, err; + + disp = (con >= 0) ? &fb_display[con] : &p->disp; + if((err = control_var_to_par(var, &par, info))) { + printk (KERN_ERR "Error in control_set_var, calling control_var_to_par: %d.\n", err); + return err; + } + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { + printk("Not activating, in control_set_var.\n"); + control_par_to_var(&par, var); + return 0; + } +/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */ +#define DIRTY(x) (p->var.x != var->x) + depthchange = DIRTY(bits_per_pixel); + if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) && + !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) { + control_par_to_var(&par, var); + p->var = disp->var = *var; + return 0; + } +printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel); + /* OK, we're getting here at the right times... */ + p->par = par; + control_par_to_var(&par, var); + p->var = *var; + control_par_to_fix(&par, &p->fix, p); + control_par_to_display(&par, disp, &p->fix, p); + p->disp = *disp; + + if(info->changevar && !switching) /* Don't want to do this if just switching consoles. */ + (*info->changevar)(con); + if(con == currcon) + control_set_hardware(p); + if(depthchange) + if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) + return err; + if(depthchange || switching) + do_install_cmap(con, info); + return 0; +} + +static int control_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (var->xoffset != 0 || var->yoffset != 0) + return -EINVAL; + return 0; +} + +static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, + controlfb_getcolreg, info); + if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + } + return 0; +} + +static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct display *disp = &fb_display[con]; + int err; + + if (disp->cmap.len == 0) { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + err = fb_alloc_cmap(&disp->cmap, size, 0); + if (err) + return err; + } + + if (con == currcon) + return fb_set_cmap(cmap, &disp->var, kspc, controlfb_setcolreg, + info); + fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + return 0; +} + +static int control_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + return -EINVAL; +} + +static int controlfb_switch(int con, struct fb_info *info) +{ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, + &fb_display[currcon].var, 1, controlfb_getcolreg, + info); + currcon = con; +#if 0 + control_var_to_par(&fb_display[currcon].var, &par, info); + control_set_par(&par, info); /*STOPPEDHERE - did i define that? */ + do_install_cmap(con, info); +#else + /* I see no reason not to do this. Minus info->changevar(). */ + /* DOH. This makes control_set_var compare, you guessed it, */ + /* fb_display[con].var (first param), and fb_display[con].var! */ + /* Perhaps I just fixed that... */ + switching = 1; + control_set_var(&fb_display[con].var, con, info); + switching = 0; +#endif + return 0; +} + +static int controlfb_updatevar(int con, struct fb_info *info) +{ + return 0; +} + +static void controlfb_blank(int blank_mode, struct fb_info *info) +{ +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +/* [danj] I think there's something fishy about those constants... */ + struct fb_info_control *p = (struct fb_info_control *) info; + int ctrl; + + ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33; + if (blank_mode) + --blank_mode; + if (blank_mode & VESA_VSYNC_SUSPEND) + ctrl &= ~3; + if (blank_mode & VESA_HSYNC_SUSPEND) + ctrl &= ~0x30; + out_le32(&p->control_regs->ctrl.r, ctrl); + +/* TODO: Figure out how the heck to powerdown this thing! */ + + return; +} + +static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + + if (regno > 255) + return 1; + *red = p->palette[regno].red; + *green = p->palette[regno].green; + *blue = p->palette[regno].blue; + return 0; +} + +static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_control *p = (struct fb_info_control *) info; + + if (regno > 255 || regno < 0) + return 1; + p->palette[regno].red = red; + p->palette[regno].green = green; + p->palette[regno].blue = blue; + + out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */ + out_8(&p->cmap_regs->lut, red); /* send one color channel at */ + out_8(&p->cmap_regs->lut, green); /* a time... */ + out_8(&p->cmap_regs->lut, blue); + + if(regno < 16) { +#if 0 +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; +#endif +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; + /* I think. */ +#endif +#else +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; +#endif +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; + /* I think. */ +#endif +#endif + } + return 0; +} + +static void do_install_cmap(int con, struct fb_info *info) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + controlfb_setcolreg, info); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, + controlfb_setcolreg, info); + } +} + +#ifdef CONFIG_FB_COMPAT_XPMAC +extern struct vc_mode display_info; +extern struct fb_info *console_fb_info; +#if 0 +extern int (*console_setmode_ptr)(struct vc_mode *, int); +extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int, + struct fb_info *); +int console_setmode(struct vc_mode *, int); +#endif +#endif /* CONFIG_FB_COMPAT_XPMAC */ + +static inline int control_vram_reqd(int video_mode, int color_mode) +{ + return control_reg_init[video_mode-1]->vres + * control_reg_init[video_mode-1]->pitch[color_mode]; +} + +static void set_control_clock(unsigned char *params) +{ + struct adb_request req; + int i; + + for (i = 0; i < 3; ++i) { + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x50, i + 1, params[i]); + while (!req.complete) + cuda_poll(); + } +} + + +__initfunc(static void init_control(struct fb_info_control *p)) +{ + struct fb_par_control *par = &p->par; + + p->sense = read_control_sense(p); + printk("Monitor sense value = 0x%x, ", p->sense); + /* Try to pick a video mode out of NVRAM if we have one. */ + par->vmode = nvram_read_byte(NV_VMODE); + if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1]) + par->vmode = VMODE_CHOOSE; + if(par->vmode == VMODE_CHOOSE) + par->vmode = mac_map_monitor_sense(p->sense); + if(!control_reg_init[par->vmode - 1]) + par->vmode = VMODE_640_480_60; + + par->cmode = nvram_read_byte(NV_CMODE); + if(par->cmode < CMODE_8 || par->cmode > CMODE_32) + par->cmode = CMODE_8; + /* + * Reduce the pixel size if we don't have enough VRAM. + */ + while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram) + par->cmode--; + + printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode); + + par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres; + par->vyres = par->yres = control_reg_init[par->vmode - 1]->vres; + par->xoffset = par->yoffset = 0; + + control_par_to_all(p, 1); + + if (register_framebuffer(&p->info) < 0) { + kfree(p); + return; + } + control_set_hardware(p); + + printk("fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); +} + +/* Now how about actually saying, Make it so! */ +/* Some things in here probably don't need to be done each time. */ +static void control_set_hardware(struct fb_info_control *p) +{ + struct control_regvals *init; + struct preg *rp; + int flags, ctrl, i; + int vmode, cmode; + + vmode = p->par.vmode; + cmode = p->par.cmode; + + init = control_reg_init[vmode - 1]; + + if (control_vram_reqd(vmode, cmode) > 0x200000) + flags = 0x51; + else if (p->control_use_bank2) + flags = 0x39; + else + flags = 0x31; + if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16) + ctrl = 0x7f; + else + ctrl = 0x3b; + + /* Initialize display timing registers */ + out_le32(&p->control_regs->ctrl.r, 0x43b); + + set_control_clock(init->clock_params); + + p->cmap_regs->addr = 0x20; p->cmap_regs->d2 = init->radacal_ctrl[cmode]; + p->cmap_regs->addr = 0x21; p->cmap_regs->d2 = p->control_use_bank2 ? 0: 1; + p->cmap_regs->addr = 0x10; p->cmap_regs->d2 = 0; + p->cmap_regs->addr = 0x11; p->cmap_regs->d2 = 0; + + rp = &p->control_regs->vswin; + for (i = 0; i < 16; ++i, ++rp) + out_le32(&rp->r, init->regs[i]); + + out_le32(&p->control_regs->pitch.r, init->pitch[cmode]); + out_le32(&p->control_regs->mode.r, init->mode[cmode]); + out_le32(&p->control_regs->flags.r, flags); + out_le32(&p->control_regs->start_addr.r, 0); + out_le32(&p->control_regs->reg18.r, 0x1e5); + out_le32(&p->control_regs->reg19.r, 0); + + for (i = 0; i < 16; ++i) { + controlfb_setcolreg(color_table[i], default_red[i], default_grn[i], + default_blu[i], 0, (struct fb_info *)p); + } +/* Does the above need to be here each time? -- danj */ + + /* Turn on display */ + out_le32(&p->control_regs->ctrl.r, ctrl); + +#ifdef CONFIG_FB_COMPAT_XPMAC + /* And let the world know the truth. */ + if (!console_fb_info || console_fb_info == &p->info) { + display_info.height = p->var.yres; + display_info.width = p->var.xres; + display_info.depth = (cmode == CMODE_32) ? 32 : + ((cmode == CMODE_16) ? 16 : 8); + display_info.pitch = p->fix.line_length; + display_info.mode = vmode; + strncpy(display_info.name, "control", + sizeof(display_info.name)); + display_info.fb_address = p->frame_buffer_phys + + control_reg_init[vmode-1]->offset[cmode]; + display_info.cmap_adr_address = p->cmap_regs_phys; + display_info.cmap_data_address = p->cmap_regs_phys + 0x30; + display_info.disp_reg_address = p->control_regs_phys; + console_fb_info = &p->info; + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +__initfunc(void control_init(void)) +{ +#ifndef CONFIG_FB_OF + struct device_node *dp; + + dp = find_devices("control"); + if (dp != 0) + control_of_init(dp); +#endif /* CONFIG_FB_OF */ +} + +__initfunc(void control_of_init(struct device_node *dp)) +{ + struct fb_info_control *p; + unsigned long addr, size; + int i, bank1, bank2; + + if(dp->next != 0) + printk("Warning: only using first control display device.\n"); + /* danj: I have a feeling this no longer applies - if we somehow * + * had two of them, they'd be two framebuffers, right? */ + if(dp->n_addrs != 2) + panic("expecting 2 address for control (got %d)", dp->n_addrs); + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (p == 0) + return; + + /* Map in frame buffer and registers */ + for (i = 0; i < dp->n_addrs; ++i) { + addr = dp->addrs[i].address; + size = dp->addrs[i].size; + if (size >= 0x800000) { + /* use the big-endian aperture (??) */ + addr += 0x800000; + /* map at most 8MB for the frame buffer */ + p->frame_buffer_phys = addr; + p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU); + } else { + p->control_regs_phys = addr; + p->control_regs = ioremap(addr, size); + } + } + p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + + /* Work out which banks of VRAM we have installed. */ + /* danj: I guess the card just ignores writes to nonexistant VRAM... */ + p->frame_buffer[0] = 0x5a; + p->frame_buffer[1] = 0xc7; + bank1 = p->frame_buffer[0] == 0x5a && p->frame_buffer[1] == 0xc7; + p->frame_buffer[0x600000] = 0xa5; + p->frame_buffer[0x600001] = 0x38; + bank2 = p->frame_buffer[0x600000] == 0xa5 && p->frame_buffer[0x600001] == 0x38; + p->total_vram = (bank1 + bank2) * 0x200000; + /* If we don't have bank 1 installed, we hope we have bank 2 :-) */ + p->control_use_bank2 = !bank1; + if (p->control_use_bank2) + p->frame_buffer += 0x600000; + +#ifdef CONFIG_FB_COMPAT_XPMAC +#if 0 + console_set_cmap_ptr = control_set_cmap; + console_setmode_ptr = control_console_setmode; +#endif +#endif /* CONFIG_FB_COMPAT_XPMAC */ + + init_control(p); +} + +/* + * Get the monitor sense value. + * Note that this can be called before calibrate_delay, + * so we can't use udelay. + * + * Hmm - looking at platinum, should we be calling eieio() here? + */ +static int read_control_sense(struct fb_info_control *p) +{ + int sense; + + out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */ + __delay(200); + out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ + __delay(2000); + sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2; + + /* drive each sense line low in turn and collect the other 2 */ + out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */ + __delay(2000); + sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2; + out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */ + __delay(2000); + sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5) + | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4); + out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */ + __delay(2000); + sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7; + + out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ + + return sense; +} + +#if 1 +/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info) +{ + int xres = var->xres; + int yres = var->yres; + int bpp = var->bits_per_pixel; + + struct control_regvals *init; + struct fb_info_control *p = (struct fb_info_control *) fb_info; + + /* + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + * Suggestion: Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + */ + /* swiped by jonh from atyfb.c */ + if (xres <= 512 && yres <= 384) + par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */ + else if (xres <= 640 && yres <= 480) + par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ + else if (xres <= 640 && yres <= 870) + par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ + else if (xres <= 768 && yres <= 576) + par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */ + else if (xres <= 800 && yres <= 600) + par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ + else if (xres <= 832 && yres <= 624) + par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */ + else if (xres <= 1024 && yres <= 768) + par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ + else if (xres <= 1152 && yres <= 870) + par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ + else if (xres <= 1280 && yres <= 960) + par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ + else if (xres <= 1280 && yres <= 1024) + par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ + else + return -EINVAL; + + xres = control_reg_init[par->vmode-1]->hres; + yres = control_reg_init[par->vmode-1]->vres; + +/* + if (var->xres_virtual <= xres) + par->vxres = xres; + else + par->vxres = (var->xres_virtual+7) & ~7; + if (var->yres_virtual <= yres) + par->vyres = yres; + else + par->vyres = var->yres_virtual; + + par->xoffset = (var->xoffset+7) & ~7; + par->yoffset = var->yoffset; + if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres) + return -EINVAL; +*/ + + /* I'm too chicken to think about virtual */ + /* resolutions just yet. Bok bok. */ + + /* And I'm too chicken to even figure out what they are. Awk awk. [danj] */ + if (var->xres_virtual > xres || var->yres_virtual > yres + || var->xoffset != 0 || var->yoffset != 0) { + return -EINVAL; + } + + par->xres = xres; + par->yres = yres; + par->vxres = xres; + par->vyres = yres; + par->xoffset = 0; + par->yoffset = 0; + + if (bpp <= 8) + par->cmode = CMODE_8; + else if (bpp <= 16) + par->cmode = CMODE_16; + else if (bpp <= 32) + par->cmode = CMODE_32; + else + return -EINVAL; + + if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) + return -EINVAL; + + /* Check if we know about the wanted video mode */ + init = control_reg_init[par->vmode-1]; + if (init == NULL) { + /* I'm not sure if control has any specific requirements -- */ + /* if we have a regvals struct, we're good to go? */ + return -EINVAL; + } + + return 0; +} +#else +/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ +static int control_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_control *par, const struct fb_info *fb_info) +{ + struct fb_info_control *p = (struct fb_info_control *) fb_info; + + if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) + return -EINVAL; + par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres; + par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres; + par->xoffset = par->yoffset = 0; + + if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) + return -EINVAL; + + /* Check if we know about the wanted video mode */ + if(!control_reg_init[par->vmode-1]) { + /* I'm not sure if control has any specific requirements -- */ + /* if we have a regvals struct, we're good to go? */ + return -EINVAL; + } + return 0; +} +#endif + +#if 1 +static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var) +{ + memset(var, 0, sizeof(*var)); + var->xres = control_reg_init[par->vmode - 1]->hres; + var->yres = control_reg_init[par->vmode - 1]->vres; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; /* For now. */ + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + var->grayscale = 0; + + if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) { + printk(KERN_ERR "Bad color mode in control_par_to_var()!\n"); + par->cmode = CMODE_8; + } + switch(par->cmode) { + case CMODE_8: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CMODE_16: /* RGB 555 */ + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CMODE_32: /* RGB 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* these are total guesses, copied right out of atyfb.c */ + var->left_margin = var->right_margin = 64; + var->upper_margin = var->lower_margin = 32; + var->hsync_len = /*64*/8; + var->vsync_len = /*2*/8; + var->sync = 0; + +#if 0 +/* jonh's pixclocks...*/ + /* no long long support in the kernel :-( */ + /* this splittig trick will work if xres > 232 */ + var->pixclock = 1000000000/ + (var->left_margin+var->xres+var->right_margin+var->hsync_len); + var->pixclock *= 1000; + var->pixclock /= vmode_attrs[par->vmode-1].vfreq* + (var->upper_margin+var->yres+var->lower_margin+var->vsync_len); +#else +/* danj's */ + /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */ + /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */ + /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */ + var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0]; + var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1]; + var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2]; +#endif +} +#else +static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var) +{ + mac_vmode_to_var(par->vmode, par->cmode, var); +} +#endif + +static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p) +{ + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, "control"); + fix->mmio_start = (char *)p->control_regs_phys; + fix->mmio_len = sizeof(struct control_regs); + fix->type = FB_TYPE_PACKED_PIXELS; + + /* + fix->type_aux = 0; + fix->ywrapstep = 0; + fix->ypanstep = 0; + fix->xpanstep = 0; + */ +} + +/* Fix must already be inited ^^^^^^^ */ +static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, + struct fb_info_control *p) +{ + fix->smem_start = (void *)(p->frame_buffer_phys + + control_reg_init[par->vmode-1]->offset[par->cmode]); + p->fix.smem_len = control_vram_reqd(par->vmode, par->cmode); + /* Hmm, jonh used total_vram here. */ + p->fix.visual = (par->cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + p->fix.line_length = par->vxres << par->cmode; + /* ywrapstep, xpanstep, ypanstep */ +} + +static void control_init_display(struct display *disp) +{ + memset(disp, 0, sizeof(*disp)); + disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS; + disp->can_soft_blank = 1; + disp->scrollmode = SCROLL_YREDRAW; +#if 0 + disp->type_aux = fix->type_aux; + disp->cmap.red = NULL; /* ??? danj */ + disp->cmap.green = NULL; + disp->cmap.blue = NULL; + disp->cmap.transp = NULL; + /* Yeah, I realize I just set 0 = 0. */ +#endif +} + +static void control_par_to_display(struct fb_par_control *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p) +{ + disp->var = p->var; + disp->screen_base = (char *) p->frame_buffer + + control_reg_init[par->vmode-1]->offset[par->cmode]; + disp->visual = fix->visual; + disp->line_length = fix->line_length; + +if(disp->scrollmode != SCROLL_YREDRAW) { + printk(KERN_ERR "Scroll mode not YREDRAW in control_par_to_display!!\n"); + disp->scrollmode = SCROLL_YREDRAW; +} + disp->dispsw = (par->cmode == CMODE_32) ? &fbcon_cfb32 : + ((par->cmode == CMODE_16) ? &fbcon_cfb16 : &fbcon_cfb8); +} + +static void control_init_info(struct fb_info *info, struct fb_info_control *p) +{ + strcpy(info->modename, p->fix.id); + info->node = -1; /* ??? danj */ + info->fbops = &controlfb_ops; + info->disp = &p->disp; + info->fontname[0] = 0; + info->changevar = NULL; + info->switch_con = &controlfb_switch; + info->updatevar = &controlfb_updatevar; + info->blank = &controlfb_blank; +} + +/* danj: Oh, I HOPE I didn't miss anything major in here... */ +static void control_par_to_all(struct fb_info_control *p, int init) +{ + if(init) { + control_init_fix(&p->fix, p); + } + control_par_to_fix(&p->par, &p->fix, p); + + control_par_to_var(&p->par, &p->var); + + if(init) { + control_init_display(&p->disp); + } + control_par_to_display(&p->par, &p->disp, &p->fix, p); + + if(init) { + control_init_info(&p->info, p); + } +} + +#if 0 +__initfunc(void controlfb_setup(char *options, int *ints)) +{ + /* Parse user speficied options (`video=controlfb:') */ + FUNCID; +} + +static int controlfb_pan_display(struct fb_var_screeninfo *var, + struct controlfb_par *par, + const struct fb_info *fb_info) +{ + /* + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + */ + + FUNCID; + + return 0; +} + +#endif diff -u --recursive --new-file v2.1.111/linux/drivers/video/controlfb.h linux/drivers/video/controlfb.h --- v2.1.111/linux/drivers/video/controlfb.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/controlfb.h Sun Jul 26 14:40:19 1998 @@ -0,0 +1,262 @@ +/* + * controlfb_hw.h: Constants of all sorts for controlfb + * + * Copyright (C) 1998 Daniel Jacobowitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based on an awful lot of code, including: + * + * control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras. + * + * The so far unpublished platinumfb.c + * Copyright (C) 1998 Jon Howell + */ + +/* + * Structure of the registers for the RADACAL colormap device. + */ +struct cmap_regs { + unsigned char addr; + char pad1[15]; + unsigned char d1; + char pad2[15]; + unsigned char d2; + char pad3[15]; + unsigned char lut; + char pad4[15]; +}; + +/* + * Structure of the registers for the "control" display adaptor. + */ +#define PAD(x) char x[12] + +struct preg { /* padded register */ + unsigned r; + char pad[12]; +}; + +struct control_regs { + struct preg vcount; /* vertical counter */ + /* Vertical parameters are in units of 1/2 scan line */ + struct preg vswin; /* between vsblank and vssync */ + struct preg vsblank; /* vert start blank */ + struct preg veblank; /* vert end blank (display start) */ + struct preg vewin; /* between vesync and veblank */ + struct preg vesync; /* vert end sync */ + struct preg vssync; /* vert start sync */ + struct preg vperiod; /* vert period */ + struct preg reg8; + /* Horizontal params are in units of 2 pixels */ + struct preg hperiod; /* horiz period - 2 */ + struct preg hsblank; /* horiz start blank */ + struct preg heblank; /* horiz end blank */ + struct preg hesync; /* horiz end sync */ + struct preg hssync; /* horiz start sync */ + struct preg rege; + struct preg regf; + struct preg reg10; + struct preg reg11; + struct preg ctrl; /* display control */ + struct preg start_addr; /* start address: 5 lsbs zero */ + struct preg pitch; /* addrs diff between scan lines */ + struct preg mon_sense; /* monitor sense bits */ + struct preg flags; + struct preg mode; + struct preg reg18; + struct preg reg19; + struct preg res[6]; +}; + +/* + * Register initialization tables for the control display. + * + * Dot clock rate is + * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0]. + * + * The values for vertical frequency (V) in the comments below + * are the values measured using the modes under MacOS. + */ +struct control_regvals { + int pitch[3]; /* bytes/line, indexed by color_mode */ + int offset[3]; /* first pixel address */ + unsigned regs[16]; /* for vswin .. reg10 */ + unsigned char mode[3]; /* indexed by color_mode */ + unsigned char radacal_ctrl[3]; + unsigned char clock_params[3]; + int hres; + int vres; +}; + +/* Register values for 1280x1024, 75Hz mode (20) */ +static struct control_regvals control_reg_init_20 = { + { 1280, 2560, 0 }, + { 0x10, 0x20, 0 }, + { 2129, 2128, 80, 42, 4, 2130, 2132, 88, + 420, 411, 91, 35, 421, 18, 211, 386, }, + { 1, 1, 1}, + { 0x50, 0x64, 0x64 }, + { 13, 56, 3 }, /* pixel clock = 134.61MHz for V=74.81Hz */ + 1280, 1024 +}; + +/* Register values for 1280x960, 75Hz mode (19) */ +static struct control_regvals control_reg_init_19 = { + { 1280, 2560, 0 }, + { 0x10, 0x20, 0 }, + { 1997, 1996, 76, 40, 4, 1998, 2000, 86, + 418, 409, 89, 35, 419, 18, 210, 384, }, + { 1, 1, 1 }, + { 0x50, 0x64, 0x64 }, + { 31, 125, 3 }, /* pixel clock = 126.01MHz for V=75.01 Hz */ + 1280, 960 +}; + +/* Register values for 1152x870, 75Hz mode (18) */ +static struct control_regvals control_reg_init_18 = { + { 1152, 2304, 4608 }, + { 0x10, 0x28, 0x50 }, + { 1825, 1822, 82, 43, 4, 1828, 1830, 120, + 726, 705, 129, 63, 727, 32, 364, 664 }, + { 2, 1, 1 }, + { 0x10, 0x14, 0x28 }, + { 19, 61, 3 }, /* pixel clock = 100.33MHz for V=75.31Hz */ + 1152, 870 +}; + +/* Register values for 1024x768, 75Hz mode (17) */ +static struct control_regvals control_reg_init_17 = { + { 1024, 2048, 4096 }, + { 0x10, 0x28, 0x50 }, + { 1603, 1600, 64, 34, 4, 1606, 1608, 120, + 662, 641, 129, 47, 663, 24, 332, 616 }, + { 2, 1, 1 }, + { 0x10, 0x14, 0x28 }, + { 11, 28, 3 }, /* pixel clock = 79.55MHz for V=74.50Hz */ + 1024, 768 +}; + +/* Register values for 1024x768, 72Hz mode (15) */ +static struct control_regvals control_reg_init_15 = { + { 1024, 2048, 4096 }, + { 0x10, 0x28, 0x50 }, + { 1607, 1604, 68, 39, 10, 1610, 1612, 132, + 670, 653, 141, 67, 671, 34, 336, 604, }, + { 2, 1, 1 }, + { 0x10, 0x14, 0x28 }, + { 12, 30, 3 }, /* pixel clock = 78.12MHz for V=72.12Hz */ + 1024, 768 +}; + +/* Register values for 1024x768, 60Hz mode (14) */ +static struct control_regvals control_reg_init_14 = { + { 1024, 2048, 4096 }, + { 0x10, 0x28, 0x50 }, + { 1607, 1604, 68, 39, 10, 1610, 1612, 132, + 670, 653, 141, 67, 671, 34, 336, 604, }, + { 2, 1, 1 }, + { 0x10, 0x14, 0x28 }, + { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */ + 1024, 768 +}; + +/* Register values for 832x624, 75Hz mode (13) */ +static struct control_regvals control_reg_init_13 = { + { 832, 1664, 3328 }, + { 0x10, 0x28, 0x50 }, + { 1331, 1330, 82, 43, 4, 1332, 1334, 128, + 574, 553, 137, 31, 575, 16, 288, 544 }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ + 832, 624 +}; + +/* Register values for 800x600, 75Hz mode (12) */ +static struct control_regvals control_reg_init_12 = { + { 800, 1600, 3200 }, + { 0x10, 0x28, 0x50 }, + { 1247, 1246, 46, 25, 4, 1248, 1250, 104, + 526, 513, 113, 39, 527, 20, 264, 488, }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 7, 11, 3 }, /* pixel clock = 49.11MHz for V=74.40Hz */ + 800, 600 +}; + +/* Register values for 800x600, 72Hz mode (11) */ +static struct control_regvals control_reg_init_11 = { + { 800, 1600, 3200 }, + { 0x10, 0x28, 0x50 }, + { 1293, 1256, 56, 33, 10, 1330, 1332, 76, + 518, 485, 85, 59, 519, 30, 260, 460, }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */ + 800, 600 +}; + +/* Register values for 800x600, 60Hz mode (10) */ +static struct control_regvals control_reg_init_10 = { + { 800, 1600, 3200 }, + { 0x10, 0x28, 0x50 }, + { 1293, 1256, 56, 33, 10, 1330, 1332, 76, + 518, 485, 85, 59, 519, 30, 260, 460, }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 20, 53, 2 }, /* pixel clock = 41.41MHz for V=59.78Hz */ + 800, 600 +}; + +/* Register values for 640x870, 75Hz Full Page Display (7) */ +static struct control_regvals control_reg_init_7 = { + { 640, 1280, 2560 }, + { 0x10, 0x30, 0x68 }, + { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40, + 0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 9, 33, 2 }, /* pixel clock = 57.29MHz for V=75.01Hz */ + 640, 870 +}; + +/* Register values for 640x480, 67Hz mode (6) */ +static struct control_regvals control_reg_init_6 = { + { 640, 1280, 2560 }, + { 0, 8, 0x10 }, + { 1045, 1042, 82, 43, 4, 1048, 1050, 72, + 430, 393, 73, 31, 431, 16, 216, 400 }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */ + 640, 480 +}; + +/* Register values for 640x480, 60Hz mode (5) */ +static struct control_regvals control_reg_init_5 = { + { 640, 1280, 2560 }, + { 0x10, 0x28, 0x50 }, + { 1037, 1026, 66, 34, 2, 1048, 1050, 56, + 398, 385, 65, 47, 399, 24, 200, 352, }, + { 2, 1, 0 }, { 0x10, 0x14, 0x18 }, + { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */ + 640, 480 +}; + +static struct control_regvals *control_reg_init[VMODE_MAX] = { + NULL, NULL, NULL, NULL, + &control_reg_init_5, + &control_reg_init_6, + &control_reg_init_7, + NULL, NULL, + &control_reg_init_10, + &control_reg_init_11, + &control_reg_init_12, + &control_reg_init_13, + &control_reg_init_14, + &control_reg_init_15, + NULL, + &control_reg_init_17, + &control_reg_init_18, + &control_reg_init_19, + &control_reg_init_20 +}; diff -u --recursive --new-file v2.1.111/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c --- v2.1.111/linux/drivers/video/creatorfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/creatorfb.c Sun Jul 26 14:40:19 1998 @@ -1,4 +1,4 @@ -/* $Id: creatorfb.c,v 1.7 1998/07/21 10:36:48 jj Exp $ +/* $Id: creatorfb.c,v 1.10 1998/07/25 22:54:37 davem Exp $ * creatorfb.c: Creator/Creator3D frame buffer driver * * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -185,7 +185,7 @@ int x, y, w, h; fbc->ppc = 0x1803; - fbc->fg = ffb_cmap[attr_bg_col_ec(conp)]; + fbc->fg = ffb_cmap[attr_bgcol_ec(p,conp)]; fbc->fbc = 0x2000707f; fbc->rop = 0x83; fbc->pmask = 0xffffffff; @@ -207,13 +207,13 @@ fbc->bw = w; } -static void ffb_fill(struct fb_info_sbusfb *fb, int s, +static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s, int count, unsigned short *boxes) { register struct ffb_fbc *fbc = fb->s.ffb.fbc; fbc->ppc = 0x1803; - fbc->fg = ffb_cmap[attr_bg_col(s)]; + fbc->fg = ffb_cmap[attr_bgcol(p,s)]; fbc->fbc = 0x2000707f; fbc->rop = 0x83; fbc->pmask = 0xffffffff; @@ -236,11 +236,15 @@ if (p->fontheightlog) { xy = (yy << (16 + p->fontheightlog)); - i = ((c & 0xff) << p->fontheightlog); + i = ((c & p->charmask) << p->fontheightlog); } else { xy = ((yy * p->fontheight) << 16); - i = (c & 0xff) * p->fontheight; + i = (c & p->charmask) * p->fontheight; } +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + fd = p->fontdata + i; + xy += (xx * 8) + fb->s.ffb.xy_margin; +#else if (p->fontwidth <= 8) fd = p->fontdata + i; else @@ -249,24 +253,29 @@ xy += (xx << p->fontwidthlog) + fb->s.ffb.xy_margin; else xy += (xx * p->fontwidth) + fb->s.ffb.xy_margin; +#endif fbc->ppc = 0x203; - fbc->fg = ffb_cmap[attr_fg_col(c)]; + fbc->fg = ffb_cmap[attr_fgcol(p,c)]; fbc->fbc = 0x2000707f; fbc->rop = 0x83; fbc->pmask = 0xffffffff; - fbc->bg = ffb_cmap[attr_bg_col(c)]; + fbc->bg = ffb_cmap[attr_bgcol(p,c)]; fbc->fontw = p->fontwidth; fbc->fontinc = 0x10000; fbc->fontxy = xy; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif for (i = 0; i < p->fontheight; i++) fbc->font = *fd++ << 24; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { for (i = 0; i < p->fontheight; i++) { fbc->font = *(u16 *)fd << 16; fd += 2; } } +#endif } static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, @@ -278,42 +287,51 @@ u8 *fd1, *fd2, *fd3, *fd4; fbc->ppc = 0x203; - fbc->fg = ffb_cmap[attr_fg_col(*s)]; + fbc->fg = ffb_cmap[attr_fgcol(p,*s)]; fbc->fbc = 0x2000707f; fbc->rop = 0x83; fbc->pmask = 0xffffffff; - fbc->bg = ffb_cmap[attr_bg_col(*s)]; + fbc->bg = ffb_cmap[attr_bgcol(p,*s)]; xy = fb->s.ffb.xy_margin; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + xy += xx * 8; +#else if (p->fontwidthlog) xy += (xx << p->fontwidthlog); else xy += xx * p->fontwidth; +#endif if (p->fontheightlog) xy += (yy << (16 + p->fontheightlog)); else xy += ((yy * p->fontheight) << 16); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif while (count >= 4) { count -= 4; fbc->fontw = 4 * p->fontwidth; fbc->fontinc = 0x10000; fbc->fontxy = xy; if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); - fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog); + fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); } else { - fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight); - fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight); + fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth == 8) { +#endif for (i = 0; i < p->fontheight; i++) fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) << 8)) << 8)) << 8); xy += 32; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { for (i = 0; i < p->fontheight; i++) fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) @@ -328,11 +346,11 @@ fbc->fontinc = 0x10000; fbc->fontxy = xy; if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1)); - fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1)); + fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); + fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); } else { - fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1); - fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1); + fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); + fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); } for (i = 0; i < p->fontheight; i++) { fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth); @@ -340,6 +358,7 @@ } xy += 2 * p->fontwidth; } +#endif } while (count) { count--; @@ -347,13 +366,16 @@ fbc->fontinc = 0x10000; fbc->fontxy = xy; if (p->fontheightlog) - i = ((*s++ & 0xff) << p->fontheightlog); + i = ((*s++ & p->charmask) << p->fontheightlog); else - i = ((*s++ & 0xff) * p->fontheight); + i = ((*s++ & p->charmask) * p->fontheight); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY if (p->fontwidth <= 8) { +#endif fd1 = p->fontdata + i; for (i = 0; i < p->fontheight; i++) fbc->font = *fd1++ << 24; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { fd1 = p->fontdata + (i << 1); for (i = 0; i < p->fontheight; i++) { @@ -361,6 +383,7 @@ fd1 += 2; } } +#endif xy += p->fontwidth; } } @@ -471,11 +494,8 @@ strcpy(fb->info.modename, "Creator"); strcpy(fix->id, "Creator"); - fix->smem_start = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF; fix->visual = FB_VISUAL_DIRECTCOLOR; fix->line_length = 8192; - fix->mmio_start = (char *)(regs[0].phys_addr) + FFB_FBC_REGS_POFF; - fix->mmio_len = PAGE_SIZE; fix->accel = FB_ACCEL_SUN_CREATOR; var->bits_per_pixel = 32; diff -u --recursive --new-file v2.1.111/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c --- v2.1.111/linux/drivers/video/cyberfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/cyberfb.c Sun Jul 26 14:40:19 1998 @@ -21,6 +21,7 @@ */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c --- v2.1.111/linux/drivers/video/dnfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/dnfb.c Sun Jul 26 14:40:19 1998 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/dummycon.c linux/drivers/video/dummycon.c --- v2.1.111/linux/drivers/video/dummycon.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/dummycon.c Sun Jul 26 14:40:19 1998 @@ -5,7 +5,6 @@ * available, usually until fbcon takes console over. */ -#include #include #include #include @@ -18,11 +17,7 @@ * Dummy console driver */ -#ifdef __sparc__ -/* Some reasonable defaults, so that we don't loose any text */ -#define DUMMY_COLUMNS 128 -#define DUMMY_ROWS 54 -#elif defined(CONFIG_ARM) +#if defined(CONFIG_ARM) #define DUMMY_COLUMNS ORIG_VIDEO_COLS #define DUMMY_ROWS ORIG_VIDEO_LINES #else diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c --- v2.1.111/linux/drivers/video/fbcon-afb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-afb.c Sun Jul 26 14:40:19 1998 @@ -251,7 +251,7 @@ int fg, bg; dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat0 = p->fontdata+(c&0xff)*p->fontheight; + cdat0 = p->fontdata+(c&p->charmask)*p->fontheight; fg = attr_fgcol(p,c); bg = attr_bgcol(p,c); @@ -286,7 +286,7 @@ u8 *dest, *dest0, *dest1, *expand; u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40; u_short i, j; - u8 c1, c2, c3, c4; + u16 c1, c2, c3, c4; int fg0, bg0, fg, bg; dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; @@ -295,7 +295,7 @@ while (count--) if (xx&3 || count < 3) { /* Slow version */ - c1 = *s++; + c1 = *s++ & p->charmask; dest1 = dest0++; xx++; @@ -322,10 +322,10 @@ dest1 += p->next_plane; } while (--i); } else { /* Fast version */ - c1 = s[0]; - c2 = s[1]; - c3 = s[2]; - c4 = s[3]; + c1 = s[0] & p->charmask; + c2 = s[1] & p->charmask; + c3 = s[2] & p->charmask; + c4 = s[3] & p->charmask; dest1 = dest0; cdat10 = p->fontdata+c1*p->fontheight; diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-afb.h linux/drivers/video/fbcon-afb.h --- v2.1.111/linux/drivers/video/fbcon-afb.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-afb.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Amiga bitplanes (afb) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE) #define FBCON_HAS_AFB diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c --- v2.1.111/linux/drivers/video/fbcon-cfb16.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb16.c Sun Jul 26 14:40:19 1998 @@ -47,23 +47,34 @@ int bytes = p->next_line, linesize = bytes * p->fontheight, rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * 16 == bytes) + if (sx == 0 && dx == 0 && width * p->fontwidth * 2 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); - else if (dy < sy || (dy == sy && dx < sx)) { - src = p->screen_base + sy * linesize + sx * 16; - dst = p->screen_base + dy * linesize + dx * 16; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 16); + return; + } + if (p->fontwidthlog) { + sx <<= p->fontwidthlog+1; + dx <<= p->fontwidthlog+1; + width <<= p->fontwidthlog+1; + } else { + sx *= p->fontwidth*2; + dx *= p->fontwidth*2; + width *= p->fontwidth*2; + } + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx; + dst = p->screen_base + dy * linesize + dx; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src += bytes; dst += bytes; } } else { - src = p->screen_base + (sy+height) * linesize + sx * 16 - bytes; - dst = p->screen_base + (dy+height) * linesize + dx * 16 - bytes; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 16); + src = p->screen_base + (sy+height) * linesize + sx - bytes; + dst = p->screen_base + (dy+height) * linesize + dx - bytes; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src -= bytes; dst -= bytes; } @@ -77,29 +88,26 @@ int bytes = p->next_line, lines = height * p->fontheight, rows, i; u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * 16; + dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 2; bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)]; bgx |= (bgx << 16); - if (sx == 0 && width * 16 == bytes) - for (i = 0 ; i < lines * width ; i++) { + width *= p->fontwidth/4; + if (sx == 0 && width * 8 == bytes) + for (i = 0; i < lines * width; i++) { ((u32 *)dest)[0] = bgx; ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - dest += 16; + dest += 8; } else { dest0 = dest; - for (rows = lines; rows-- ; dest0 += bytes) { + for (rows = lines; rows--; dest0 += bytes) { dest = dest0; - for (i = 0 ; i < width ; i++) { + for (i = 0; i < width; i++) { ((u32 *)dest)[0] = bgx; ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - dest += 16; + dest += 8; } } } @@ -108,12 +116,11 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - u8 *dest, *cdat; + u8 *dest, *cdat, bits; int bytes = p->next_line, rows; u32 eorx, fgx, bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; - cdat = p->fontdata + (c & 0xff) * p->fontheight; + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2; fgx = fbcon_cfb16_cmap[attr_fgcol(p, c)]; bgx = fbcon_cfb16_cmap[attr_bgcol(p, c)]; @@ -121,41 +128,112 @@ bgx |= (bgx << 16); eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - u8 bits = *cdat++; - ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; - ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; - ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; - ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + switch (p->fontwidth) { + case 4: + case 8: +#endif + cdat = p->fontdata + (c & p->charmask) * p->fontheight; + for (rows = p->fontheight; rows--; dest += bytes) { + bits = *cdat++; + ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth == 8) +#endif + { + ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + } + } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + break; + case 12: + case 16: + cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); + for (rows = p->fontheight; rows--; dest += bytes) { + bits = *cdat++; + ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; + ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + bits = *cdat++; + ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; + if (p->fontwidth == 16) { + ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + } + } + break; } +#endif } -void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, +void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0; + u16 c; int rows, bytes = p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16; + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2; fgx = fbcon_cfb16_cmap[attr_fgcol(p, *s)]; bgx = fbcon_cfb16_cmap[attr_bgcol(p, *s)]; fgx |= (fgx << 16); bgx |= (bgx << 16); eorx = fgx ^ bgx; - while (count--) { - c = *s++; - cdat = p->fontdata + c * p->fontheight; - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { - u8 bits = *cdat++; - ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; - ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; - ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; - ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + switch (p->fontwidth) { + case 4: + case 8: +#endif + while (count--) { + c = *s++ & p->charmask; + cdat = p->fontdata + c * p->fontheight; + for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + u8 bits = *cdat++; + ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth == 8) +#endif + { + + ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + } + } + dest0 += p->fontwidth*2;; + } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + break; + case 12: + case 16: + while (count--) { + c = *s++ & p->charmask; + cdat = p->fontdata + (c * p->fontheight << 1); + for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + u8 bits = *cdat++; + ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; + ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + bits = *cdat++; + ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; + ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; + if (p->fontwidth == 16) { + ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; + ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx; + } + } + dest0 += p->fontwidth*2; } - dest0 += 16; + break; } +#endif } void fbcon_cfb16_revc(struct display *p, int xx, int yy) @@ -163,12 +241,60 @@ u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - ((u32 *)dest)[0] ^= 0xffffffff; - ((u32 *)dest)[1] ^= 0xffffffff; - ((u32 *)dest)[2] ^= 0xffffffff; - ((u32 *)dest)[3] ^= 0xffffffff; + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth*2; + for (rows = p->fontheight; rows--; dest += bytes) { +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; +#else + switch (p->fontwidth) { + case 16: + ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; + /* FALL THROUGH */ + case 12: + ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff; + /* FALL THROUGH */ + case 8: + ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; + /* FALL THROUGH */ + case 4: + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; + } +#endif + } +} + +void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p) +{ + u8 *dest0; + u32 *dest; + int bytes = p->next_line; + u32 bgx; + int i, j; + + unsigned int right_start = conp->vc_cols*p->fontwidth; + unsigned int right_width = p->var.xres_virtual-right_start; + unsigned int bottom_start = conp->vc_rows*p->fontheight; + unsigned int bottom_width = p->var.yres_virtual-bottom_start; + + bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)]; + bgx |= (bgx << 16); + + if (right_width) { + dest0 = p->screen_base+right_start*2; + for (i = 0; i < bottom_start; i++, dest0 += bytes) { + for (j = 0, dest = (u32 *)dest0; j < right_width/2; j++) + *dest++ = bgx; + if (right_width & 1) + *(u16 *)dest = bgx; + } + } + if (bottom_width) { + dest = (u32 *)(p->screen_base+bottom_start*bytes); + for (i = 0; i < bytes*bottom_width/4; i++) + *dest++ = bgx; + if ((bytes*bottom_width) & 2) + *(u16 *)dest = bgx; } } @@ -179,7 +305,8 @@ struct display_switch fbcon_cfb16 = { fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc, - fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb16.h linux/drivers/video/fbcon-cfb16.h --- v2.1.111/linux/drivers/video/fbcon-cfb16.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb16.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 16 bpp packed pixel (cfb16) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE) #define FBCON_HAS_CFB16 @@ -26,3 +24,4 @@ extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx); extern void fbcon_cfb16_revc(struct display *p, int xx, int yy); +extern void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p); diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c --- v2.1.111/linux/drivers/video/fbcon-cfb2.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb2.c Sun Jul 26 14:40:19 1998 @@ -129,7 +129,7 @@ u32 eorx,fgx,bgx; dest = p->screen_base + yy * p->fontheight * bytes + xx * 2; - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; fgx=3;/*attr_fgcol(p,c);*/ bgx=attr_bgcol(p,c); @@ -150,7 +150,8 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0; + u16 c; int rows,bytes=p->next_line; u32 eorx, fgx, bgx; @@ -163,7 +164,7 @@ bgx |= (bgx << 4); eorx = fgx ^ bgx; while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + c * p->fontheight; for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb2.h linux/drivers/video/fbcon-cfb2.h --- v2.1.111/linux/drivers/video/fbcon-cfb2.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb2.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 2 bpp packed pixel (cfb2) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE) #define FBCON_HAS_CFB2 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c --- v2.1.111/linux/drivers/video/fbcon-cfb24.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb24.c Sun Jul 26 14:40:19 1998 @@ -37,29 +37,56 @@ int bytes = p->next_line, linesize = bytes * p->fontheight, rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * 24 == bytes) + if (sx == 0 && dx == 0 && width * p->fontwidth * 3 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); - else if (dy < sy || (dy == sy && dx < sx)) { - src = p->screen_base + sy * linesize + sx * 24; - dst = p->screen_base + dy * linesize + dx * 24; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 24); + return; + } + if (p->fontwidthlog) { + sx <<= p->fontwidthlog; + dx <<= p->fontwidthlog; + width <<= p->fontwidthlog; + } else { + sx *= p->fontwidth; + dx *= p->fontwidth; + width *= p->fontwidth; + } + sx *= 3; dx *= 3; width *= 3; + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx; + dst = p->screen_base + dy * linesize + dx; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src += bytes; dst += bytes; } } else { - src = p->screen_base + (sy+height) * linesize + sx * 24 - bytes; - dst = p->screen_base + (dy+height) * linesize + dx * 24 - bytes; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 24); + src = p->screen_base + (sy+height) * linesize + sx - bytes; + dst = p->screen_base + (dy+height) * linesize + dx - bytes; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src -= bytes; dst -= bytes; } } } +static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest) +{ +#if defined(__BIG_ENDIAN) + *dest++ = (d1<<8) | (d2>>16); + *dest++ = (d2<<16) | (d3>>8); + *dest++ = (d3<<24) | d4; +#elif defined(__LITTLE_ENDIAN) + *dest++ = (d1<<8) | (d2>>16); + *dest++ = (d2<<16) | (d3>>8); + *dest++ = (d3<<24) | d4; +#else +#error FIXME: No endianness?? +#endif +} + void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { @@ -67,112 +94,139 @@ int bytes = p->next_line, lines = height * p->fontheight, rows, i; u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * 24; + dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 3; bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)]; - if (sx == 0 && width * 24 == bytes) - for (i = 0 ; i < lines * width ; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - ((u32 *)dest)[4] = bgx; - ((u32 *)dest)[5] = bgx; - dest += 24; + width *= p->fontwidth/4; + if (sx == 0 && width * 12 == bytes) + for (i = 0; i < lines * width; i++) { + store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); + dest += 12; } else { dest0 = dest; - for (rows = lines; rows-- ; dest0 += bytes) { + for (rows = lines; rows--; dest0 += bytes) { dest = dest0; - for (i = 0 ; i < width ; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - ((u32 *)dest)[4] = bgx; - ((u32 *)dest)[5] = bgx; - dest += 24; + for (i = 0; i < width; i++) { + store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); + dest += 12; } } } } -static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest) -{ -#if defined(__BIG_ENDIAN) - *dest++ = (d1<<8) | (d2>>16); - *dest++ = (d2<<16) | (d3>>8); - *dest++ = (d3<<24) | d4; -#elif defined(__LITTLE_ENDIAN) - *dest++ = (d1<<8) | (d2>>16); - *dest++ = (d2<<16) | (d3>>8); - *dest++ = (d3<<24) | d4; -#else -#error FIXME: No endianness?? -#endif -} - void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - u8 *dest, *cdat; + u8 *dest, *cdat, bits; int bytes = p->next_line, rows; - u32 eorx, fgx, bgx; + u32 eorx, fgx, bgx, d1, d2, d3, d4; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 24; - cdat = p->fontdata + (c & 0xff) * p->fontheight; + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; + if (p->fontwidth <= 8) + cdat = p->fontdata + (c & p->charmask) * p->fontheight; + else + cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); fgx = fbcon_cfb24_cmap[attr_fgcol(p, c)]; bgx = fbcon_cfb24_cmap[attr_bgcol(p, c)]; eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - u8 bits = *cdat++; - u32 d1, d2, d3, d4; + for (rows = p->fontheight; rows--; dest += bytes) { + bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)dest); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 8) + continue; +#endif d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 12) + continue; + bits = *cdat++; + d1 = (-(bits >> 7) & eorx) ^ bgx; + d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; + d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; + d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; + store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); + if (p->fontwidth < 16) + continue; + d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; + d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; + d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; + d4 = (-(bits & 1) & eorx) ^ bgx; + store4pixels(d1, d2, d3, d4, (u32 *)(dest+32)); +#endif } } -void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, +void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0, bits; + u16 c; int rows, bytes = p->next_line; - u32 eorx, fgx, bgx; + u32 eorx, fgx, bgx, d1, d2, d3, d4; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 24; + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; fgx = fbcon_cfb24_cmap[attr_fgcol(p, *s)]; bgx = fbcon_cfb24_cmap[attr_bgcol(p, *s)]; eorx = fgx ^ bgx; while (count--) { - c = *s++; + c = *s++ & p->charmask; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY cdat = p->fontdata + c * p->fontheight; - - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { - u8 bits = *cdat++; - u32 d1, d2, d3, d4; +#else + if (p->fontwidth <= 8) + cdat = p->fontdata + c * p->fontheight; + + else + cdat = p->fontdata + (c * p->fontheight << 1); +#endif + for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)dest); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 8) + continue; +#endif d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 12) + continue; + bits = *cdat++; + d1 = (-(bits >> 7) & eorx) ^ bgx; + d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; + d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; + d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; + store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); + if (p->fontwidth < 16) + continue; + d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; + d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; + d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; + d4 = (-(bits & 1) & eorx) ^ bgx; + store4pixels(d1, d2, d3, d4, (u32 *)(dest+32)); +#endif } - dest0 += 24; + dest0 += p->fontwidth*3; } } @@ -181,14 +235,60 @@ u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 24; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - ((u32 *)dest)[0] ^= 0xffffffff; - ((u32 *)dest)[1] ^= 0xffffffff; - ((u32 *)dest)[2] ^= 0xffffffff; - ((u32 *)dest)[3] ^= 0xffffffff; - ((u32 *)dest)[4] ^= 0xffffffff; + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; + for (rows = p->fontheight; rows--; dest += bytes) { +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff; + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; + ((u32 *)dest)[2] ^= 0xffffffff; +#else + switch (p->fontwidth) { + case 16: + ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff; + ((u32 *)dest)[11] ^= 0xffffffff; /* FALL THROUGH */ + case 12: + ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; + ((u32 *)dest)[8] ^= 0xffffffff; /* FALL THROUGH */ + case 8: + ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff; + ((u32 *)dest)[5] ^= 0xffffffff; /* FALL THROUGH */ + case 4: + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; + ((u32 *)dest)[2] ^= 0xffffffff; + } +#endif + } +} + +void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p) +{ + u8 *dest0, *dest; + int bytes = p->next_line; + u32 bgx; + int i, j; + + unsigned int right_start = conp->vc_cols*p->fontwidth; + unsigned int right_width = p->var.xres_virtual-right_start; + unsigned int bottom_start = conp->vc_rows*p->fontheight; + unsigned int bottom_width = p->var.yres_virtual-bottom_start; + + bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)]; + + if (right_width) { + dest0 = p->screen_base+right_start*3; + for (i = 0; i < bottom_start; i++, dest0 += bytes) + for (j = 0, dest = dest0; j < right_width/4; j++) { + store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); + dest += 12; + } + } + if (bottom_width) { + dest = p->screen_base+bottom_start*bytes; + for (i = 0; i < bytes*bottom_width/12; i++) { + store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); + dest += 12; + } } } @@ -199,7 +299,8 @@ struct display_switch fbcon_cfb24 = { fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc, - fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb24.h linux/drivers/video/fbcon-cfb24.h --- v2.1.111/linux/drivers/video/fbcon-cfb24.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb24.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 24 bpp packed pixel (cfb24) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE) #define FBCON_HAS_CFB24 @@ -26,3 +24,4 @@ extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx); extern void fbcon_cfb24_revc(struct display *p, int xx, int yy); +extern void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p); diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c --- v2.1.111/linux/drivers/video/fbcon-cfb32.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb32.c Sun Jul 26 14:40:19 1998 @@ -37,23 +37,34 @@ int bytes = p->next_line, linesize = bytes * p->fontheight, rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * 32 == bytes) + if (sx == 0 && dx == 0 && width * p->fontwidth * 4 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); - else if (dy < sy || (dy == sy && dx < sx)) { - src = p->screen_base + sy * linesize + sx * 32; - dst = p->screen_base + dy * linesize + dx * 32; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 32); + return; + } + if (p->fontwidthlog) { + sx <<= p->fontwidthlog+2; + dx <<= p->fontwidthlog+2; + width <<= p->fontwidthlog+2; + } else { + sx *= p->fontwidth*4; + dx *= p->fontwidth*4; + width *= p->fontwidth*4; + } + if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx; + dst = p->screen_base + dy * linesize + dx; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src += bytes; dst += bytes; } } else { - src = p->screen_base + (sy+height) * linesize + sx * 32 - bytes; - dst = p->screen_base + (dy+height) * linesize + dx * 32 - bytes; - for (rows = height * p->fontheight ; rows-- ;) { - mymemmove(dst, src, width * 32); + src = p->screen_base + (sy+height) * linesize + sx - bytes; + dst = p->screen_base + (dy+height) * linesize + dx - bytes; + for (rows = height * p->fontheight; rows--;) { + mymemmove(dst, src, width); src -= bytes; dst -= bytes; } @@ -67,36 +78,29 @@ int bytes = p->next_line, lines = height * p->fontheight, rows, i; u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * 32; + dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 4; bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)]; - if (sx == 0 && width * 32 == bytes) - for (i = 0 ; i < lines * width ; i++) { + width *= p->fontwidth/4; + if (sx == 0 && width * 16 == bytes) + for (i = 0; i < lines * width; i++) { ((u32 *)dest)[0] = bgx; ((u32 *)dest)[1] = bgx; ((u32 *)dest)[2] = bgx; ((u32 *)dest)[3] = bgx; - ((u32 *)dest)[4] = bgx; - ((u32 *)dest)[5] = bgx; - ((u32 *)dest)[6] = bgx; - ((u32 *)dest)[7] = bgx; - dest += 32; + dest += 16; } else { dest0 = dest; - for (rows = lines; rows-- ; dest0 += bytes) { + for (rows = lines; rows--; dest0 += bytes) { dest = dest0; - for (i = 0 ; i < width ; i++) { + for (i = 0; i < width; i++) { ((u32 *)dest)[0] = bgx; ((u32 *)dest)[1] = bgx; ((u32 *)dest)[2] = bgx; ((u32 *)dest)[3] = bgx; - ((u32 *)dest)[4] = bgx; - ((u32 *)dest)[5] = bgx; - ((u32 *)dest)[6] = bgx; - ((u32 *)dest)[7] = bgx; - dest += 32; + dest += 16; } } } @@ -105,57 +109,108 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - u8 *dest, *cdat; + u8 *dest, *cdat, bits; int bytes = p->next_line, rows; u32 eorx, fgx, bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 32; - cdat = p->fontdata + (c & 0xff) * p->fontheight; - + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + cdat = p->fontdata + (c & p->charmask) * p->fontheight; +#else + if (p->fontwidth <= 8) + cdat = p->fontdata + (c & p->charmask) * p->fontheight; + else + cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); +#endif fgx = fbcon_cfb32_cmap[attr_fgcol(p, c)]; bgx = fbcon_cfb32_cmap[attr_bgcol(p, c)]; eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - u8 bits = *cdat++; + for (rows = p->fontheight; rows--; dest += bytes) { + bits = *cdat++; ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 8) + continue; +#endif ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 12) + continue; + bits = *cdat++; + ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx; + ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx; + ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx; + ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx; + if (p->fontwidth < 16) + continue; + ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx; + ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx; + ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx; + ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx; +#endif } } -void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, +void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0, bits; + u16 c; int rows, bytes = p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 32; + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; fgx = fbcon_cfb32_cmap[attr_fgcol(p, *s)]; bgx = fbcon_cfb32_cmap[attr_bgcol(p, *s)]; eorx = fgx ^ bgx; while (count--) { - c = *s++; + c = *s++ & p->charmask; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY cdat = p->fontdata + c * p->fontheight; - - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { - u8 bits = *cdat++; +#else + if (p->fontwidth <= 8) + cdat = p->fontdata + c * p->fontheight; + else + cdat = p->fontdata + (c * p->fontheight << 1); +#endif + for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + bits = *cdat++; ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 8) + continue; +#endif ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth < 12) + continue; + bits = *cdat++; + ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx; + ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx; + ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx; + ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx; + if (p->fontwidth < 16) + continue; + ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx; + ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx; + ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx; + ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx; +#endif } - dest0 += 32; + dest0 += p->fontwidth*4; } } @@ -164,16 +219,61 @@ u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 32; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - ((u32 *)dest)[0] ^= 0xffffffff; - ((u32 *)dest)[1] ^= 0xffffffff; - ((u32 *)dest)[2] ^= 0xffffffff; - ((u32 *)dest)[3] ^= 0xffffffff; - ((u32 *)dest)[4] ^= 0xffffffff; - ((u32 *)dest)[5] ^= 0xffffffff; - ((u32 *)dest)[6] ^= 0xffffffff; - ((u32 *)dest)[7] ^= 0xffffffff; + dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; + for (rows = p->fontheight; rows--; dest += bytes) { +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff; + ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; + ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; +#else + switch (p->fontwidth) { + case 16: + ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff; + ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff; + /* FALL THROUGH */ + case 12: + ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff; + ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff; + /* FALL THROUGH */ + case 8: + ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff; + ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; + /* FALL THROUGH */ + case 4: + ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; + ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; + /* FALL THROUGH */ + } +#endif + } +} + +void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p) +{ + u8 *dest0; + u32 *dest; + int bytes = p->next_line; + u32 bgx; + int i, j; + + unsigned int right_start = conp->vc_cols*p->fontwidth; + unsigned int right_width = p->var.xres_virtual-right_start; + unsigned int bottom_start = conp->vc_rows*p->fontheight; + unsigned int bottom_width = p->var.yres_virtual-bottom_start; + + bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)]; + + if (right_width) { + dest0 = p->screen_base+right_start*4; + for (i = 0; i < bottom_start; i++, dest0 += bytes) + for (j = 0, dest = (u32 *)dest0; j < right_width; j++) + *dest++ = bgx; + } + if (bottom_width) { + dest = (u32 *)(p->screen_base+bottom_start*bytes); + for (i = 0; i < bytes*bottom_width/4; i++) + *dest++ = bgx; } } @@ -184,7 +284,8 @@ struct display_switch fbcon_cfb32 = { fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc, - fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb32.h linux/drivers/video/fbcon-cfb32.h --- v2.1.111/linux/drivers/video/fbcon-cfb32.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb32.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 32 bpp packed pixel (cfb32) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE) #define FBCON_HAS_CFB32 @@ -26,3 +24,4 @@ extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx); extern void fbcon_cfb32_revc(struct display *p, int xx, int yy); +extern void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p); diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c --- v2.1.111/linux/drivers/video/fbcon-cfb4.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb4.c Sun Jul 26 14:40:19 1998 @@ -131,7 +131,7 @@ u32 eorx,fgx,bgx; dest = p->screen_base + yy * p->fontheight * bytes + xx * 4; - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; fgx=15;/*attr_fgcol(p,c);*/ bgx=attr_bgcol(p,c); @@ -152,7 +152,8 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0; + u16 c; int rows,bytes=p->next_line; u32 eorx, fgx, bgx; @@ -167,7 +168,7 @@ bgx |= (bgx << 16); eorx = fgx ^ bgx; while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + c * p->fontheight; for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb4.h linux/drivers/video/fbcon-cfb4.h --- v2.1.111/linux/drivers/video/fbcon-cfb4.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb4.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 4 bpp packed pixel (cfb4) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE) #define FBCON_HAS_CFB4 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c --- v2.1.111/linux/drivers/video/fbcon-cfb8.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb8.c Sun Jul 26 14:40:19 1998 @@ -110,9 +110,9 @@ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth; if (p->fontwidth <= 8) - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; else - cdat = p->fontdata + ((c & 0xff) * p->fontheight << 1); + cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); fgx=attr_fgcol(p,c); bgx=attr_bgcol(p,c); @@ -122,16 +122,19 @@ bgx |= (bgx << 16); eorx = fgx ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY switch (p->fontwidth) { case 4: for (rows = p->fontheight ; rows-- ; dest += bytes) ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx; break; case 8: +#endif for (rows = p->fontheight ; rows-- ; dest += bytes) { ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx; ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx; } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: @@ -145,12 +148,14 @@ } break; } +#endif } void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx) { - u8 *cdat, c, *dest, *dest0; + u8 *cdat, *dest, *dest0; + u16 c; int rows,bytes=p->next_line; u32 eorx, fgx, bgx; @@ -162,10 +167,11 @@ bgx |= (bgx << 8); bgx |= (bgx << 16); eorx = fgx ^ bgx; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY switch (p->fontwidth) { case 4: while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + c * p->fontheight; for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) @@ -174,8 +180,9 @@ } break; case 8: +#endif while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + c * p->fontheight; for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { @@ -184,11 +191,12 @@ } dest0+=8; } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight << 1); for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { @@ -203,6 +211,7 @@ } break; } +#endif } void fbcon_cfb8_revc(struct display *p, int xx, int yy) @@ -212,6 +221,10 @@ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth; for (rows = p->fontheight ; rows-- ; dest += bytes) { +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + ((u32 *)dest)[1] ^= 0x0f0f0f0f; + ((u32 *)dest)[0] ^= 0x0f0f0f0f; +#else switch (p->fontwidth) { case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */ case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */ @@ -219,6 +232,7 @@ case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f; /* FALL THROUGH */ default: break; } +#endif } } diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb8.h linux/drivers/video/fbcon-cfb8.h --- v2.1.111/linux/drivers/video/fbcon-cfb8.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-cfb8.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * 8 bpp packed pixel (cfb8) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE) #define FBCON_HAS_CFB8 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c --- v2.1.111/linux/drivers/video/fbcon-ilbm.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-ilbm.c Sun Jul 26 14:40:19 1998 @@ -103,7 +103,7 @@ int fg0, bg0, fg, bg; dest = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat = p->fontdata+(c&0xff)*p->fontheight; + cdat = p->fontdata+(c&p->charmask)*p->fontheight; fg0 = attr_fgcol(p,c); bg0 = attr_bgcol(p,c); @@ -149,7 +149,7 @@ { u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4; u_int rows, i; - u8 c1, c2, c3, c4; + u16 c1, c2, c3, c4; u32 d; int fg0, bg0, fg, bg; @@ -159,7 +159,7 @@ while (count--) if (xx&3 || count < 3) { /* Slow version */ - c1 = *s++; + c1 = *s++ & p->charmask; dest = dest0++; xx++; @@ -185,10 +185,10 @@ } } } else { /* Fast version */ - c1 = s[0]; - c2 = s[1]; - c3 = s[2]; - c4 = s[3]; + c1 = s[0] & p->charmask; + c2 = s[1] & p->charmask; + c3 = s[2] & p->charmask; + c4 = s[3] & p->charmask; dest = dest0; cdat1 = p->fontdata+c1*p->fontheight; diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-ilbm.h linux/drivers/video/fbcon-ilbm.h --- v2.1.111/linux/drivers/video/fbcon-ilbm.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-ilbm.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Amiga interleaved bitplanes (ilbm) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE) #define FBCON_HAS_ILBM diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c --- v2.1.111/linux/drivers/video/fbcon-iplan2p2.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p2.c Sun Jul 26 14:40:19 1998 @@ -307,7 +307,7 @@ u16 eorx, fgx, bgx, fdx; dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1); - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; fgx = expand2w(COLOR_2P(attr_fgcol(p,c))); bgx = expand2w(COLOR_2P(attr_bgcol(p,c))); @@ -323,7 +323,8 @@ const unsigned short *s, int count, int yy, int xx) { u8 *dest, *dest0; - u8 *cdat, c; + u8 *cdat; + u16 c; int rows; int bytes; u16 eorx, fgx, bgx, fdx; @@ -335,7 +336,7 @@ eorx = fgx ^ bgx; while (count--) { - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight); for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p2.h linux/drivers/video/fbcon-iplan2p2.h --- v2.1.111/linux/drivers/video/fbcon-iplan2p2.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p2.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Atari interleaved bitplanes (2 planes) (iplan2p2) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE) #define FBCON_HAS_IPLAN2P2 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c --- v2.1.111/linux/drivers/video/fbcon-iplan2p4.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p4.c Sun Jul 26 14:40:19 1998 @@ -317,7 +317,7 @@ u32 eorx, fgx, bgx, fdx; dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1); - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; fgx = expand4l(attr_fgcol(p,c)); bgx = expand4l(attr_bgcol(p,c)); @@ -333,7 +333,8 @@ const unsigned short *s, int count, int yy, int xx) { u8 *dest, *dest0; - u8 *cdat, c; + u8 *cdat; + u16 c; int rows; int bytes; u32 eorx, fgx, bgx, fdx; @@ -352,7 +353,7 @@ * cache :-( */ - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight); for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p4.h linux/drivers/video/fbcon-iplan2p4.h --- v2.1.111/linux/drivers/video/fbcon-iplan2p4.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p4.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Atari interleaved bitplanes (4 planes) (iplan2p4) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE) #define FBCON_HAS_IPLAN2P4 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c --- v2.1.111/linux/drivers/video/fbcon-iplan2p8.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p8.c Sun Jul 26 14:40:19 1998 @@ -349,7 +349,7 @@ u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1); - cdat = p->fontdata + (c & 0xff) * p->fontheight; + cdat = p->fontdata + (c & p->charmask) * p->fontheight; expand8dl(attr_fgcol(p,c), &fgx1, &fgx2); expand8dl(attr_bgcol(p,c), &bgx1, &bgx2); @@ -365,7 +365,8 @@ const unsigned short *s, int count, int yy, int xx) { u8 *dest, *dest0; - u8 *cdat, c; + u8 *cdat; + u16 c; int rows; int bytes; u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; @@ -387,7 +388,7 @@ * cache :-( */ - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight); for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p8.h linux/drivers/video/fbcon-iplan2p8.h --- v2.1.111/linux/drivers/video/fbcon-iplan2p8.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-iplan2p8.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Atari interleaved bitplanes (8 planes) (iplan2p8) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE) #define FBCON_HAS_IPLAN2P8 diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c --- v2.1.111/linux/drivers/video/fbcon-mac.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-mac.c Sun Jul 26 14:40:19 1998 @@ -272,7 +272,7 @@ u8 d; int j; - cdat = p->fontdata+(c&0xff)*p->fontheight; + cdat = p->fontdata+(c&p->charmask)*p->fontheight; bold = attr_bold(p,c); ch_reverse = attr_reverse(p,c); ch_underline = attr_underline(p,c); diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mac.h linux/drivers/video/fbcon-mac.h --- v2.1.111/linux/drivers/video/fbcon-mac.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-mac.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Mac variable bpp packed pixels (mac) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE) #define FBCON_HAS_MAC diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c --- v2.1.111/linux/drivers/video/fbcon-mfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-mfb.c Sun Jul 26 14:40:19 1998 @@ -90,7 +90,7 @@ u8 d; dest = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat = p->fontdata+(c&0xff)*p->fontheight; + cdat = p->fontdata+(c&p->charmask)*p->fontheight; bold = attr_bold(p,c); revs = attr_reverse(p,c); underl = attr_underline(p,c); @@ -112,7 +112,8 @@ { u8 *dest, *dest0, *cdat; u_int rows, bold, revs, underl; - u8 c, d; + u8 d; + u16 c; dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; bold = attr_bold(p,*s); @@ -120,7 +121,7 @@ underl = attr_underline(p,*s); while (count--) { - c = *s++; + c = *s++ & p->charmask; dest = dest0++; cdat = p->fontdata+c*p->fontheight; for (rows = p->fontheight; rows--; dest += p->next_line) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mfb.h linux/drivers/video/fbcon-mfb.h --- v2.1.111/linux/drivers/video/fbcon-mfb.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-mfb.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * Monochrome (mfb) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE) #define FBCON_HAS_MFB diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-vga.h linux/drivers/video/fbcon-vga.h --- v2.1.111/linux/drivers/video/fbcon-vga.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon-vga.h Sun Jul 26 14:40:19 1998 @@ -2,8 +2,6 @@ * VGA characters/attributes */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE) #define FBCON_HAS_VGA diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c --- v2.1.111/linux/drivers/video/fbcon.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon.c Sun Jul 26 14:40:19 1998 @@ -25,7 +25,8 @@ * Andreas Schwab * * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) - * Smart redraw scrolling, arbitrary font width support added by + * Smart redraw scrolling, arbitrary font width support, 512char font support + * added by * Jakub Jelinek (jj@ultra.linux.cz) * * @@ -108,7 +109,8 @@ #define LOGO_LINE (LOGO_W/8) struct display fb_display[MAX_NR_CONSOLES]; - +static int logo_lines; +static int logo_shown = -1; /* * Emmanuel: fbcon will now use a hardware cursor if the @@ -396,11 +398,9 @@ int nr_rows, nr_cols; int old_rows, old_cols; unsigned short *save = NULL, *r, *q; - int logo_lines = 0; /* Only if not module */ extern int initmem_freed; struct fbcon_font_desc *font; - if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT) logo = 0; @@ -485,6 +485,10 @@ } p->vrows = p->var.yres_virtual/p->fontheight; conp->vc_can_do_color = p->var.bits_per_pixel != 1; + p->fgshift = 8; + p->bgshift = 12; + p->charmask = 0xff; + conp->vc_hi_font_mask = 0; if (!p->dispsw) { printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not " @@ -512,8 +516,11 @@ update_screen(con); /* So that we set origin correctly */ } - if (logo) + if (logo) { + logo_shown = fg_console; fbcon_show_logo(); /* This is protected above by initmem_freed */ + conp->vc_top = logo_lines; + } } @@ -1025,7 +1032,7 @@ { int unit = conp->vc_num; struct display *p = &fb_display[unit]; - + if (!p->can_soft_blank && console_blanked) return; @@ -1033,9 +1040,9 @@ return; if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && - (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || - ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && - (dx <= p->cursor_x) && (p->cursor_x < dx+width))) + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || + ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && + (dx <= p->cursor_x) && (p->cursor_x < dx+width))) fbcon_cursor(conp, CM_ERASE); /* Split blits that cross physical y_wrap case. @@ -1048,7 +1055,6 @@ fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll); } - static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break) { @@ -1087,6 +1093,13 @@ struct display *p = &fb_display[unit]; struct fb_info *info = p->fb_info; + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + logo_shown = -1; + } p->var.yoffset = p->yscroll*p->fontheight; switch (p->scrollmode) { case SCROLL_YWRAP: @@ -1153,23 +1166,62 @@ static inline int fbcon_get_font(int unit, struct console_font_op *op) { struct display *p = &fb_display[unit]; - char *data = op->data; + u8 *data = op->data; int i, j; - if (p->fontwidth != 8) /* FIXME: Implement for wide fonts */ - return -EINVAL; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + if (p->fontwidth != 8) return -EINVAL; +#endif op->width = p->fontwidth; op->height = p->fontheight; - op->charcount = 256; - for (i = 0; i < 256; i++) - for (j = 0; j < p->fontheight; j++) - data[i*32+j] = p->fontdata[i*p->fontheight+j]; + op->charcount = (p->charmask == 0x1ff) ? 512 : 256; + if (!op->data) return 0; + + if (op->width <= 8) { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < p->fontheight; j++) + *data++ = p->fontdata[i*p->fontheight+j]; + data += 32 - p->fontheight; + } + } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + else if (op->width <= 16) { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < p->fontheight; j++) { + *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8; + *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j]; + } + data += 2 * (32 - p->fontheight); + } + } else if (op->width <= 24) { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < p->fontheight; j++) { + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24; + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16; + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8; + } + data += 3 * (32 - p->fontheight); + } + } else { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < p->fontheight; j++) { + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24; + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16; + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8; + *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j]; + } + data += 4 * (32 - p->fontheight); + } + } +#endif return 0; } #define REFCOUNT(fd) (((int *)(fd))[-1]) #define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FNTSUM(fd) (((int *)(fd))[-4]) static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont) { @@ -1177,6 +1229,7 @@ int resize; int w = op->width; int h = op->height; + int cnt; char *old_data = NULL; if (!fontwidthvalid(p,w)) { @@ -1188,11 +1241,28 @@ resize = (w != p->fontwidth) || (h != p->fontheight); if (p->userfont) old_data = p->fontdata; + if (userfont) + cnt = FNTCHARCNT(data); + else + cnt = 256; p->fontdata = data; if ((p->userfont = userfont)) REFCOUNT(data)++; p->fontwidth = w; p->fontheight = h; + if (p->conp->vc_hi_font_mask && cnt == 256) { + p->conp->vc_hi_font_mask = 0; + p->conp->vc_complement_mask >>= 1; + p->fgshift--; + p->bgshift--; + p->charmask = 0xff; + } else if (!p->conp->vc_hi_font_mask && cnt == 512) { + p->conp->vc_hi_font_mask = 0x100; + p->conp->vc_complement_mask <<= 1; + p->fgshift++; + p->bgshift++; + p->charmask = 0x1ff; + } fbcon_font_widths(p); if (resize) { @@ -1210,7 +1280,7 @@ update_screen( unit ); if (old_data && (--REFCOUNT(old_data) == 0)) - kfree( old_data - 2*sizeof(int) ); + kfree( old_data - 4*sizeof(int) ); return 0; } @@ -1227,6 +1297,8 @@ od = &fb_display[h]; if (od->fontdata == p->fontdata) return 0; /* already the same font... */ + op->width = od->fontwidth; + op->height = od->fontheight; return fbcon_do_set_font(unit, op, od->fontdata, od->userfont); } @@ -1234,21 +1306,94 @@ { int w = op->width; int h = op->height; - int size = (w+7)/8 * h * 256; - int i, j; - u8 *new_data, *data = op->data; + int size = h; + int i, j, k; + u8 *new_data, *data = op->data, c, *p; + u32 d; - if (w != 8 || op->charcount != 256) +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + if (w != 8) + return -EINVAL; +#endif + + if (w > 32 || (op->charcount != 256 && op->charcount != 512)) return -EINVAL; + + if (w > 8) { + if (w <= 16) + size *= 2; + else + size *= 4; + } + size *= op->charcount; - if (!(new_data = kmalloc( 2*sizeof(int)+size, GFP_USER ))) + if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER ))) return -ENOMEM; - new_data += 2*sizeof(int); + new_data += 4*sizeof(int); FNTSIZE(new_data) = size; + FNTCHARCNT(new_data) = op->charcount; REFCOUNT(new_data) = 0; /* usage counter */ - for (i = 0; i < 256; i++) - for (j = 0; j < h; j++) - new_data[i*h+j] = data[i*32+j]; + k = 0; + p = data; + if (w <= 8) { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < h; j++) { + c = *p++; + k += c; + new_data[i*h+j] = c; + } + p += 32 - h; + } + } +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY + else if (w <= 16) { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < h; j++) { + d = (p[0] << 8) | p[1]; + p += 2; + k += d; + ((u16 *)new_data)[i*h+j] = d; + } + p += 2*(32 - h); + } + } else { + for (i = 0; i < op->charcount; i++) { + for (j = 0; j < h; j++) { + if (w <= 24) { + d = (p[0] << 24) | + (p[1] << 16) | + (p[2] << 8); + p += 3; + } else { + d = (p[0] << 24) | + (p[1] << 16) | + (p[2] << 8) | + p[3]; + p += 4; + } + k += d; + ((u32 *)new_data)[i*h+j] = d; + } + if (w <= 24) + p += 3*(32 - h); + else + p += 4*(32 - h); + } + } +#endif + FNTSUM(new_data) = k; + /* Check if the same font is on some other console already */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (fb_display[i].userfont && + fb_display[i].fontdata && + FNTSUM(fb_display[i].fontdata) == k && + FNTSIZE(fb_display[i].fontdata) == size && + !memcmp(fb_display[i].fontdata, new_data, size)) { + kfree(new_data - 4*sizeof(int)); + new_data = fb_display[i].fontdata; + break; + } + } return fbcon_do_set_font(unit, op, new_data, 1); } @@ -1269,7 +1414,6 @@ } op->width = f->width; op->height = f->height; - op->charcount = 256; return fbcon_do_set_font(unit, op, f->data, 0); } @@ -1371,7 +1515,6 @@ fbcon_cursor(conp, CM_DRAW); return 0; } - __initfunc(static int fbcon_show_logo( void )) { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon.h linux/drivers/video/fbcon.h --- v2.1.111/linux/drivers/video/fbcon.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fbcon.h Sun Jul 26 14:40:19 1998 @@ -11,6 +11,7 @@ #ifndef __VIDEO_FBCON_H #define __VIDEO_FBCON_H +#include #include @@ -35,11 +36,21 @@ unsigned int fontwidthmask; /* 1 at (1 << (width - 1)) if width is supported */ }; +#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY + +/* fontwidth w is supported by dispsw */ +#define FONTWIDTH(w) (1 << ((8) - 1)) +/* fontwidths w1-w2 inclusive are supported by dispsw */ +#define FONTWIDTHRANGE(w1,w2) FONTWIDTH(8) + +#else + /* fontwidth w is supported by dispsw */ #define FONTWIDTH(w) (1 << ((w) - 1)) /* fontwidths w1-w2 inclusive are supported by dispsw */ #define FONTWIDTHRANGE(w1,w2) (FONTWIDTH(w2+1) - FONTWIDTH(w1)) +#endif /* * Attribute Decoding @@ -47,11 +58,11 @@ /* Color */ #define attr_fgcol(p,s) \ - (((s) >> ((p)->inverse ? 12 : 8)) & 0x0f) + (((s) >> ((p)->fgshift)) & 0x0f) #define attr_bgcol(p,s) \ - (((s) >> ((p)->inverse ? 8 : 12)) & 0x0f) + (((s) >> ((p)->bgshift)) & 0x0f) #define attr_bgcol_ec(p,conp) \ - (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f) + (((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f) /* Monochrome */ #define attr_bold(p,s) \ diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbgen.c linux/drivers/video/fbgen.c --- v2.1.111/linux/drivers/video/fbgen.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbgen.c Sun Jul 26 14:40:19 1998 @@ -17,45 +17,8 @@ #include - static int currcon = 0; -static struct display disp; - - - /* - * `Generic' versions of the frame buffer device operations - */ - -extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -extern int fbgen_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -extern int fbgen_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -extern int fbgen_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info); - - - /* - * Helper functions - */ - -int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info_gen *info); -void fbgen_set_disp(int con, struct fb_info_gen *info); -void fbgen_install_cmap(int con, struct fb_info_gen *info); -int fbgen_update_var(int con, struct fb_info *info); -int fbgen_switch(int con, struct fb_info *info); -void fbgen_blank(int blank, struct fb_info *info); - /* ---- `Generic' versions of the frame buffer device operations ----------- */ @@ -156,9 +119,10 @@ else if (fb_display[con].cmap.len) /* non default colormap ? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(1<= 0) display = &fb_display[con]; else - display = &disp; /* used during initialization */ + display = info->info.disp; /* used during initialization */ if (con == -1) fbhw->get_par(&par, info); @@ -314,9 +278,11 @@ if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, fbhw->setcolreg, &info->info); - else - fb_set_cmap(fb_default_cmap(1<setcolreg, &info->info); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256; + fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, + fbhw->setcolreg, &info->info); + } } diff -u --recursive --new-file v2.1.111/linux/drivers/video/font_acorn_8x8.c linux/drivers/video/font_acorn_8x8.c --- v2.1.111/linux/drivers/video/font_acorn_8x8.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/font_acorn_8x8.c Sun Jul 26 14:40:19 1998 @@ -1,6 +1,5 @@ /* Acorn-like font definition, with PC graphics characters */ -#include #include "font.h" static unsigned char acorndata_8x8[] = { diff -u --recursive --new-file v2.1.111/linux/drivers/video/fonts.c linux/drivers/video/fonts.c --- v2.1.111/linux/drivers/video/fonts.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/fonts.c Sun Jul 26 14:40:19 1998 @@ -30,7 +30,7 @@ &font_vga_8x16, #endif #ifdef CONFIG_FONT_6x11 -#if !defined(CONFIG_MAC) && !defined(CONFIG_FB_SBUS) +#if defined(CONFIG_MAC) || defined(CONFIG_FB_SBUS) #undef NO_FONTS #endif &font_vga_6x11, @@ -40,7 +40,7 @@ &font_sun_8x16, #endif #ifdef CONFIG_FONT_SUN12x22 -#if !defined(CONFIG_FB_SBUS) && !defined(CONFIG_FBCON_CFB8) +#if defined(CONFIG_FB_SBUS) || defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB32) #undef NO_FONTS #endif &font_sun_12x22, diff -u --recursive --new-file v2.1.111/linux/drivers/video/macfb.c linux/drivers/video/macfb.c --- v2.1.111/linux/drivers/video/macfb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/macfb.c Sun Jul 26 14:40:19 1998 @@ -2,6 +2,7 @@ * We've been given MAC frame buffer info by the booter. Now go set it up */ +#include #include #include #include @@ -42,7 +43,7 @@ {0,0,0}, /* transparency */ 0, /* standard pixel format */ FB_ACTIVATE_NOW, - 274,195, /* 14" monitor - the late Mikael Nykvist's anyway */ + 274,195, /* 14" monitor *Mikael Nykvist's anyway* */ 0, /* The only way to accelerate a mac is .. */ 0L,0L,0L,0L,0L, 0L,0L,0, /* No sync info */ diff -u --recursive --new-file v2.1.111/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c --- v2.1.111/linux/drivers/video/macmodes.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/macmodes.c Sun Jul 26 14:40:19 1998 @@ -9,6 +9,7 @@ */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/macmodes.h linux/drivers/video/macmodes.h --- v2.1.111/linux/drivers/video/macmodes.h Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/macmodes.h Sun Jul 26 14:40:19 1998 @@ -50,3 +50,11 @@ extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, int *cmode); extern int mac_map_monitor_sense(int sense); + + + /* + * Addresses in NVRAM where video mode and pixel size are stored. + */ + +#define NV_VMODE 0x140f +#define NV_CMODE 0x1410 diff -u --recursive --new-file v2.1.111/linux/drivers/video/offb.c linux/drivers/video/offb.c --- v2.1.111/linux/drivers/video/offb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/offb.c Sun Jul 26 14:40:19 1998 @@ -282,6 +282,13 @@ #ifdef CONFIG_FB_CT65550 extern void chips_of_init(struct device_node *dp); #endif /* CONFIG_FB_CT65550 */ +#ifdef CONFIG_FB_CONTROL +extern void control_of_init(struct device_node *dp); +#endif /* CONFIG_FB_CONTROL */ +#ifdef CONFIG_FB_PLATINUM +extern void platinum_of_init(struct device_node *dp); +#endif /* CONFIG_FB_PLATINUM */ + /* * Initialisation @@ -318,6 +325,19 @@ continue; } #endif /* CONFIG_FB_CT65550 */ +#ifdef CONFIG_FB_CONTROL + if(!strcmp(dp->name, "control")) { + control_of_init(dp); + continue; + } +#endif /* CONFIG_FB_CONTROL */ +#ifdef CONFIG_FB_PLATINUM + if (!strncmp(dp->name, "platinum",8)) { + printk("jonh: offb_init sees device node %s\n", dp->name); + platinum_of_init(dp); + continue; + } +#endif /* CONFIG_FB_PLATINUM */ } info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC); diff -u --recursive --new-file v2.1.111/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c --- v2.1.111/linux/drivers/video/platinumfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/platinumfb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,1052 @@ +/* + * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display + * + * Created 12 July 1998 by Dan Jacobowitz + * Copyright (C) 1998 Dan Jacobowitz + * + * Frame buffer structure from: + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * Hardware information from: + * platinum.c: Console support for PowerMac "platinum" display adaptor. + * Copyright (C) 1996 Paul Mackerras + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FB_COMPAT_XPMAC +#include +#endif +#include +#include +#include +#include +#include + +#include "fbcon.h" +#include "fbcon-cfb8.h" +#include "fbcon-cfb16.h" +#include "fbcon-cfb32.h" + +#include "macmodes.h" +#include "platinumfb.h" + +static int currcon = 0; +static int switching = 0; + +struct fb_par_platinum { + int vmode, cmode; + int xres, yres; + int vxres, vyres; + int xoffset, yoffset; +}; + +struct fb_info_platinum { + struct fb_info info; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + struct display disp; + struct fb_par_platinum par; + struct { + __u8 red, green, blue; + } palette[256]; + + volatile struct cmap_regs *cmap_regs; + unsigned long cmap_regs_phys; + + volatile struct platinum_regs *platinum_regs; + unsigned long platinum_regs_phys; + + __u8 *frame_buffer; + __u8 *base_frame_buffer; + unsigned long frame_buffer_phys; + + int sense; + unsigned long total_vram; +}; + +/* + * Exported functions + */ +void platinum_init(void); +void platinum_of_init(struct device_node *dp); + +static int platinum_open(struct fb_info *info, int user); +static int platinum_release(struct fb_info *info, int user); +static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int platinum_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int platinum_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int platinum_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); + +static int read_platinum_sense(struct fb_info_platinum *p); +static inline int platinum_vram_reqd(int video_mode, int color_mode); +static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *params); +static void platinum_set_hardware(struct fb_info_platinum *p); +static void platinum_par_to_all(struct fb_info_platinum *p, int init); +static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var); +static int platinum_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_platinum *par, const struct fb_info *fb_info); + +static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p); +static void platinum_par_to_display(struct fb_par_platinum *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p); +static void platinum_init_display(struct display *disp); +static void platinum_par_to_fix(struct fb_par_platinum *par, struct fb_fix_screeninfo *fix, + struct fb_info_platinum *p); +static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p); + +static struct fb_ops platinumfb_ops = { + platinum_open, + platinum_release, + platinum_get_fix, + platinum_get_var, + platinum_set_var, + platinum_get_cmap, + platinum_set_cmap, + platinum_pan_display, + platinum_ioctl +}; + +static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info); +static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static void do_install_cmap(int con, struct fb_info *info); + +#define FUNCID { printk(KERN_INFO "entering %s\n", __FUNCTION__); } + +__openfirmware + + +static int platinum_open(struct fb_info *info, int user) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int platinum_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_info_platinum *cp = (struct fb_info_platinum *) info; + + *fix = cp->fix; + return 0; +} + +static int platinum_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_platinum *cp = (struct fb_info_platinum *) info; + + *var = cp->var; + return 0; +} + +/* Sets everything according to var */ +static int platinum_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_platinum *p = (struct fb_info_platinum *) info; + struct display *disp; + struct fb_par_platinum par; + int depthchange, err; + +// FUNCID; + disp = (con >= 0) ? &fb_display[con] : &p->disp; + if((err = platinum_var_to_par(var, &par, info))) { + printk (KERN_ERR "Error in platinum_set_var, calling platinum_var_to_par: %d.\n", err); + return err; + } + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { + printk("Not activating, in platinum_set_var.\n"); + platinum_par_to_var(&par, var); + return 0; + } +/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */ +#define DIRTY(x) (p->var.x != var->x) + depthchange = DIRTY(bits_per_pixel); + if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) && + !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) { + platinum_par_to_var(&par, var); + p->var = disp->var = *var; + return 0; + } + printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel); + /* OK, we're getting here at the right times... */ + p->par = par; + platinum_par_to_var(&par, var); + p->var = *var; + platinum_par_to_fix(&par, &p->fix, p); + platinum_par_to_display(&par, disp, &p->fix, p); + p->disp = *disp; + + if(info->changevar && !switching) /* Don't want to do this if just switching consoles. */ + (*info->changevar)(con); + if(con == currcon) + platinum_set_hardware(p); + if(depthchange) + if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) + return err; + if(depthchange || switching) + do_install_cmap(con, info); + return 0; +} + +static int platinum_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + /* + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + */ + +// FUNCID; + if (var->xoffset != 0 || var->yoffset != 0) + return -EINVAL; + return 0; +} + +static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ +// FUNCID; + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, + platinum_getcolreg, info); + if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + } + return 0; +} + +static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct display *disp = &fb_display[con]; + int err; + +// FUNCID; + if (disp->cmap.len == 0) { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + err = fb_alloc_cmap(&disp->cmap, size, 0); + if (err) + return err; + } + + if (con == currcon) + return fb_set_cmap(cmap, &disp->var, kspc, platinum_setcolreg, + info); + fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + return 0; +} + +static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ +// FUNCID; + return -EINVAL; +} + +static int platinum_switch(int con, struct fb_info *info) +{ +// FUNCID; + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, + &fb_display[currcon].var, 1, platinum_getcolreg, + info); + currcon = con; +#if 0 + platinum_var_to_par(&fb_display[currcon].var, &par, info); + platinum_set_par(&par, info); /*STOPPEDHERE - did i define that? */ + do_install_cmap(con, info); +#else + /* I see no reason not to do this. Minus info->changevar(). */ + /* DOH. This makes platinum_set_var compare, you guessed it, */ + /* fb_display[con].var (first param), and fb_display[con].var! */ + /* Perhaps I just fixed that... */ + switching = 1; + platinum_set_var(&fb_display[con].var, con, info); + switching = 0; +#endif + return 0; +} + +static int platinum_updatevar(int con, struct fb_info *info) +{ + return 0; +} + +static void platinum_blank(int blank_mode, struct fb_info *info) +{ +/* + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +/* [danj] I think there's something fishy about those constants... */ +/* + struct fb_info_platinum *p = (struct fb_info_platinum *) info; + int ctrl; + + ctrl = ld_le32(&p->platinum_regs->ctrl.r) | 0x33; + if (blank_mode) + --blank_mode; + if (blank_mode & VESA_VSYNC_SUSPEND) + ctrl &= ~3; + if (blank_mode & VESA_HSYNC_SUSPEND) + ctrl &= ~0x30; + out_le32(&p->platinum_regs->ctrl.r, ctrl); +*/ +/* TODO: Figure out how the heck to powerdown this thing! */ +//FUNCID; + return; +} + +static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info) +{ + struct fb_info_platinum *p = (struct fb_info_platinum *) info; + +// FUNCID; + if (regno > 255 || regno < 0) + return 1; + *red = p->palette[regno].red; + *green = p->palette[regno].green; + *blue = p->palette[regno].blue; + return 0; +} + +static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_platinum *p = (struct fb_info_platinum *) info; + +// FUNCID; + if (regno > 255 || regno < 0) + return 1; + p->palette[regno].red = red; + p->palette[regno].green = green; + p->palette[regno].blue = blue; + + out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */ + out_8(&p->cmap_regs->lut, red); /* send one color channel at */ + out_8(&p->cmap_regs->lut, green); /* a time... */ + out_8(&p->cmap_regs->lut, blue); + + if(regno < 16) { +#if 0 +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; +#endif +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; + /* I think. */ +#endif +#else +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; +#endif +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; + /* I think. */ +#endif +#endif + } + return 0; +} + +static void do_install_cmap(int con, struct fb_info *info) +{ +// FUNCID; + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + platinum_setcolreg, info); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, + platinum_setcolreg, info); + } +} + +#ifdef CONFIG_FB_COMPAT_XPMAC +extern struct vc_mode display_info; +extern struct fb_info *console_fb_info; +#if 0 +extern int (*console_setmode_ptr)(struct vc_mode *, int); +extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int, + struct fb_info *); +int console_setmode(struct vc_mode *, int); +#endif +#endif /* CONFIG_FB_COMPAT_XPMAC */ + +static inline int platinum_vram_reqd(int video_mode, int color_mode) +{ + return vmode_attrs[video_mode - 1].vres + * platinum_reg_init[video_mode-1]->pitch[color_mode]; +} + +#define STORE_D2(a, d) { \ + out_8(&p->cmap_regs->addr, (a+32)); \ + out_8(&p->cmap_regs->d2, (d)); \ +} + +static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_params) +{ +// FUNCID; + STORE_D2(6, 0xc6); + out_8(&p->cmap_regs->addr,3+32); + if (in_8(&p->cmap_regs->d2) == 2) { + STORE_D2(7, clock_params[0]); + STORE_D2(8, clock_params[1]); + STORE_D2(3, 3); + } else { + STORE_D2(4, clock_params[0]); + STORE_D2(5, clock_params[1]); + STORE_D2(3, 2); + } + + __delay(5000); + STORE_D2(9, 0xa6); +} + + +__initfunc(static void init_platinum(struct fb_info_platinum *p)) +{ + struct fb_par_platinum *par = &p->par; + +// FUNCID; + p->sense = read_platinum_sense(p); + printk("Monitor sense value = 0x%x, ", p->sense); + /* Try to pick a video mode out of NVRAM if we have one. */ + par->vmode = nvram_read_byte(NV_VMODE); + if(par->vmode <= 0 || par->vmode > VMODE_MAX || !platinum_reg_init[par->vmode - 1]) + par->vmode = VMODE_CHOOSE; + if(par->vmode == VMODE_CHOOSE) + par->vmode = mac_map_monitor_sense(p->sense); + if(!platinum_reg_init[par->vmode - 1]) + par->vmode = VMODE_640_480_67; + + par->cmode = nvram_read_byte(NV_CMODE); + if(par->cmode < CMODE_8 || par->cmode > CMODE_32) + par->cmode = CMODE_8; + /* + * Reduce the pixel size if we don't have enough VRAM. + */ + while(par->cmode > CMODE_8 && platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) + par->cmode--; + + printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode); + + par->vxres = par->xres = vmode_attrs[par->vmode - 1].hres; + par->vyres = par->yres = vmode_attrs[par->vmode - 1].vres; + par->xoffset = par->yoffset = 0; + + platinum_par_to_all(p, 1); + + if (register_framebuffer(&p->info) < 0) { + kfree(p); + return; + } + platinum_set_hardware(p); + + printk("fb%d: platinum display adapter\n", GET_FB_IDX(p->info.node)); +} + +/* Now how about actually saying, Make it so! */ +/* Some things in here probably don't need to be done each time. */ +static void platinum_set_hardware(struct fb_info_platinum *p) +{ + struct platinum_regvals *init; + int i, dtype, clkmode; + int vmode, cmode; + +// FUNCID; + vmode = p->par.vmode; + cmode = p->par.cmode; + + init = platinum_reg_init[vmode - 1]; + + /* Initialize display timing registers */ + out_be32(&p->platinum_regs->reg[24].r, 7); /* turn display off */ + + for (i = 0; i < 26; ++i) + out_be32(&p->platinum_regs->reg[i+32].r, init->regs[i]); + out_be32(&p->platinum_regs->reg[26+32].r, (p->total_vram == 0x100000 ? + init->offset[cmode] + 4 - cmode : + init->offset[cmode])); + out_be32(&p->platinum_regs->reg[16].r, (unsigned) p->frame_buffer_phys + init->fb_offset); + out_be32(&p->platinum_regs->reg[18].r, init->pitch[cmode]); + out_be32(&p->platinum_regs->reg[19].r, (p->total_vram == 0x100000 ? + init->mode[cmode+1] : + init->mode[cmode])); + out_be32(&p->platinum_regs->reg[20].r, (p->total_vram == 0x100000 ? 0x11 : 0x1011)); + out_be32(&p->platinum_regs->reg[21].r, 0x100); + out_be32(&p->platinum_regs->reg[22].r, 1); + out_be32(&p->platinum_regs->reg[23].r, 1); + out_be32(&p->platinum_regs->reg[26].r, 0xc00); + out_be32(&p->platinum_regs->reg[27].r, 0x235); + /* out_be32(&p->platinum_regs->reg[27].r, 0x2aa); */ + + STORE_D2(0, (p->total_vram == 0x100000 ? + init->dacula_ctrl[cmode] & 0xf : + init->dacula_ctrl[cmode])); + STORE_D2(1, 4); + STORE_D2(2, 0); + /* + * Try to determine whether we have an old or a new DACula. + */ + out_8(&p->cmap_regs->addr, 0x40); + dtype = in_8(&p->cmap_regs->d2); + switch (dtype) { + case 0x3c: + clkmode = 1; + break; + case 0x84: + clkmode = 0; + break; + default: + clkmode = 0; + printk("Unknown DACula type: %x\n", dtype); + } + + set_platinum_clock(p, init->clock_params[clkmode]); + + out_be32(&p->platinum_regs->reg[24].r, 0); /* turn display on */ + +#ifdef CONFIG_FB_COMPAT_XPMAC + /* And let the world know the truth. */ + if (!console_fb_info || console_fb_info == &p->info) { + display_info.height = p->var.yres; + display_info.width = p->var.xres; + display_info.depth = ( (cmode == CMODE_32) ? 32 : + ((cmode == CMODE_16) ? 16 : 8)); + display_info.pitch = p->fix.line_length; + display_info.mode = vmode; + strncpy(display_info.name, "platinum", + sizeof(display_info.name)); + display_info.fb_address = p->frame_buffer_phys + + init->fb_offset + + 0x10; + display_info.cmap_adr_address = p->cmap_regs_phys; + display_info.cmap_data_address = p->cmap_regs_phys + 0x30; + display_info.disp_reg_address = p->platinum_regs_phys; + console_fb_info = &p->info; + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +__initfunc(void platinum_init(void)) +{ +#ifndef CONFIG_FB_OF + struct device_node *dp; + + dp = find_devices("platinum"); + if (dp != 0) + platinum_of_init(dp); +#endif /* CONFIG_FB_OF */ +} + +__initfunc(void platinum_of_init(struct device_node *dp)) +{ + struct fb_info_platinum *p; + unsigned long addr, size; + int i, bank0, bank1, bank2, bank3; +//FUNCID; + if(dp->n_addrs != 2) + panic("expecting 2 address for platinum (got %d)", dp->n_addrs); + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (p == 0) + return; + + /* Map in frame buffer and registers */ + for (i = 0; i < dp->n_addrs; ++i) { + addr = dp->addrs[i].address; + size = dp->addrs[i].size; + if (size >= 0x400000) { + /* frame buffer - map only 4MB */ + p->frame_buffer_phys = addr; + p->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); + p->base_frame_buffer = p->frame_buffer; + } else { + /* registers */ + p->platinum_regs_phys = addr; + p->platinum_regs = ioremap(addr, size); + } + } + p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + + /* Grok total video ram */ + out_be32(&p->platinum_regs->reg[16].r, (unsigned)p->frame_buffer_phys); + out_be32(&p->platinum_regs->reg[20].r, 0x1011); /* select max vram */ + out_be32(&p->platinum_regs->reg[24].r, 0); /* switch in vram */ + eieio(); + p->frame_buffer[0x100000] = 0x34; + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x100000]) : "memory"); + p->frame_buffer[0x200000] = 0x56; + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory"); + p->frame_buffer[0x300000] = 0x78; + asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x300000]) : "memory"); + bank0 = 1; /* builtin 1MB vram, always there */ + bank1 = p->frame_buffer[0x100000] == 0x34; + bank2 = p->frame_buffer[0x200000] == 0x56; + bank3 = p->frame_buffer[0x300000] == 0x78; + p->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; + printk("Total VRAM = %dMB\n", p->total_vram / 1024 / 1024); + +// p->frame_buffer = p->base_frame_buffer +// + platinum_reg_init[p->par.vmode-1]->fb_offset; + +#ifdef CONFIG_FB_COMPAT_XPMAC +#if 0 + console_set_cmap_ptr = platinum_set_cmap; + console_setmode_ptr = platinum_console_setmode; +#endif +#endif /* CONFIG_FB_COMPAT_XPMAC */ + + init_platinum(p); +} + +/* + * Get the monitor sense value. + * Note that this can be called before calibrate_delay, + * so we can't use udelay. + */ +static int read_platinum_sense(struct fb_info_platinum *p) +{ + int sense; + + out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */ + __delay(2000); + sense = (~in_be32(&p->platinum_regs->reg[23].r) & 7) << 8; + + /* drive each sense line low in turn and collect the other 2 */ + out_be32(&p->platinum_regs->reg[23].r, 3); /* drive A low */ + __delay(2000); + sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 3) << 4; + out_be32(&p->platinum_regs->reg[23].r, 5); /* drive B low */ + __delay(2000); + sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 4) << 1; + sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 1) << 2; + out_be32(&p->platinum_regs->reg[23].r, 6); /* drive C low */ + __delay(2000); + sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 6) >> 1; + + out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */ + + return sense; +} + +#if 0 +/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ +static int platinum_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_platinum *par, const struct fb_info *fb_info) +{ + int xres = var->xres; + int yres = var->yres; + int bpp = var->bits_per_pixel; + + struct platinum_regvals *init; + struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info; + +// FUNCID; + /* + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + * Suggestion: Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + */ + /* swiped by jonh from atyfb.c */ + if (xres <= 512 && yres <= 384) + par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */ + else if (xres <= 640 && yres <= 480) + par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ + else if (xres <= 640 && yres <= 870) + par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ + else if (xres <= 768 && yres <= 576) + par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */ + else if (xres <= 800 && yres <= 600) + par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ + else if (xres <= 832 && yres <= 624) + par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */ + else if (xres <= 1024 && yres <= 768) + par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ + else if (xres <= 1152 && yres <= 870) + par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ + else if (xres <= 1280 && yres <= 960) + par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ + else if (xres <= 1280 && yres <= 1024) + par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ + else { + printk(KERN_ERR "Bad resolution in platinum_var_to_par()!\n"); + return -EINVAL; + } + xres = vmode_attrs[par->vmode - 1].hres; + yres = vmode_attrs[par->vmode - 1].vres; + +/* + if (var->xres_virtual <= xres) + par->vxres = xres; + else + par->vxres = (var->xres_virtual+7) & ~7; + if (var->yres_virtual <= yres) + par->vyres = yres; + else + par->vyres = var->yres_virtual; + + par->xoffset = (var->xoffset+7) & ~7; + par->yoffset = var->yoffset; + if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres) + return -EINVAL; +*/ + + /* I'm too chicken to think about virtual */ + /* resolutions just yet. Bok bok. */ + + /* And I'm too chicken to even figure out what they are. Awk awk. [danj] */ + if (var->xres_virtual > xres || var->yres_virtual > yres + || var->xoffset != 0 || var->yoffset != 0) { + printk(KERN_ERR "Bad virtual resolution in platinum_var_to_par()!\n"); + return -EINVAL; + } + + par->xres = xres; + par->yres = yres; + par->vxres = xres; + par->vyres = yres; + par->xoffset = 0; + par->yoffset = 0; + + if (bpp <= 8) + par->cmode = CMODE_8; + else if (bpp <= 16) + par->cmode = CMODE_16; + else if (bpp <= 32) + par->cmode = CMODE_32; + else { + printk(KERN_ERR "Bad color mode in platinum_var_to_par()!\n"); + return -EINVAL; + } + + if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) { + printk(KERN_ERR "Bad vram size requested in platinum_var_to_par()!\n"); + return -EINVAL; + } + /* Check if we know about the wanted video mode */ + init = platinum_reg_init[par->vmode-1]; + if (init == NULL) { + /* I'm not sure if platinum has any specific requirements -- */ + /* if we have a regvals struct, we're good to go? */ + printk(KERN_ERR "platinum_reg_init failed platinum_var_to_par()!\n"); + return -EINVAL; + } + + return 0; +} +#else +/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ +static int platinum_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_platinum *par, const struct fb_info *fb_info) +{ + struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info; + +// FUNCID; + if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) + return -EINVAL; + par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres; + par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres; + par->xoffset = par->yoffset = 0; + + if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) + return -EINVAL; + + /* Check if we know about the wanted video mode */ + if(!platinum_reg_init[par->vmode-1]) { + /* I'm not sure if platinum has any specific requirements -- */ + /* if we have a regvals struct, we're good to go? */ + return -EINVAL; + } + return 0; +} +#endif + +#if 0 +static void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var) +{ + memset(var, 0, sizeof(*var)); + var->xres = vmode_attrs[par->vmode - 1].hres; + var->yres = vmode_attrs[par->vmode - 1].vres; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; /* For now. */ + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + var->grayscale = 0; + + if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) { + printk(KERN_ERR "Bad color mode in platinum_par_to_var()!\n"); + par->cmode = CMODE_8; + } + switch(par->cmode) { + case CMODE_8: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CMODE_16: /* RGB 555 */ + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CMODE_32: /* RGB 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* these are total guesses, copied right out of atyfb.c */ + var->left_margin = var->right_margin = 64; + var->upper_margin = var->lower_margin = 32; + var->hsync_len = 8; + var->vsync_len = 8; + var->sync = 0; + +#if 1 +/* jonh's pixclocks...*/ + /* no long long support in the kernel :-( */ + /* this splittig trick will work if xres > 232 */ + var->pixclock = 1000000000/ + (var->left_margin+var->xres+var->right_margin+var->hsync_len); + var->pixclock *= 1000; + var->pixclock /= vmode_attrs[par->vmode-1].vfreq* + (var->upper_margin+var->yres+var->lower_margin+var->vsync_len); +#else +/* danj's */ + /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */ + /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */ + /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */ + var->pixclock = 255990 * platinum_reg_init[par->vmode-1]->clock_params[0]; + var->pixclock /= platinum_reg_init[par->vmode-1]->clock_params[1]; + var->pixclock >>= platinum_reg_init[par->vmode-1]->clock_params[2]; +#endif +} +#else +static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var) +{ +// FUNCID; + mac_vmode_to_var(par->vmode, par->cmode, var); +} +#endif + +static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p) +{ +// FUNCID; + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, "platinum"); + fix->mmio_start = (char *)p->platinum_regs_phys; + fix->mmio_len = 0x1000; + fix->type = FB_TYPE_PACKED_PIXELS; + + fix->type_aux = 0; + fix->ywrapstep = 0; + fix->xpanstep = 0; + fix->ypanstep = 0; +} + +/* Fix must already be inited ^^^^^^^ */ +static void platinum_par_to_fix(struct fb_par_platinum *par, + struct fb_fix_screeninfo *fix, + struct fb_info_platinum *p) +{ +// FUNCID; + fix->smem_start = (void *)(p->frame_buffer_phys); + fix->smem_len = platinum_vram_reqd(par->vmode, par->cmode); + /* Hmm, jonh used total_vram here. */ + fix->visual = (par->cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; +// fix->line_length = par->vxres << par->cmode; + fix->line_length = platinum_reg_init[par->vmode-1]->pitch[par->cmode]; + +} + +static void platinum_init_display(struct display *disp) +{ + memset(disp, 0, sizeof(*disp)); + disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS; + disp->can_soft_blank = 1; + disp->scrollmode = SCROLL_YREDRAW; +#if 0 + disp->type_aux = fix->type_aux; + disp->cmap.red = NULL; /* ??? danj */ + disp->cmap.green = NULL; + disp->cmap.blue = NULL; + disp->cmap.transp = NULL; + /* Yeah, I realize I just set 0 = 0. */ +#endif +} + +static void platinum_par_to_display(struct fb_par_platinum *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p) +{ +// FUNCID; + disp->var = p->var; + disp->screen_base = (char *) p->frame_buffer + + platinum_reg_init[par->vmode-1]->fb_offset + + ((par->yres % 16) / 2) * fix->line_length + 0x10; + disp->visual = fix->visual; + disp->line_length = fix->line_length; + + if(disp->scrollmode != SCROLL_YREDRAW) { + printk(KERN_ERR "Scroll mode not YREDRAW in platinum_par_to_display!!\n"); + disp->scrollmode = SCROLL_YREDRAW; + } + + switch(par->cmode) { +#ifdef FBCON_HAS_CFB8 + case CMODE_8: + disp->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case CMODE_16: + disp->dispsw = &fbcon_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case CMODE_32: + disp->dispsw = &fbcon_cfb32; + break; +#endif + default: + disp->dispsw = NULL; + break; + } +} + +static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p) +{ +// FUNCID; + strcpy(info->modename, p->fix.id); + info->node = -1; /* ??? danj */ + info->fbops = &platinumfb_ops; + info->disp = &p->disp; + info->fontname[0] = 0; + info->changevar = NULL; + info->switch_con = &platinum_switch; + info->updatevar = &platinum_updatevar; + info->blank = &platinum_blank; +} + +/* danj: Oh, I HOPE I didn't miss anything major in here... */ +static void platinum_par_to_all(struct fb_info_platinum *p, int init) +{ +// FUNCID; + if(init) { + platinum_init_fix(&p->fix, p); + } + platinum_par_to_fix(&p->par, &p->fix, p); + + platinum_par_to_var(&p->par, &p->var); + + if(init) { + platinum_init_display(&p->disp); + } + platinum_par_to_display(&p->par, &p->disp, &p->fix, p); + + if(init) { + platinum_init_info(&p->info, p); + } +} + +#if 0 +__initfunc(void platinum_setup(char *options, int *ints)) +{ + /* Parse user speficied options (`video=platinumfb:') */ + FUNCID; +} + +#endif + diff -u --recursive --new-file v2.1.111/linux/drivers/video/platinumfb.h linux/drivers/video/platinumfb.h --- v2.1.111/linux/drivers/video/platinumfb.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/platinumfb.h Sun Jul 26 14:40:19 1998 @@ -0,0 +1,399 @@ +/* + * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the + * Platinum on-board video in PowerMac 7200s (and some clones based + * on the same motherboard.) + * + * Created 09 Feb 1998 by Jon Howell + * + * Copyright (C) 1998 Jon Howell + * + * based on drivers/macintosh/platinum.c: Console support + * for PowerMac "platinum" display adaptor. + * Copyright (C) 1996 Paul Mackerras and Mark Abene. + * + * based on skeletonfb.c: + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * 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. + */ + +/* + * Structure of the registers for the DACula colormap device. + */ +struct cmap_regs { + unsigned char addr; + char pad1[15]; + unsigned char d1; + char pad2[15]; + unsigned char d2; + char pad3[15]; + unsigned char lut; + char pad4[15]; +}; + +/* + * Structure of the registers for the "platinum" display adaptor". + */ +struct preg { /* padded register */ + unsigned r; /* notice this is 32 bits. */ + char pad[12]; +}; + +struct platinum_regs { + struct preg reg[128]; +}; + +/* + * Register initialization tables for the platinum display. + * + * It seems that there are two different types of platinum display + * out there. Older ones use the values in clocksel[1], for which + * the formula for the clock frequency seems to be + * F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5)) + * Newer ones use the values in clocksel[0], for which the formula + * seems to be + * F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5)) + */ +struct platinum_regvals { + int fb_offset; + int pitch[3]; + unsigned regs[26]; + unsigned char offset[3]; + unsigned char mode[3]; + unsigned char dacula_ctrl[3]; + unsigned char clock_params[2][2]; +}; + +#define DIV2 0x20 +#define DIV4 0x40 +#define DIV8 0x60 +#define DIV16 0x80 + +/* 1280x1024, 75Hz (20) */ +static struct platinum_regvals platinum_reg_init_20 = { + 0x5c00, + { 1312, 2592, 2592 }, + { 0xffc, 4, 0, 0, 0, 0, 0x428, 0, + 0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d, + 0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50, + 0x850, 0x851 }, { 0x58, 0x5d, 0x5d }, + { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 }, + {{ 45, 3 }, { 66, 7 }} +}; + +/* 1280x960, 75Hz (19) */ +static struct platinum_regvals platinum_reg_init_19 = { + 0x5c00, + { 1312, 2592, 2592 }, + { 0xffc, 4, 0, 0, 0, 0, 0x428, 0, + 0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d, + 0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c, + 0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b }, + { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 }, + {{ 42, 3 }, { 44, 5 }} +}; + +/* 1152x870, 75Hz (18) */ +static struct platinum_regvals platinum_reg_init_18 = { + 0x11b0, + { 1184, 2336, 4640 }, + { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0, + 0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53, + 0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52, + 0x71e, 0x722 }, { 0x74, 0x7c, 0x81 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV2 }, { 42, 6 }} +}; + +/* 1024x768, 75Hz (17) */ +static struct platinum_regvals platinum_reg_init_17 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b, + 0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40, + 0x640, 0x644 }, { 0x72, 0x7a, 0x7f }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV2 }, { 67, 12 }} +}; + +/* 1024x768, 75Hz (16) */ +static struct platinum_regvals platinum_reg_init_16 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47, + 0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c, + 0x63c, 0x63d }, { 0x74, 0x7c, 0x81 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 20, 0 + DIV2 }, { 11, 2 }} +}; + +/* 1024x768, 70Hz (15) */ +static struct platinum_regvals platinum_reg_init_15 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b, + 0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44, + 0x644, 0x646 }, { 0x78, 0x80, 0x85 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 19, 0 + DIV2 }, { 110, 21 }} +}; + +/* 1024x768, 60Hz (14) */ +static struct platinum_regvals platinum_reg_init_14 = { + 0x10b0, + { 1056, 2080, 4128 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b, + 0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44, + 0x644, 0x646 }, { 0x80, 0x88, 0x8d }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }} +}; + +/* 832x624, 75Hz (13) */ +static struct platinum_regvals platinum_reg_init_13 = { + 0x70, + { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */ + { 0xff0, 4, 0, 0, 0, 0, 0x299, 0, + 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37, + 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52, + 0x532, 0x533 }, { 0x7c, 0x84, 0x89 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }} +}; + +/* 800x600, 75Hz (12) */ +static struct platinum_regvals platinum_reg_init_12 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39, + 0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e, + 0x4de, 0x4df }, { 0x64, 0x6c, 0x71 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }} +}; + +/* 800x600, 72Hz (11) */ +static struct platinum_regvals platinum_reg_init_11 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d, + 0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38, + 0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }} +}; + +/* 800x600, 60Hz (10) */ +static struct platinum_regvals platinum_reg_init_10 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d, + 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34, + 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }} +}; + +/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */ +static struct platinum_regvals platinum_reg_init_9 = { + 0x1010, + { 832, 1632, 3232 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d, + 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34, + 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }} +}; + +/* 768x576, 50Hz Interlaced-PAL (8) */ +static struct platinum_regvals platinum_reg_init_8 = { + 0x1010, + { 800, 1568, 3104 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36, + 0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27, + 0x267, 0x26b }, { 0x39, 0x41, 0x46 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }} +}; + +/* 640x870, 75Hz Portrait (7) */ +static struct platinum_regvals platinum_reg_init_7 = { + 0xb10, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f, + 0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58, + 0x724, 0x72a }, { 0x3c, 0x44, 0x49 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }} +}; + +/* 640x480, 67Hz (6) */ +static struct platinum_regvals platinum_reg_init_6 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x209, 0, + 0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37, + 0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52, + 0x412, 0x416 }, { 0x3c, 0x44, 0x49 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }} +}; + +/* 640x480, 60Hz (5) */ +static struct platinum_regvals platinum_reg_init_5 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e, + 0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44, + 0x404, 0x408 }, { 0x34, 0x3c, 0x41 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }} +}; + +/* 640x480, 60Hz Interlaced-NTSC (4) */ +static struct platinum_regvals platinum_reg_init_4 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30, + 0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23, + 0x203, 0x206 }, { 0x29, 0x31, 0x36 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} +}; + +/* 640x480, 50Hz Interlaced-PAL (3) */ +static struct platinum_regvals platinum_reg_init_3 = { + 0x1010, + { 672, 1312, 2592 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36, + 0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57, + 0x237, 0x26b }, { 0x59, 0x61, 0x66 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }} +}; + +/* 512x384, 60Hz (2) */ +static struct platinum_regvals platinum_reg_init_2 = { + 0x1010, + { 544, 1056, 2080 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f, + 0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a, + 0x32a, 0x32b }, { 0x5a, 0x62, 0x67 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }} +}; + +/* 512x384, 60Hz Interlaced-NTSC (1) */ +static struct platinum_regvals platinum_reg_init_1 = { + 0x1010, + { 544, 1056, 2080 }, + { 0xff0, 4, 0, 0, 0, 0, 0x320, 0, + 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30, + 0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53, + 0x1d3, 0x206 }, { 0x49, 0x51, 0x56 }, + { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, + {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} +}; + +#define VMODE_MAX 20 + +static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = { + &platinum_reg_init_1, + &platinum_reg_init_2, + &platinum_reg_init_3, + &platinum_reg_init_4, + &platinum_reg_init_5, + &platinum_reg_init_6, + &platinum_reg_init_7, + &platinum_reg_init_8, + &platinum_reg_init_9, + &platinum_reg_init_10, + &platinum_reg_init_11, + &platinum_reg_init_12, + &platinum_reg_init_13, + &platinum_reg_init_14, + &platinum_reg_init_15, + &platinum_reg_init_16, + &platinum_reg_init_17, + &platinum_reg_init_18, + &platinum_reg_init_19, + &platinum_reg_init_20 +}; + +struct vmode_attr { + int hres; + int vres; + int vfreq; + int interlaced; +}; + +struct vmode_attr vmode_attrs[VMODE_MAX] = { + {512, 384, 60, 1}, + {512, 384, 60}, + {640, 480, 50, 1}, + {640, 480, 60, 1}, + {640, 480, 60}, + {640, 480, 67}, + {640, 870, 75}, + {768, 576, 50, 1}, + {800, 600, 56}, + {800, 600, 60}, + {800, 600, 72}, + {800, 600, 75}, + {832, 624, 75}, + {1024, 768, 60}, + {1024, 768, 72}, + {1024, 768, 75}, + {1024, 768, 75}, + {1152, 870, 75}, + {1280, 960, 75}, + {1280, 1024, 75} +}; + +/* this stuff should probably be shared by the various vmode-based */ +/* drivers in a vmode.h header. */ + +#define VMODE_NVRAM 0 /* use value stored in nvram */ +#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */ +#define VMODE_512_384_60 2 /* 512x384, 60Hz */ +#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */ +#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */ +#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */ +#define VMODE_640_480_67 6 /* 640x480, 67Hz */ +#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */ +#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */ +#define VMODE_800_600_56 9 /* 800x600, 56Hz */ +#define VMODE_800_600_60 10 /* 800x600, 60Hz */ +#define VMODE_800_600_72 11 /* 800x600, 72Hz */ +#define VMODE_800_600_75 12 /* 800x600, 75Hz */ +#define VMODE_832_624_75 13 /* 832x624, 75Hz */ +#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */ +#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */ +#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */ +#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */ +#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ +#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ +#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ +#define VMODE_MAX 20 +#define VMODE_CHOOSE 99 /* choose based on monitor sense */ + +#define CMODE_NVRAM -1 /* use value stored in nvram */ +#define CMODE_8 0 /* 8 bits/pixel */ +#define CMODE_16 1 /* 16 (actually 15) bits/pixel */ +#define CMODE_32 2 /* 32 (actually 24) bits/pixel */ diff -u --recursive --new-file v2.1.111/linux/drivers/video/prom.uni linux/drivers/video/prom.uni --- v2.1.111/linux/drivers/video/prom.uni Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/prom.uni Sun Jul 26 14:40:19 1998 @@ -0,0 +1,11 @@ +# +# Unicode mapping table for font in Sun PROM +# +# +0x20-0x7e idem +0xa0-0xff idem +# +0x7c U+2502 +0x2d U+2500 +0x2b U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c +0xa4 U+fffd diff -u --recursive --new-file v2.1.111/linux/drivers/video/promcon.c linux/drivers/video/promcon.c --- v2.1.111/linux/drivers/video/promcon.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/promcon.c Sun Jul 26 14:40:19 1998 @@ -1,10 +1,11 @@ -/* $Id: promcon.c,v 1.6 1998/07/19 12:49:26 mj Exp $ +/* $Id: promcon.c,v 1.10 1998/07/24 15:31:53 jj Exp $ * Console driver utilizing PROM sun terminal emulation * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ +#include #include #include #include @@ -15,15 +16,23 @@ #include #include #include +#include #include #include +#include +#include #include +#include static short pw = 80 - 1, ph = 34 - 1; static short px, py; +static unsigned long promcon_uni_pagedir[2]; -#define PROMCON_COLOR 1 +extern u8 promfont_unicount[]; +extern u16 promfont_unitable[]; + +#define PROMCON_COLOR 0 #if PROMCON_COLOR #define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1) @@ -119,12 +128,70 @@ return display_desc; } +__initfunc(static void +promcon_init_unimap(struct vc_data *conp)) +{ + mm_segment_t old_fs = get_fs(); + struct unipair *p, *p1; + u16 *q; + int i, j, k; + + p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL); + if (!p) return; + + q = promfont_unitable; + p1 = p; + k = 0; + for (i = 0; i < 256; i++) + for (j = promfont_unicount[i]; j; j--) { + p1->unicode = *q++; + p1->fontpos = i; + p1++; + k++; + } + set_fs(KERNEL_DS); + con_clear_unimap(conp->vc_num, NULL); + con_set_unimap(conp->vc_num, k, p); + con_protect_unimap(conp->vc_num, 1); + set_fs(old_fs); + kfree(p); +} + static void promcon_init(struct vc_data *conp, int init) { + unsigned long p; + conp->vc_can_do_color = PROMCON_COLOR; - conp->vc_cols = pw + 1; - conp->vc_rows = ph + 1; + if (init) { + conp->vc_cols = pw + 1; + conp->vc_rows = ph + 1; + } + p = *conp->vc_uni_pagedir_loc; + if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir || + !--conp->vc_uni_pagedir_loc[1]) + con_free_unimap(conp->vc_num); + conp->vc_uni_pagedir_loc = promcon_uni_pagedir; + promcon_uni_pagedir[1]++; + if (!promcon_uni_pagedir[0] && p) { + promcon_init_unimap(conp); + } + if (!init) { + if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) + vc_resize_con(ph + 1, pw + 1, conp->vc_num); + else if (conp->vc_num == fg_console) + update_screen(fg_console); + } +} + +static void +promcon_deinit(struct vc_data *conp) +{ + /* When closing the last console, reset video origin */ + if (!--promcon_uni_pagedir[1]) + con_free_unimap(conp->vc_num); + conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir; + con_set_default_unimap(conp->vc_num); } static int @@ -482,6 +549,13 @@ return 0; } +#if !(PROMCON_COLOR) +static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +{ + return (_reverse) ? 0xf : 0x7; +} +#endif + /* * The console 'switch' structure for the VGA based console */ @@ -496,7 +570,7 @@ struct consw prom_con = { con_startup: promcon_startup, con_init: promcon_init, - con_deinit: DUMMY, + con_deinit: promcon_deinit, con_clear: promcon_clear, con_putc: promcon_putc, con_putcs: promcon_putcs, @@ -510,6 +584,18 @@ con_scrolldelta: DUMMY, con_set_origin: NULL, con_save_screen: NULL, +#if PROMCON_COLOR con_build_attr: NULL, +#else + con_build_attr: promcon_build_attr, +#endif con_invert_region: NULL, }; + +__initfunc(void prom_con_init(void)) +{ + if (conswitchp == &dummy_con) + take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1); + else if (conswitchp == &prom_con) + promcon_init_unimap(vc_cons[fg_console].d); +} diff -u --recursive --new-file v2.1.111/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c --- v2.1.111/linux/drivers/video/retz3fb.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/video/retz3fb.c Sun Jul 26 14:40:19 1998 @@ -21,6 +21,7 @@ */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c --- v2.1.111/linux/drivers/video/sbusfb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/sbusfb.c Sun Jul 26 14:40:19 1998 @@ -277,7 +277,7 @@ rects [13] = fb->var.yres_virtual - fb->y_margin; rects [14] = fb->var.xres_virtual - fb->x_margin; rects [15] = fb->var.yres_virtual; - (*fb->fill)(fb, s, 4, rects); + (*fb->fill)(fb, p, s, 4, rects); } else { unsigned char *fb_base = p->screen_base, *q; int skip_bytes = fb->y_margin * fb->var.xres_virtual; @@ -298,13 +298,13 @@ memset (q, ~0, size); } else { fb_base -= (skip_bytes + fb->x_margin); - memset (fb_base, attr_bg_col(s), skip_bytes - fb->x_margin); - memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bg_col(s), skip_bytes - fb->x_margin); + memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); + memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin); incr = fb->var.xres_virtual; size = fb->x_margin * 2; for (q = fb_base + skip_bytes - fb->x_margin, h = 0; h <= he; q += incr, h++) - memset (q, attr_bg_col(s), size); + memset (q, attr_bgcol(p,s), size); } } if (fb->switch_from_graph) @@ -942,6 +942,7 @@ type->fb_height = h = prom_getintdefault(node, "height", 900); type->fb_width = w = prom_getintdefault(node, "width", 1152); +sizechange: type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8; linebytes = prom_getintdefault(node, "linebytes", w * depth / 8); type->fb_size = PAGE_ALIGN((linebytes) * h); @@ -990,7 +991,7 @@ fb->cursor.hwsize.fbx = 32; fb->cursor.hwsize.fby = 32; - if (depth > 1) + if (depth > 1 && !fb->color_map) fb->color_map = kmalloc(256 * 3, GFP_ATOMIC); switch(fbtype) { @@ -1028,6 +1029,9 @@ kfree(fb); return; } + + if (p == SBUSFBINIT_SIZECHANGE) + goto sizechange; disp->dispsw = &fb->dispsw; if (fb->setcursor) diff -u --recursive --new-file v2.1.111/linux/drivers/video/sbusfb.h linux/drivers/video/sbusfb.h --- v2.1.111/linux/drivers/video/sbusfb.h Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/sbusfb.h Sun Jul 26 14:40:19 1998 @@ -24,6 +24,18 @@ struct cg6_tec *tec; volatile u32 *fhc; }; +struct fb_info_bwtwo { + struct bw2_regs *regs; +}; +struct fb_info_cgthree { + struct cg3_regs *regs; +}; +struct fb_info_tcx { + struct bt_regs *bt; + struct tcx_thc *thc; + struct tcx_tec *tec; + u32 *cplane; +}; struct cg_cursor { short enable; /* cursor is enabled */ @@ -56,6 +68,9 @@ union { struct fb_info_creator ffb; struct fb_info_cgsix cg6; + struct fb_info_bwtwo bw2; + struct fb_info_cgthree cg3; + struct fb_info_tcx tcx; } s; unsigned char *color_map; struct cg_cursor cursor; @@ -81,7 +96,7 @@ void (*unblank)(struct fb_info_sbusfb *); void (*margins)(struct fb_info_sbusfb *, struct display *, int, int); void (*reset)(struct fb_info_sbusfb *); - void (*fill)(struct fb_info_sbusfb *, int, int, unsigned short *); + void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *); void (*switch_from_graph)(struct fb_info_sbusfb *); void (*restore_palette)(struct fb_info_sbusfb *); }; @@ -94,13 +109,8 @@ extern char *bwtwofb_init(struct fb_info_sbusfb *); extern char *cgfourteenfb_init(struct fb_info_sbusfb *); -#define attr_fg_col(s) \ - (((s) >> 8) & 0x0f) -#define attr_bg_col(s) \ - (((s) >> 12) & 0x0f) -#define attr_bg_col_ec(conp) \ - (((conp)->vc_video_erase_char >> 12) & 0x0f) - #define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info)) #define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info)) #define CM(i, j) [3*(i)+(j)] + +#define SBUSFBINIT_SIZECHANGE ((char *)-1) diff -u --recursive --new-file v2.1.111/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c --- v2.1.111/linux/drivers/video/skeletonfb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/skeletonfb.c Sun Jul 26 14:40:19 1998 @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/tcxfb.c linux/drivers/video/tcxfb.c --- v2.1.111/linux/drivers/video/tcxfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/tcxfb.c Sun Jul 26 14:40:19 1998 @@ -0,0 +1,290 @@ +/* $Id: tcxfb.c,v 1.1 1998/07/21 14:50:44 jj Exp $ + * tcxfb.c: TCX 24/8bit frame buffer driver + * + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sbusfb.h" +#include + +#include "fbcon-cfb8.h" + +/* THC definitions */ +#define TCX_THC_MISC_REV_SHIFT 16 +#define TCX_THC_MISC_REV_MASK 15 +#define TCX_THC_MISC_VSYNC_DIS (1 << 25) +#define TCX_THC_MISC_HSYNC_DIS (1 << 24) +#define TCX_THC_MISC_RESET (1 << 12) +#define TCX_THC_MISC_VIDEO (1 << 10) +#define TCX_THC_MISC_SYNC (1 << 9) +#define TCX_THC_MISC_VSYNC (1 << 8) +#define TCX_THC_MISC_SYNC_ENAB (1 << 7) +#define TCX_THC_MISC_CURS_RES (1 << 6) +#define TCX_THC_MISC_INT_ENAB (1 << 5) +#define TCX_THC_MISC_INT (1 << 4) +#define TCX_THC_MISC_INIT 0x9f +#define TCX_THC_REV_REV_SHIFT 20 +#define TCX_THC_REV_REV_MASK 15 +#define TCX_THC_REV_MINREV_SHIFT 28 +#define TCX_THC_REV_MINREV_MASK 15 + +/* The contents are unknown */ +struct tcx_tec { + volatile u32 tec_matrix; + volatile u32 tec_clip; + volatile u32 tec_vdc; +}; + +struct tcx_thc { + volatile u32 thc_rev; + u32 thc_pad0[511]; + volatile u32 thc_hs; /* hsync timing */ + volatile u32 thc_hsdvs; + volatile u32 thc_hd; + volatile u32 thc_vs; /* vsync timing */ + volatile u32 thc_vd; + volatile u32 thc_refresh; + volatile u32 thc_misc; + u32 thc_pad1[56]; + volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + volatile u32 thc_cursmask[32]; /* cursor mask bits */ + volatile u32 thc_cursbits[32]; /* what to show where mask enabled */ +}; + +static struct sbus_mmap_map tcx_mmap_map[] = { + { TCX_RAM8BIT, 0, SBUS_MMAP_FBSIZE(1) }, + { TCX_RAM24BIT, 0, SBUS_MMAP_FBSIZE(4) }, + { TCX_UNK3, 0, SBUS_MMAP_FBSIZE(8) }, + { TCX_UNK4, 0, SBUS_MMAP_FBSIZE(8) }, + { TCX_CONTROLPLANE, 0, SBUS_MMAP_FBSIZE(4) }, + { TCX_UNK6, 0, SBUS_MMAP_FBSIZE(8) }, + { TCX_UNK7, 0, SBUS_MMAP_FBSIZE(8) }, + { TCX_TEC, 0, PAGE_SIZE }, + { TCX_BTREGS, 0, PAGE_SIZE }, + { TCX_THC, 0, PAGE_SIZE }, + { TCX_DHC, 0, PAGE_SIZE }, + { TCX_ALT, 0, PAGE_SIZE }, + { TCX_UNK2, 0, 0x20000 }, + { 0, 0, 0 } +}; + +static void tcx_set_control_plane (struct fb_info_sbusfb *fb) +{ + u32 *p, *pend; + + p = fb->s.tcx.cplane; + if (!p) return; + for (pend = p + fb->type.fb_size; p < pend; p++) + *p &= 0xffffff; +} + +static void tcx_switch_from_graph (struct fb_info_sbusfb *fb) +{ + /* Reset control plane to 8bit mode if necessary */ + if (fb->open && fb->mmaped) + tcx_set_control_plane (fb); +} + +static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +{ + struct bt_regs *bt = fb->s.tcx.bt; + int i; + + bt->addr = index << 24; + for (i = index; count--; i++){ + bt->color_map = fb->color_map CM(i,0) << 24; + bt->color_map = fb->color_map CM(i,1) << 24; + bt->color_map = fb->color_map CM(i,2) << 24; + } +} + +static void tcx_restore_palette (struct fb_info_sbusfb *fb) +{ + struct bt_regs *bt = fb->s.tcx.bt; + + bt->addr = 0; + bt->color_map = 0xffffffff; + bt->color_map = 0xffffffff; + bt->color_map = 0xffffffff; +} + +static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue) +{ + struct bt_regs *bt = fb->s.tcx.bt; + + /* Note the 2 << 24 is different from cg6's 1 << 24 */ + bt->addr = 2 << 24; + bt->cursor = red[0] << 24; + bt->cursor = green[0] << 24; + bt->cursor = blue[0] << 24; + bt->addr = 3 << 24; + bt->cursor = red[1] << 24; + bt->cursor = green[1] << 24; + bt->cursor = blue[1] << 24; + bt->addr = 0; +} + +/* Set cursor shape */ +static void tcx_setcurshape (struct fb_info_sbusfb *fb) +{ + struct tcx_thc *thc = fb->s.tcx.thc; + int i; + + for (i = 0; i < 32; i++){ + thc->thc_cursmask [i] = fb->cursor.bits[0][i]; + thc->thc_cursbits [i] = fb->cursor.bits[1][i]; + } +} + +/* Load cursor information */ +static void tcx_setcursor (struct fb_info_sbusfb *fb) +{ + unsigned int v; + struct cg_cursor *c = &fb->cursor; + + if (c->enable) + v = ((c->cpos.fbx - c->chot.fbx) << 16) + |((c->cpos.fby - c->chot.fby) & 0xffff); + else + /* Magic constant to turn off the cursor */ + v = ((65536-32) << 16) | (65536-32); + fb->s.tcx.thc->thc_cursxy = v; +} + +static void tcx_blank (struct fb_info_sbusfb *fb) +{ + fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO; + /* This should put us in power-save */ + fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VSYNC_DIS; + fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_HSYNC_DIS; +} + +static void tcx_unblank (struct fb_info_sbusfb *fb) +{ + fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VSYNC_DIS; + fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_HSYNC_DIS; + fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO; +} + +static void tcx_reset (struct fb_info_sbusfb *fb) +{ + if (fb->open && fb->mmaped) + tcx_set_control_plane(fb); + + /* Turn off stuff in the Transform Engine. */ + fb->s.tcx.tec->tec_matrix = 0; + fb->s.tcx.tec->tec_clip = 0; + fb->s.tcx.tec->tec_vdc = 0; + + /* Enable cursor in Brooktree DAC. */ + fb->s.tcx.bt->addr = 0x06 << 24; + fb->s.tcx.bt->control |= 0x03 << 24; +} + +static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) +{ + p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin); +} + +static char idstring[60] __initdata = { 0 }; + +__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct display *disp = &fb->disp; + struct fbtype *type = &fb->type; + unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; + int lowdepth; + +#ifndef FBCON_HAS_CFB8 + return NULL; +#endif + + lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit"); + + if (lowdepth) { + strcpy(fb->info.modename, "TCX8"); + strcpy(fix->id, "TCX8"); + } else { + strcpy(fb->info.modename, "TCX24"); + strcpy(fix->id, "TCX24"); + } + fix->line_length = fb->var.xres_virtual; + + disp->scrollmode = SCROLL_YREDRAW; + if (!disp->screen_base) + disp->screen_base = (char *)sparc_alloc_io(phys, 0, + type->fb_size, "tcx_ram", fb->iospace, 0); + disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; + fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0, + sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0); + fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0, + sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0); + fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0, + sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0); + if (!lowdepth) { + fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0, + type->fb_size*4, "tcx_cplane", fb->iospace, 0); + type->fb_depth = 24; + fb->switch_from_graph = tcx_switch_from_graph; + } else { + /* As there can be one tcx in a machine only, we can write directly into + tcx_mmap_map */ + tcx_mmap_map[1].size = SBUS_MMAP_EMPTY; + tcx_mmap_map[4].size = SBUS_MMAP_EMPTY; + tcx_mmap_map[5].size = SBUS_MMAP_EMPTY; + tcx_mmap_map[6].size = SBUS_MMAP_EMPTY; + } + fb->dispsw = fbcon_cfb8; + + fb->margins = tcx_margins; + fb->loadcmap = tcx_loadcmap; + if (prom_getbool (fb->prom_node, "hw-cursor")) { + fb->setcursor = tcx_setcursor; + fb->setcursormap = tcx_setcursormap; + fb->setcurshape = tcx_setcurshape; + } + fb->restore_palette = tcx_restore_palette; + fb->blank = tcx_blank; + fb->unblank = tcx_unblank; + fb->reset = tcx_reset; + + fb->physbase = 0; + fb->mmap_map = tcx_mmap_map; + + /* Initialize Brooktree DAC */ + fb->s.tcx.bt->addr = 0x04 << 24; /* color planes */ + fb->s.tcx.bt->control = 0xff << 24; + fb->s.tcx.bt->addr = 0x05 << 24; + fb->s.tcx.bt->control = 0x00 << 24; + fb->s.tcx.bt->addr = 0x06 << 24; /* overlay plane */ + fb->s.tcx.bt->control = 0x73 << 24; + fb->s.tcx.bt->addr = 0x07 << 24; + fb->s.tcx.bt->control = 0x00 << 24; + + sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys, + (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK, + (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK, + lowdepth ? "8-bit only" : "24-bit depth"); + + tcx_reset(fb); + + return idstring; +} diff -u --recursive --new-file v2.1.111/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.1.111/linux/drivers/video/tgafb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/tgafb.c Sun Jul 26 14:40:19 1998 @@ -22,6 +22,7 @@ * KNOWN PROBLEMS/TO DO ==================================================== */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c --- v2.1.111/linux/drivers/video/vesafb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/vesafb.c Sun Jul 26 14:40:19 1998 @@ -8,6 +8,7 @@ * */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/vfb.c linux/drivers/video/vfb.c --- v2.1.111/linux/drivers/video/vfb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/vfb.c Sun Jul 26 14:40:19 1998 @@ -8,6 +8,7 @@ * more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c --- v2.1.111/linux/drivers/video/vgacon.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/vgacon.c Sun Jul 26 23:34:35 1998 @@ -33,7 +33,7 @@ * more details. */ -#include + #include #include #include @@ -94,6 +94,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines); static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse); static void vgacon_invert_region(struct vc_data *c, u16 *p, int count); +static unsigned long vgacon_uni_pagedir[2]; /* Description of the hardware situation */ @@ -292,16 +293,23 @@ return display_desc; } -static int vga_use_count; - static void vgacon_init(struct vc_data *c, int init) { + unsigned long p; + /* We cannot be loaded as a module, therefore init is always 1 */ c->vc_can_do_color = vga_can_do_color; c->vc_cols = vga_video_num_columns; c->vc_rows = vga_video_num_lines; c->vc_complement_mask = 0x7700; - vga_use_count++; + p = *c->vc_uni_pagedir_loc; + if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir || + !--c->vc_uni_pagedir_loc[1]) + con_free_unimap(c->vc_num); + c->vc_uni_pagedir_loc = vgacon_uni_pagedir; + vgacon_uni_pagedir[1]++; + if (!vgacon_uni_pagedir[0] && p) + con_set_default_unimap(c->vc_num); } static inline void vga_set_mem_top(struct vc_data *c) @@ -312,10 +320,13 @@ static void vgacon_deinit(struct vc_data *c) { /* When closing the last console, reset video origin */ - if (!--vga_use_count) { + if (!--vgacon_uni_pagedir[1]) { c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); + con_free_unimap(c->vc_num); } + c->vc_uni_pagedir_loc = &c->vc_uni_pagedir; + con_set_default_unimap(c->vc_num); } static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse) @@ -345,15 +356,19 @@ static void vgacon_invert_region(struct vc_data *c, u16 *p, int count) { - int col = vga_can_do_color; - - while (count--) { - u16 a = *p; - if (col) - a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); - else + if (vga_can_do_color) { + while (count--) { + u16 a = scr_readw(p); + a = (((a) & 0x88ff) | (((a) & 0x7000) >> 4) + | (((a) & 0x0700) << 4)); + scr_writew(a, p++); + } + } else { + while (count--) { + u16 a = scr_readw(p); a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700; - *p++ = a; + scr_writew(a, p++); + } } } @@ -862,6 +877,7 @@ op->width = 8; op->height = vga_video_font_height; op->charcount = vga_512_chars ? 512 : 256; + if (!op->data) return 0; rc = vgacon_do_font_op(op->data, 0, 0); } else rc = -ENOSYS; diff -u --recursive --new-file v2.1.111/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c --- v2.1.111/linux/drivers/video/virgefb.c Sun Jul 26 11:57:18 1998 +++ linux/drivers/video/virgefb.c Sun Jul 26 14:40:19 1998 @@ -16,6 +16,7 @@ #undef VIRGEFBDEBUG +#include #include #include #include diff -u --recursive --new-file v2.1.111/linux/fs/Config.in linux/fs/Config.in --- v2.1.111/linux/fs/Config.in Wed Jun 24 22:54:08 1998 +++ linux/fs/Config.in Sun Jul 26 01:20:22 1998 @@ -66,7 +66,7 @@ if [ "$CONFIG_AFFS_FS" != "n" ]; then define_bool CONFIG_AMIGA_PARTITION y fi -tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS +tristate 'UFS filesystem support' CONFIG_UFS_FS if [ "$CONFIG_UFS_FS" != "n" ]; then bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL diff -u --recursive --new-file v2.1.111/linux/fs/ufs/Makefile linux/fs/ufs/Makefile --- v2.1.111/linux/fs/ufs/Makefile Wed Jun 24 22:54:10 1998 +++ linux/fs/ufs/Makefile Sun Jul 26 01:20:22 1998 @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile. O_TARGET := ufs.o -O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \ - ufs_super.o ufs_symlink.o ufs_swab.o +O_OBJS := acl.o balloc.o cylinder.o dir.o file.o ialloc.o inode.o \ + namei.o super.o symlink.o truncate.o util.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.111/linux/fs/ufs/acl.c linux/fs/ufs/acl.c --- v2.1.111/linux/fs/ufs/acl.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/acl.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,66 @@ +/* + * linux/fs/ufs/acl.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles Uiversity, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/acl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +/* + * This file will contain the Access Control Lists management for the + * second extended file system. + */ + +#include +#include +#include +#include +#include + +/* + * ufs_permission () + * + * Check for access rights + */ +int ufs_permission (struct inode * inode, int mask) +{ + unsigned short mode = inode->i_mode; + + /* + * Nobody gets write access to a file on a readonly-fs + */ + if ((mask & S_IWOTH) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && + IS_RDONLY(inode)) + return -EROFS; + /* + * Nobody gets write access to an immutable file + */ + if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) + return -EACCES; + + /* + * If no ACL, checks using the file mode + */ + else if (current->fsuid == inode->i_uid) + mode >>= 6; + else if (in_group_p (inode->i_gid)) + mode >>= 3; + /* + * Access is always granted for root. We now check last, + * though, for BSD process accounting correctness + */ + if (((mode & mask & S_IRWXO) == mask) || fsuser()) + return 0; + else + return -EACCES; +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/balloc.c linux/fs/ufs/balloc.c --- v2.1.111/linux/fs/ufs/balloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/balloc.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,792 @@ +/* + * linux/fs/ufs/balloc.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_BALLOC_DEBUG +#undef UFS_BALLOC_DEBUG_MORE + +#ifdef UFS_BALLOC_DEBUG +#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +#ifdef UFS_BALLOC_DEBUG_MORE +#define UFSDM \ +ufs_print_cylinder_stuff (ucg, swab); \ +printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), \ +swab32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \ +printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), \ +SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \ +printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), \ +SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \ +printk("ndir: total %u, fs %u, cg %u\n\n", SWAB32(usb1->fs_cstotal.cs_ndir), \ +SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir)); +#else +#define UFSDM +#endif + + +unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *); +unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *); +unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *); +unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned); +static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[]; + +/* + * Free 'count' fragments from fragment number 'fragment' + */ +void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) { + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno; + unsigned swab; + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + swab = sb->u.ufs_sb.s_swab; + usb1 = ubh_get_usb_first(USPI_UBH); + + UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) + + if (ufs_fragnum(fragment) + count > uspi->s_fpg) + ufs_error (sb, "ufs_free_fragments", "internal error"); + + lock_super(sb); + + cgno = ufs_dtog(fragment); + bit = ufs_dtogd(fragment); + if (cgno >= uspi->s_ncg) { + ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device"); + goto failed; + } + + ucpi = ufs_load_cylinder (sb, cgno); + if (!ucpi) + goto failed; + ucg = ubh_get_ucg (UCPI_UBH); + if (!ufs_cg_chkmagic (ucg)) { + ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno); + goto failed; + } + + UFSDM + + end_bit = bit + count; + bbase = ufs_blknum (bit); + blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); + ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1); + for (i = bit; i < end_bit; i++) { + if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i)) + ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i); + else ufs_error (sb, "ufs_free_fragments", + "bit already cleared for fragment %u", i); + } + + DQUOT_FREE_BLOCK (sb, inode, count); + ADD_SWAB32(ucg->cg_cs.cs_nffree, count); + ADD_SWAB32(usb1->fs_cstotal.cs_nffree, count); + ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, count); + blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); + ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1); + + /* + * Trying to reasembly free fragments into block + */ + blkno = ufs_fragstoblks (bbase); + if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { + SUB_SWAB32(ucg->cg_cs.cs_nffree, uspi->s_fpb); + SUB_SWAB32(usb1->fs_cstotal.cs_nffree, uspi->s_fpb); + SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, uspi->s_fpb); + INC_SWAB32(ucg->cg_cs.cs_nbfree); + INC_SWAB32(usb1->fs_cstotal.cs_nbfree); + INC_SWAB32(sb->fs_cs(cgno).cs_nbfree); + cylno = ufs_cbtocylno (bbase); + INC_SWAB16(ubh_cg_blks (ucpi, cylno, ufs_cbtorpos(bbase))); + INC_SWAB32(ubh_cg_blktot (ucpi, cylno)); + } + + UFSDM + + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + sb->s_dirt = 1; + + unlock_super (sb); + UFSD(("EXIT\n")) + return; + +failed: + unlock_super (sb); + UFSD(("EXIT (FAILED)\n")) + return; +} + +/* + * Free 'count' fragments from fragment number 'fragment' (free whole blocks) + */ +void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned overflow, cgno, bit, end_bit, blkno, i, cylno; + unsigned swab; + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + swab = sb->u.ufs_sb.s_swab; + usb1 = ubh_get_usb_first(USPI_UBH); + + UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) + + if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) { + ufs_error (sb, "ufs_free_blocks", "internal error"); + goto failed; + } + + lock_super(sb); + +do_more: + overflow = 0; + cgno = ufs_dtog (fragment); + bit = ufs_dtogd (fragment); + if (cgno >= uspi->s_ncg) { + ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device"); + goto failed; + } + end_bit = bit + count; + if (end_bit > uspi->s_fpg) { + overflow = bit + count - uspi->s_fpg; + count -= overflow; + end_bit -= overflow; + } + + ucpi = ufs_load_cylinder (sb, cgno); + if (!ucpi) + goto failed; + ucg = ubh_get_ucg (UCPI_UBH); + if (!ufs_cg_chkmagic (ucg)) { + ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno); + goto failed; + } + + UFSDM + + for (i = bit; i < end_bit; i += uspi->s_fpb) { + blkno = ufs_fragstoblks(i); + if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { + ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); + } + ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno); + DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb); + INC_SWAB32(ucg->cg_cs.cs_nbfree); + INC_SWAB32(usb1->fs_cstotal.cs_nbfree); + INC_SWAB32(sb->fs_cs(cgno).cs_nbfree); + cylno = ufs_cbtocylno(i); + INC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i))); + INC_SWAB32(ubh_cg_blktot(ucpi, cylno)); + } + + UFSDM + + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + + if (overflow) { + fragment += count; + count = overflow; + goto do_more; + } + + sb->s_dirt = 1; + unlock_super (sb); + UFSD(("EXIT\n")) + return; + +failed: + unlock_super (sb); + UFSD(("EXIT (FAILED)\n")) + return; +} + + + +#define NULLIFY_FRAGMENTS \ + for (i = oldcount; i < newcount; i++) { \ + bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \ + memset (bh->b_data, 0, sb->s_blocksize); \ + mark_buffer_uptodate(bh, 1); \ + mark_buffer_dirty (bh, 1); \ + if (IS_SYNC(inode)) { \ + ll_rw_block (WRITE, 1, &bh); \ + wait_on_buffer (bh); \ + } \ + brelse (bh); \ + } + +unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment, + unsigned goal, unsigned count, int * err ) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct buffer_head * bh; + unsigned cgno, oldcount, newcount, tmp, request, i, result; + unsigned swab; + + UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + *err = -ENOSPC; + + lock_super (sb); + + tmp = SWAB32(*p); + if (count + ufs_fragnum(fragment) > uspi->s_fpb) { + ufs_warning (sb, "ufs_new_fragments", "internal warning" + " fragment %u, count %u", fragment, count); + count = uspi->s_fpb - ufs_fragnum(fragment); + } + oldcount = ufs_fragnum (fragment); + newcount = oldcount + count; + + /* + * Somebody else has just allocated our fragments + */ + if (oldcount) { + if (!tmp) { + ufs_error (sb, "ufs_new_fragments", "internal error, " + "fragment %u, tmp %u\n", fragment, tmp); + return (unsigned)-1; + } + if (fragment < inode->u.ufs_i.i_lastfrag) { + UFSD(("EXIT (ALREADY ALLOCATED)\n")) + printk("hlaska 2\n"); + unlock_super (sb); + return 0; + } + } + else { + if (tmp) { + UFSD(("EXIT (ALREADY ALLOCATED)\n")) + printk("hlaska 3, fragment %u, tmp %u, oldcount %u\n", fragment, tmp, oldcount); + unlock_super(sb); + return 0; + } + } + + /* + * There is not enough space for user on the device + */ + if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) { + unlock_super (sb); + UFSD(("EXIT (FAILED)\n")) + return 0; + } + + if (goal >= uspi->s_size) + goal = 0; + if (goal == 0) + cgno = ufs_inotocg (inode->i_ino); + else + cgno = ufs_dtog (goal); + + /* + * allocate new fragment + */ + if (oldcount == 0) { + result = ufs_alloc_fragments (inode, cgno, goal, count, err); + if (result) { + *p = SWAB32(result); + *err = 0; + inode->i_blocks += count << uspi->s_nspfshift; + inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count); + NULLIFY_FRAGMENTS + } + unlock_super(sb); + UFSD(("EXIT, result %u\n", result)) + return result; + } + + /* + * resize block + */ + result = ufs_add_fragments (inode, tmp, oldcount, newcount, err); + if (result) { + *err = 0; + inode->i_blocks += count << uspi->s_nspfshift; + inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count); + NULLIFY_FRAGMENTS + unlock_super(sb); + UFSD(("EXIT, result %u\n", result)) + return result; + } + + /* + * allocate new block and move data + */ + switch (SWAB32(usb1->fs_optim)) { + case UFS_OPTSPACE: + request = newcount; + if (uspi->s_minfree < 5 || SWAB32(usb1->fs_cstotal.cs_nffree) + > uspi->s_dsize * uspi->s_minfree / (2 * 100) ) + break; + usb1->fs_optim = SWAB32(UFS_OPTTIME); + break; + default: + usb1->fs_optim = SWAB32(UFS_OPTTIME); + + case UFS_OPTTIME: + request = uspi->s_fpb; + if (SWAB32(usb1->fs_cstotal.cs_nffree) < uspi->s_dsize * + (uspi->s_minfree - 2) / 100) + break; + usb1->fs_optim = SWAB32(UFS_OPTSPACE); + break; + } + result = ufs_alloc_fragments (inode, cgno, goal, request, err); + if (result) { + for (i = 0; i < oldcount; i++) { + bh = bread (sb->s_dev, tmp + i, sb->s_blocksize); + mark_buffer_clean (bh); + bh->b_blocknr = result + i; + mark_buffer_dirty (bh, 0); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + } + *p = SWAB32(result); + *err = 0; + inode->i_blocks += count << uspi->s_nspfshift; + inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count); + NULLIFY_FRAGMENTS + unlock_super(sb); + if (newcount < request) + ufs_free_fragments (inode, result + newcount, request - newcount); + ufs_free_fragments (inode, tmp, oldcount); + UFSD(("EXIT, result %u\n", result)) + return result; + } + + unlock_super(sb); + UFSD(("EXIT (FAILED)\n")) + return 0; +} + +unsigned ufs_add_fragments (struct inode * inode, unsigned fragment, + unsigned oldcount, unsigned newcount, int * err) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned cgno, fragno, fragoff, count, fragsize, i; + unsigned swab; + + UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount)) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first (USPI_UBH); + count = newcount - oldcount; + + cgno = ufs_dtog(fragment); + if (sb->fs_cs(cgno).cs_nffree < count) + return 0; + if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb) + return 0; + ucpi = ufs_load_cylinder (sb, cgno); + if (!ucpi) + return 0; + ucg = ubh_get_ucg (UCPI_UBH); + if (!ufs_cg_chkmagic(ucg)) { + ufs_panic (sb, "ufs_add_fragments", + "internal error, bad magic number on cg %u", cgno); + return 0; + } + + UFSDM + + fragno = ufs_dtogd (fragment); + fragoff = ufs_fragnum (fragno); + for (i = oldcount; i < newcount; i++) + if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i)) + return 0; + /* + * Block can be extended + */ + ucg->cg_time = SWAB32(CURRENT_TIME); + for (i = newcount; i < (uspi->s_fpb - fragoff); i++) + if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i)) + break; + fragsize = i - oldcount; + if (!SWAB32(ucg->cg_frsum[fragsize])) + ufs_panic (sb, "ufs_add_fragments", + "internal error or corruted bitmap on cg %u", cgno); + DEC_SWAB32(ucg->cg_frsum[fragsize]); + if (fragsize != count) + INC_SWAB32(ucg->cg_frsum[fragsize - count]); + for (i = oldcount; i < newcount; i++) + ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i); + if(DQUOT_ALLOC_BLOCK(sb, inode, count)) { + *err = -EDQUOT; + return 0; + } + SUB_SWAB32(ucg->cg_cs.cs_nffree, count); + SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count); + SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count); + usb1->fs_fmod = SWAB32(1); + + UFSDM + + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + sb->s_dirt = 1; + + UFSD(("EXIT, fragment %u\n", fragment)) + + return fragment; +} + +#define UFS_TEST_FREE_SPACE_CG \ + ucg = (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[cgno]->b_data; \ + if (SWAB32(ucg->cg_cs.cs_nbfree)) \ + goto cg_found; \ + for (k = count; k < uspi->s_fpb; k++) \ + if (SWAB32(ucg->cg_frsum[k])) \ + goto cg_found; + +unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno, + unsigned goal, unsigned count, int * err) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned oldcg, i, j, k, result, allocsize; + unsigned swab; + + UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count)) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + oldcg = cgno; + + /* + * 1. searching on preferred cylinder group + */ + UFS_TEST_FREE_SPACE_CG + + /* + * 2. quadratic rehash + */ + for (j = 1; j < uspi->s_ncg; j *= 2) { + cgno += j; + if (cgno >= uspi->s_ncg) + cgno -= uspi->s_ncg; + UFS_TEST_FREE_SPACE_CG + } + + /* + * 3. brute force search + * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step ) + */ + cgno = (oldcg + 1) % uspi->s_ncg; + for (j = 2; j < uspi->s_ncg; j++) { + cgno++; + if (cgno >= uspi->s_ncg) + cgno = 0; + UFS_TEST_FREE_SPACE_CG + } + + UFSD(("EXIT (FAILED)\n")) + return 0; + +cg_found: + ucpi = ufs_load_cylinder (sb, cgno); + if (!ucpi) + return 0; + ucg = ubh_get_ucg (UCPI_UBH); + if (!ufs_cg_chkmagic(ucg)) + ufs_panic (sb, "ufs_alloc_fragments", + "internal error, bad magic number on cg %u", cgno); + ucg->cg_time = SWAB32(CURRENT_TIME); + + UFSDM + + if (count == uspi->s_fpb) { + result = ufs_alloccg_block (inode, ucpi, goal, err); + if (result == (unsigned)-1) + return 0; + goto succed; + } + + for (allocsize = count; allocsize < uspi->s_fpb; allocsize++) + if (SWAB32(ucg->cg_frsum[allocsize]) != 0) + break; + + if (allocsize == uspi->s_fpb) { + result = ufs_alloccg_block (inode, ucpi, goal, err); + if (result == (unsigned)-1) + return 0; + goal = ufs_dtogd (result); + for (i = count; i < uspi->s_fpb; i++) + ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i); + i = uspi->s_fpb - count; + DQUOT_FREE_BLOCK(sb, inode, i); + ADD_SWAB32(ucg->cg_cs.cs_nffree, i); + ADD_SWAB32(usb1->fs_cstotal.cs_nffree, i); + ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, i); + INC_SWAB32(ucg->cg_frsum[i]); + goto succed; + } + + result = ufs_bitmap_search (sb, ucpi, goal, allocsize); + if (result == (unsigned)-1) + return 0; + if(DQUOT_ALLOC_BLOCK(sb, inode, count)) { + *err = -EDQUOT; + return 0; + } + for (i = 0; i < count; i++) + ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i); + SUB_SWAB32(ucg->cg_cs.cs_nffree, count); + SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count); + SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count); + DEC_SWAB32(ucg->cg_frsum[allocsize]); + if (count != allocsize) + INC_SWAB32(ucg->cg_frsum[allocsize - count]); + +succed: + usb1->fs_fmod = SWAB32(1); + + UFSDM + + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + sb->s_dirt = 1; + + result += cgno * uspi->s_fpg; + UFSD(("EXIT3, result %u\n", result)) + return result; +} + +unsigned ufs_alloccg_block (struct inode * inode, + struct ufs_cg_private_info * ucpi, unsigned goal, int * err) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cylinder_group * ucg; + unsigned result, cylno, blkno; + unsigned swab; + + UFSD(("ENTER, goal %u\n", goal)) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH); + + if (goal == 0) { + goal = ucpi->c_rotor; + goto norot; + } + goal = ufs_blknum (goal); + goal = ufs_dtogd (goal); + + /* + * If the requested block is available, use it. + */ + if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) { + result = goal; + goto gotit; + } + + /*** This function should be optimalized later ***/ + +norot: + result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb); + if (result == (unsigned)-1) + return (unsigned)-1; + ucpi->c_rotor = result; +gotit: + blkno = ufs_fragstoblks(result); + ubh_clrblock(UCPI_UBH, ucpi->c_freeoff, blkno); + if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) { + *err = -EDQUOT; + return (unsigned)-1; + } + DEC_SWAB32(ucg->cg_cs.cs_nbfree); + DEC_SWAB32(usb1->fs_cstotal.cs_nbfree); + DEC_SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree); + cylno = ufs_cbtocylno(result); + DEC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result))); + DEC_SWAB32(ubh_cg_blktot(ucpi, cylno)); + usb1->fs_fmod = 1; + + UFSD(("EXIT, result %u\n", result)) + + return result; +} + +unsigned ufs_bitmap_search (struct super_block * sb, + struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count) +{ + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cylinder_group * ucg; + unsigned start, length, length2, location, result; + unsigned possition, fragsize, blockmap, mask; + unsigned swab; + + UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count)) + + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first (USPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH); + + if (goal) + start = ufs_dtogd(goal) >> 3; + else + start = ucpi->c_frotor >> 3; + + length = howmany(uspi->s_fpg, 8) - start; + location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length, + (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, + 1 << (count - 1 + (uspi->s_fpb & 7))); + if (location == 0) { + length2 = start + 1; + location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length2, + (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, + 1 << (count - 1 + (uspi->s_fpb & 7))); + if (location == 0) { + ufs_error (sb, "ufs_bitmap_search", + "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n", + ucpi->c_cgx, start, length, count, ucpi->c_freeoff); + return (unsigned)-1; + } + start = 0; + length = length2; + } + result = (start + length - location) << 3; + ucpi->c_frotor = result; + + /* + * found the byte in the map + */ + blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result); + fragsize = 0; + for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) { + if (blockmap & mask) { + if (!(possition & uspi->s_fpbmask)) + fragsize = 1; + else + fragsize++; + } + else { + if (fragsize == count) { + result += possition - count; + UFSD(("EXIT, result %u\n", result)) + return result; + } + fragsize = 0; + } + } + if (fragsize == count) { + result += possition - count; + UFSD(("EXIT, result %u\n", result)) + return result; + } + ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx); + UFSD(("EXIT (FAILED)\n")) + return (unsigned)-1; +} + +static unsigned char ufs_fragtable_8fpb[] = { + 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C, + 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80, +}; + +static unsigned char ufs_fragtable_other[] = { + 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE, + 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E, + 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE, + 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA, + 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE, + 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE, + 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A, +}; diff -u --recursive --new-file v2.1.111/linux/fs/ufs/cylinder.c linux/fs/ufs/cylinder.c --- v2.1.111/linux/fs/ufs/cylinder.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/cylinder.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,212 @@ +/* + * linux/fs/ufs/cylinder.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * ext2 - inode (block) bitmap caching inspired + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_CYLINDER_DEBUG +#undef UFS_CYLINDER_DEBUG_MORE + +#ifdef UFS_CYLINDER_DEBUG +#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + + +/* + * Read cylinder group into cache. The memory space for ufs_cg_private_info + * structure is already allocated during ufs_read_super. + */ +static void ufs_read_cylinder (struct super_block * sb, + unsigned cgno, unsigned bitmap_nr) +{ + struct ufs_sb_private_info * uspi; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned i, j; + unsigned swab; + + UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr)) + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr]; + ucg = (struct ufs_cylinder_group *)sb->u.ufs_sb.s_ucg[cgno]->b_data; + +#ifdef UFS_CYLINDER_DEBUG_MORE + ufs_print_cylinder_stuff (ucg, swab); +#endif + + UCPI_UBH->fragment = ufs_cgcmin(cgno); + UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits; + /* + * We have already the first fragment of cylinder group block in buffer + */ + UCPI_UBH->bh[0] = sb->u.ufs_sb.s_ucg[cgno]; + for (i = 1; i < UCPI_UBH->count; i++) + if (!(UCPI_UBH->bh[i] = bread (sb->s_dev, UCPI_UBH->fragment + i, sb->s_blocksize))) + goto failed; + sb->u.ufs_sb.s_cgno[bitmap_nr] = cgno; + + ucpi->c_cgx = SWAB32(ucg->cg_cgx); + ucpi->c_ncyl = SWAB16(ucg->cg_ncyl); + ucpi->c_niblk = SWAB16(ucg->cg_niblk); + ucpi->c_ndblk = SWAB32(ucg->cg_ndblk); + ucpi->c_rotor = SWAB32(ucg->cg_rotor); + ucpi->c_frotor = SWAB32(ucg->cg_frotor); + ucpi->c_irotor = SWAB32(ucg->cg_irotor); + ucpi->c_btotoff = SWAB32(ucg->cg_btotoff); + ucpi->c_boff = SWAB32(ucg->cg_boff); + ucpi->c_iusedoff = SWAB32(ucg->cg_iusedoff); + ucpi->c_freeoff = SWAB32(ucg->cg_freeoff); + ucpi->c_nextfreeoff = SWAB32(ucg->cg_nextfreeoff); + + UFSD(("EXIT\n")) + return; + +failed: + for (j = 1; j < i; j++) + brelse (sb->u.ufs_sb.s_ucg[j]); + sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; + ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno); +} + +/* + * Remove cylinder group from cache, does'n release memory + * allocated for cylinder group (this is done at ufs_put_super only). + */ +void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr) +{ + struct ufs_sb_private_info * uspi; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + unsigned i; + unsigned swab; + + UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr)) + + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + if (sb->u.ufs_sb.s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) { + UFSD(("EXIT\n")) + return; + } + ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr]; + ucg = ubh_get_ucg(UCPI_UBH); + + if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sb->u.ufs_sb.s_cg_loaded) { + ufs_panic (sb, "ufs_put_cylinder", "internal error"); + return; + } + /* + * rotor is not so important data, so we put it to disk + * at the end of working with cylinder + */ + ucg->cg_rotor = SWAB32(ucpi->c_rotor); + ucg->cg_frotor = SWAB32(ucpi->c_frotor); + ucg->cg_irotor = SWAB32(ucpi->c_irotor); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + for (i = 1; i < UCPI_UBH->count; i++) { + brelse (UCPI_UBH->bh[i]); + } + + sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; + UFSD(("EXIT\n")) +} + +/* + * Find cylinder group in cache and return it as pointer. + * If cylinder group is not in cache, we will load it from disk. + * + * The cache is managed by LRU alghoritm. + */ +struct ufs_cg_private_info * ufs_load_cylinder ( + struct super_block * sb, unsigned cgno) +{ + struct ufs_sb_private_info * uspi; + struct ufs_cg_private_info * ucpi; + unsigned cg, i, j; + + UFSD(("ENTER, cgno %u\n", cgno)) + + uspi = sb->u.ufs_sb.s_uspi; + if (cgno >= uspi->s_ncg) { + ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg"); + return NULL; + } + /* + * Cylinder group number cg it in cache and it was last used + */ + if (sb->u.ufs_sb.s_cgno[0] == cgno) { + UFSD(("EXIT\n")) + return sb->u.ufs_sb.s_ucpi[0]; + } + /* + * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED + */ + if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) { + if (sb->u.ufs_sb.s_cgno[cgno] != UFS_CGNO_EMPTY) { + if (sb->u.ufs_sb.s_cgno[cgno] != cgno) { + ufs_panic (sb, "ufs_load_cylinder", "internal error, wrog number of cg in cache"); + UFSD(("EXIT (FAILED)\n")) + return NULL; + } + else { + UFSD(("EXIT\n")) + return sb->u.ufs_sb.s_ucpi[cgno]; + } + } else { + ufs_read_cylinder (sb, cgno, cgno); + UFSD(("EXIT\n")) + return sb->u.ufs_sb.s_ucpi[cgno]; + } + } + /* + * Cylinder group number cg is in cache but it was not last used, + * we will move to the first position + */ + for (i = 0; i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] != cgno; i++); + if (i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] == cgno) { + cg = sb->u.ufs_sb.s_cgno[i]; + ucpi = sb->u.ufs_sb.s_ucpi[i]; + for (j = i; j > 0; j--) { + sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1]; + sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1]; + } + sb->u.ufs_sb.s_cgno[0] = cg; + sb->u.ufs_sb.s_ucpi[0] = ucpi; + /* + * Cylinder group number cg is not in cache, we will read it from disk + * and put it to the first possition + */ + } else { + if (sb->u.ufs_sb.s_cg_loaded < UFS_MAX_GROUP_LOADED) + sb->u.ufs_sb.s_cg_loaded++; + else + ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1); + for (j = sb->u.ufs_sb.s_cg_loaded - 1; j > 0; j--) { + sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1]; + sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1]; + } + ufs_read_cylinder (sb, cgno, 0); + } + UFSD(("EXIT\n")) + return sb->u.ufs_sb.s_ucpi[0]; +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/dir.c linux/fs/ufs/dir.c --- v2.1.111/linux/fs/ufs/dir.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/dir.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,228 @@ +/* + * linux/fs/ufs/ufs_dir.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * swab support by Francois-Rene Rideau 19970406 + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * + * write support by Daniel Pirkl 1998 + */ + +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_DIR_DEBUG + +#ifdef UFS_DIR_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +/* + * This is blatantly stolen from ext2fs + */ +static int +ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) +{ + struct inode *inode = filp->f_dentry->d_inode; + int error = 0; + unsigned long offset, lblk, blk; + int i, stored; + struct buffer_head * bh; + struct ufs_dir_entry * de; + struct super_block * sb; + int de_reclen; + unsigned flags, swab; + + + /* Isn't that already done in the upper layer??? + * the VFS layer really needs some explicit documentation! + */ + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + flags = sb->u.ufs_sb.s_flags; + + UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos)) + + stored = 0; + bh = NULL; + offset = filp->f_pos & (sb->s_blocksize - 1); + + while (!error && !stored && filp->f_pos < inode->i_size) { + lblk = (filp->f_pos) >> sb->s_blocksize_bits; + /* XXX - ufs_bmap() call needs error checking */ + blk = ufs_bmap(inode, lblk); + bh = bread (sb->s_dev, blk, sb->s_blocksize); + if (!bh) { + /* XXX - error - skip to the next block */ + printk("ufs_readdir: " + "dir inode %lu has a hole at offset %lu\n", + inode->i_ino, (unsigned long int)filp->f_pos); + filp->f_pos += sb->s_blocksize - offset; + continue; + } + +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (filp->f_version != inode->i_version) { + for (i = 0; i < sb->s_blocksize && i < offset; ) { + de = (struct ufs_dir_entry *)(bh->b_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + de_reclen = SWAB16(de->d_reclen); + if (de_reclen < 1) + break; + i += de_reclen; + } + offset = i; + filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + | offset; + filp->f_version = inode->i_version; + } + + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct ufs_dir_entry *) (bh->b_data + offset); + /* XXX - put in a real ufs_check_dir_entry() */ + if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) { + /* SWAB16() was unneeded -- compare to 0 */ + filp->f_pos = (filp->f_pos & + (sb->s_blocksize - 1)) + + sb->s_blocksize; + brelse(bh); + return stored; + } +#if 0 /* XXX */ + if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + /* XXX - beware about de having to be swabped somehow */ + bh, offset)) { + /* On error, skip the f_pos to the + next block. */ + filp->f_pos = (filp->f_pos & + (sb->s_blocksize - 1)) + + sb->s_blocksize; + brelse (bh); + return stored; + } +#endif /* XXX */ + offset += SWAB16(de->d_reclen); + if (de->d_ino) { + /* SWAB16() was unneeded -- compare to 0 */ + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. */ + unsigned long version = inode->i_version; + + UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino))) + UFSD(("namlen %u\n", ufs_namlen(de))) + error = filldir(dirent, de->d_name, ufs_namlen(de), + filp->f_pos, SWAB32(de->d_ino)); + if (error) + break; + if (version != inode->i_version) + goto revalidate; + stored ++; + } + filp->f_pos += SWAB16(de->d_reclen); + } + offset = 0; + brelse (bh); + } + UPDATE_ATIME(inode); + return 0; +} + +int ufs_check_dir_entry (const char * function, struct inode * dir, + struct ufs_dir_entry * de, struct buffer_head * bh, + unsigned long offset) +{ + struct super_block * sb; + const char * error_msg; + unsigned flags, swab; + + sb = dir->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + error_msg = NULL; + + if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1)) + error_msg = "reclen is smaller than minimal"; + else if (SWAB16(de->d_reclen) % 4 != 0) + error_msg = "reclen % 4 != 0"; + else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de))) + error_msg = "reclen is too small for namlen"; + else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) > + dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg)) + error_msg = "inode out of bounds"; + + if (error_msg != NULL) + ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - " + "offset=%lu, inode=%lu, reclen=%d, namlen=%d", + dir->i_ino, dir->i_size, error_msg, offset, + (unsigned long) SWAB32(de->d_ino), + SWAB16(de->d_reclen), ufs_namlen(de)); + + return (error_msg == NULL ? 1 : 0); +} + +static struct file_operations ufs_dir_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + ufs_readdir, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + file_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct inode_operations ufs_dir_inode_operations = { + &ufs_dir_operations, /* default directory file operations */ + ufs_create, /* create */ + ufs_lookup, /* lookup */ + ufs_link, /* link */ + ufs_unlink, /* unlink */ + ufs_symlink, /* symlink */ + ufs_mkdir, /* mkdir */ + ufs_rmdir, /* rmdir */ + ufs_mknod, /* mknod */ + ufs_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + ufs_bmap, /* bmap */ + ufs_truncate, /* truncate */ + ufs_permission, /* permission */ + NULL, /* smap */ +}; diff -u --recursive --new-file v2.1.111/linux/fs/ufs/file.c linux/fs/ufs/file.c --- v2.1.111/linux/fs/ufs/file.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/file.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,281 @@ +/* + * linux/fs/ufs/file.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/file.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 fs regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static long long ufs_file_lseek(struct file *, long long, int); +static ssize_t ufs_file_write (struct file *, const char *, size_t, loff_t *); +static int ufs_release_file (struct inode *, struct file *); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the ufs filesystem. + */ +static struct file_operations ufs_file_operations = { + ufs_file_lseek, /* lseek */ + generic_file_read, /* read */ + ufs_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + ufs_release_file, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + +struct inode_operations ufs_file_inode_operations = { + &ufs_file_operations,/* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + generic_readpage, /* readpage */ + NULL, /* writepage */ + ufs_bmap, /* bmap */ + ufs_truncate, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + +/* + * Make sure the offset never goes beyond the 32-bit mark.. + */ +static long long ufs_file_lseek( + struct file *file, + long long offset, + int origin ) +{ + long long retval; + struct inode *inode = file->f_dentry->d_inode; + + switch (origin) { + case 2: + offset += inode->i_size; + break; + case 1: + offset += file->f_pos; + } + retval = -EINVAL; + /* make sure the offset fits in 32 bits */ + if (((unsigned long long) offset >> 32) == 0) { + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + retval = offset; + } + return retval; +} + +static inline void remove_suid(struct inode *inode) +{ + unsigned int mode; + + /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ + mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; + + /* was any of the uid bits set? */ + mode &= inode->i_mode; + if (mode && !suser()) { + inode->i_mode &= ~mode; + mark_inode_dirty(inode); + } +} + +static ssize_t ufs_file_write ( + struct file * filp, + const char * buf, + size_t count, + loff_t *ppos ) +{ + struct inode * inode = filp->f_dentry->d_inode; + __u32 pos; + long block; + int offset; + int written, c; + struct buffer_head * bh, *bufferlist[NBUF]; + struct super_block * sb; + int err; + int i,buffercount,write_error; + + /* POSIX: mtime/ctime may not change for 0 count */ + if (!count) + return 0; + write_error = buffercount = 0; + if (!inode) + return -EINVAL; + sb = inode->i_sb; + if (sb->s_flags & MS_RDONLY) + /* + * This fs has been automatically remounted ro because of errors + */ + return -ENOSPC; + + if (!S_ISREG(inode->i_mode)) { + ufs_warning (sb, "ufs_file_write", "mode = %07o", + inode->i_mode); + return -EINVAL; + } + remove_suid(inode); + + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else { + pos = *ppos; + if (pos != *ppos) + return -EINVAL; + } + + /* Check for overflow.. */ + if (pos > (__u32) (pos + count)) { + count = ~pos; /* == 0xFFFFFFFF - pos */ + if (!count) + return -EFBIG; + } + + /* + * If a file has been opened in synchronous mode, we have to ensure + * that meta-data will also be written synchronously. Thus, we + * set the i_osync field. This field is tested by the allocation + * routines. + */ + if (filp->f_flags & O_SYNC) + inode->u.ufs_i.i_osync++; + block = pos >> sb->s_blocksize_bits; + offset = pos & (sb->s_blocksize - 1); + c = sb->s_blocksize - offset; + written = 0; + do { + bh = ufs_getfrag (inode, block, 1, &err); + if (!bh) { + if (!written) + written = err; + break; + } + if (c > count) + c = count; + if (c != sb->s_blocksize && !buffer_uptodate(bh)) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) { + brelse (bh); + if (!written) + written = -EIO; + break; + } + } + c -= copy_from_user (bh->b_data + offset, buf, c); + if (!c) { + brelse(bh); + if (!written) + written = -EFAULT; + break; + } + update_vm_cache(inode, pos, bh->b_data + offset, c); + pos += c; + written += c; + buf += c; + count -= c; + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 0); + if (filp->f_flags & O_SYNC) + bufferlist[buffercount++] = bh; + else + brelse(bh); + if (buffercount == NBUF){ + ll_rw_block(WRITE, buffercount, bufferlist); + for(i=0; is_blocksize; + } while (count); + if (buffercount){ + ll_rw_block(WRITE, buffercount, bufferlist); + for (i=0; i inode->i_size) + inode->i_size = pos; + if (filp->f_flags & O_SYNC) + inode->u.ufs_i.i_osync--; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + *ppos = pos; + mark_inode_dirty(inode); + return written; +} + +/* + * Called when an inode is released. Note that this is different + * from ufs_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +static int ufs_release_file (struct inode * inode, struct file * filp) +{ + return 0; +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c --- v2.1.111/linux/fs/ufs/ialloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/ialloc.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,341 @@ +/* + * linux/fs/ufs/ialloc.c + * + * Copyright (c) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/ialloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_IALLOC_DEBUG +#undef UFS_IALLOC_DEBUG_MORE + +#ifdef UFS_IALLOC_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +#ifdef UFS_IALLOC_DEBUG_MORE +#define UFSDM \ +ufs_print_cylinder_stuff (ucg, swab); \ +printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \ +printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \ +printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \ +printk("ndir: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_ndir), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir)); +#else +#define UFSDM +#endif + + +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ +void ufs_free_inode (struct inode * inode) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + int is_directory; + unsigned ino, cg, bit; + unsigned swab; + + UFSD(("ENTER, ino %lu\n", inode->i_ino)) + + if (!inode) + return; + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + + if (inode->i_count > 1) { + ufs_warning(sb, "ufs_free_inode", "inode has count=%d\n", inode->i_count); + return; + } + if (inode->i_nlink) { + ufs_warning(sb, "ufs_free_inode", "inode has nlink=%d\n", inode->i_nlink); + return; + } + + ino = inode->i_ino; + + lock_super (sb); + + if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) { + ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); + unlock_super (sb); + return; + } + + cg = ufs_inotocg (ino); + bit = ufs_inotocgoff (ino); + ucpi = ufs_load_cylinder (sb, cg); + if (!ucpi) { + unlock_super (sb); + return; + } + ucg = ubh_get_ucg(UCPI_UBH); + if (!ufs_cg_chkmagic(ucg)) + ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number"); + + UFSDM + + ucg->cg_time = SWAB32(CURRENT_TIME); + + is_directory = S_ISDIR(inode->i_mode); + + DQUOT_FREE_INODE(sb, inode); + + clear_inode (inode); + + if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit)) + ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino); + else { + ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit); + if (ino < ucpi->c_irotor) + ucpi->c_irotor = ino; + INC_SWAB32(ucg->cg_cs.cs_nifree); + INC_SWAB32(usb1->fs_cstotal.cs_nifree); + INC_SWAB32(sb->fs_cs(cg).cs_nifree); + + if (is_directory) { + DEC_SWAB32(ucg->cg_cs.cs_ndir); + DEC_SWAB32(usb1->fs_cstotal.cs_ndir); + DEC_SWAB32(sb->fs_cs(cg).cs_ndir); + } + } + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + + UFSDM + + sb->s_dirt = 1; + unlock_super (sb); + UFSD(("EXIT\n")) +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ +struct inode * ufs_new_inode (const struct inode * dir, int mode, int * err ) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_cg_private_info * ucpi; + struct ufs_cylinder_group * ucg; + struct inode * inode; + unsigned cg, bit, i, j, start; + unsigned swab; + + UFSD(("ENTER\n")) + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) { + *err = -EPERM; + return NULL; + } + inode = get_empty_inode (); + if (!inode) { + *err = -ENOMEM; + return NULL; + } + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + + lock_super (sb); + + *err = -ENOSPC; + + /* + * Try to place the inode in its parent directory + */ + i = ufs_inotocg(dir->i_ino); + if (SWAB32(sb->fs_cs(i).cs_nifree)) { + cg = i; + goto cg_found; + } + + /* + * Use a quadratic hash to find a group with a free inode + */ + for ( j = 1; j < uspi->s_ncg; j <<= 1 ) { + i += j; + if (i >= uspi->s_ncg) + i -= uspi->s_ncg; + if (SWAB32(sb->fs_cs(i).cs_nifree)) { + cg = i; + goto cg_found; + } + } + + /* + * That failed: try linear search for a free inode + */ + i = ufs_inotocg(dir->i_ino) + 1; + for (j = 2; j < uspi->s_ncg; j++) { + i++; + if (i >= uspi->s_ncg) + i = 0; + if (SWAB32(sb->fs_cs(i).cs_nifree)) { + cg = i; + goto cg_found; + } + } + + goto failed; + +cg_found: + ucpi = ufs_load_cylinder (sb, cg); + if (!ucpi) + goto failed; + ucg = ubh_get_ucg(UCPI_UBH); + if (!ufs_cg_chkmagic(ucg)) + ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number"); + + UFSDM + + start = ucpi->c_irotor; + bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start); + if (!(bit < uspi->s_ipg)) { + bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start); + if (!(bit < start)) { + ufs_error (sb, "ufs_new_inode", + "cylinder group %u corrupted - error in inode bitmap\n", cg); + goto failed; + } + } + UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg)) + if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit)) + ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit); + else { + ufs_panic (sb, "ufs_new_inode", "internal error"); + goto failed; + } + + DEC_SWAB32(ucg->cg_cs.cs_nifree); + DEC_SWAB32(usb1->fs_cstotal.cs_nifree); + DEC_SWAB32(sb->fs_cs(cg).cs_nifree); + + if (S_ISDIR(mode)) { + INC_SWAB32(ucg->cg_cs.cs_ndir); + INC_SWAB32(usb1->fs_cstotal.cs_ndir); + INC_SWAB32(sb->fs_cs(cg).cs_ndir); + } + + ubh_mark_buffer_dirty (USPI_UBH, 1); + ubh_mark_buffer_dirty (UCPI_UBH, 1); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi); + ubh_wait_on_buffer (UCPI_UBH); + } + sb->s_dirt = 1; + + inode->i_mode = mode; + inode->i_sb = sb; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->fsuid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + + inode->i_ino = cg * uspi->s_ipg + bit; + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags; + inode->u.ufs_i.i_uid = inode->i_uid; + inode->u.ufs_i.i_gid = inode->i_gid; + inode->u.ufs_i.i_lastfrag = 0; + inode->i_op = NULL; + + insert_inode_hash(inode); + mark_inode_dirty(inode); + + UFSDM + + unlock_super (sb); + + if(DQUOT_ALLOC_INODE(sb, inode)) { + sb->dq_op->drop(inode); + inode->i_nlink = 0; + iput(inode); + *err = -EDQUOT; + return NULL; + } + + UFSD(("allocating inode %lu\n", inode->i_ino)) + *err = 0; + UFSD(("EXIT\n")) + return inode; + +failed: + unlock_super (sb); + iput (inode); + UFSD(("EXIT (FAILED)\n")) + return NULL; +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/inode.c linux/fs/ufs/inode.c --- v2.1.111/linux/fs/ufs/inode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/inode.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,665 @@ +/* + * linux/ufs/ufs/inode.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/inode.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_INODE_DEBUG +#undef UFS_INODE_DEBUG_MORE + +#ifdef UFS_INODE_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +#ifdef UFS_INODE_DEBUG_MORE +static void ufs_print_inode(struct inode * inode) +{ + unsigned swab = inode->i_sb->u.ufs_sb.s_swab; + printk("ino %lu mode 0%6.6o nlink %d uid %d gid %d" + " size %lu blocks %lu\n", + inode->i_ino, inode->i_mode, inode->i_nlink, + inode->i_uid,inode->i_gid, inode->i_size, inode->i_blocks); + printk(" db <%u %u %u %u %u %u %u %u %u %u %u %u>\n", + SWAB32(inode->u.ufs_i.i_u1.i_data[0]), + SWAB32(inode->u.ufs_i.i_u1.i_data[1]), + SWAB32(inode->u.ufs_i.i_u1.i_data[2]), + SWAB32(inode->u.ufs_i.i_u1.i_data[3]), + SWAB32(inode->u.ufs_i.i_u1.i_data[4]), + SWAB32(inode->u.ufs_i.i_u1.i_data[5]), + SWAB32(inode->u.ufs_i.i_u1.i_data[6]), + SWAB32(inode->u.ufs_i.i_u1.i_data[7]), + SWAB32(inode->u.ufs_i.i_u1.i_data[8]), + SWAB32(inode->u.ufs_i.i_u1.i_data[9]), + SWAB32(inode->u.ufs_i.i_u1.i_data[10]), + SWAB32(inode->u.ufs_i.i_u1.i_data[11])); + printk(" gen %u ib <%u %u %u>\n", + inode->u.ufs_i.i_gen, + SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]), + SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]), + SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK])); +} +#endif + +#define ufs_inode_bmap(inode, nr) \ + (SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask)) + +static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr, + struct ufs_sb_private_info * uspi, unsigned swab) +{ + unsigned tmp; + + UFSD(("ENTER, nr %u\n", nr)) + if (!bh) + return 0; + tmp = SWAB32(((u32 *) bh->b_data)[nr >> uspi->s_fpbshift]) + (nr & uspi->s_fpbmask); + brelse (bh); + UFSD(("EXIT, resutl %u\n", tmp)) + return tmp; +} + +int ufs_bmap (struct inode * inode, int fragment) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + unsigned tmp; + unsigned swab; + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + swab = sb->u.ufs_sb.s_swab; + + UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment)) + + if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) { + ufs_warning (sb, "ufs_bmap", "block > big"); + return 0; + } + + /* + * direct fragment + */ + if (fragment < UFS_NDIR_FRAGMENT) + return ufs_inode_bmap (inode, fragment); + + /* + * indirect fragment + */ + fragment -= UFS_NDIR_FRAGMENT; + if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) { + tmp = ufs_inode_bmap (inode, + UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift)); + if (!tmp) + return 0; + return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + fragment & uspi->s_apbmask, uspi, swab); + } + + /* + * dindirect fragment + */ + fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); + if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) { + tmp = ufs_inode_bmap (inode, + UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift)); + if (!tmp) + return 0; + tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab); + if (!tmp) + return 0; + return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + fragment & uspi->s_apbmask, uspi, swab); + } + + /* + * tindirect fragment + */ + fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); + tmp = ufs_inode_bmap (inode, + UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift)); + if (!tmp) + return 0; + tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + (fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab); + if (!tmp) + return 0; + tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab); + if (!tmp) + return 0; + return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), + fragment & uspi->s_apbmask, uspi, swab); +} + +static struct buffer_head * ufs_inode_getfrag (struct inode * inode, + unsigned fragment, unsigned new_fragment, int create, + unsigned required, int * err ) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * result; + unsigned long limit; + unsigned block, blockoff, lastfrag, lastblock, lastblockoff; + unsigned tmp, goal; + u32 * p, * p2; + unsigned swab; + + UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n", + inode->i_ino, fragment, new_fragment, required)) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + block = ufs_fragstoblks (fragment); + blockoff = ufs_fragnum (fragment); + p = inode->u.ufs_i.i_u1.i_data + block; + goal = 0; + +repeat: + tmp = SWAB32(*p); + lastfrag = inode->u.ufs_i.i_lastfrag; + if (tmp && fragment < lastfrag) { + result = getblk (sb->s_dev, tmp + blockoff, sb->s_blocksize); + if (tmp == SWAB32(*p)) { + UFSD(("EXIT, result %u\n", tmp + blockoff)) + return result; + } + brelse (result); + goto repeat; + } + *err = -EFBIG; + if (!create) + return NULL; + limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + if (limit < RLIM_INFINITY) { + limit >>= sb->s_blocksize_bits; + if (new_fragment >= limit) { + send_sig(SIGXFSZ, current, 0); + return NULL; + } + } + lastblock = ufs_fragstoblks (lastfrag); + lastblockoff = ufs_fragnum (lastfrag); + /* + * We will extend file into new block beyond last allocated block + */ + if (lastblock < block) { + /* + * We must reallocate last allocated block + */ + if (lastblockoff) { + p2 = inode->u.ufs_i.i_u1.i_data + lastblock; + tmp = ufs_new_fragments (inode, p2, lastfrag, + SWAB32(*p2), uspi->s_fpb - lastblockoff, err); + if (!tmp) { + if (lastfrag != inode->u.ufs_i.i_lastfrag) + goto repeat; + else + return NULL; + } + lastfrag = inode->u.ufs_i.i_lastfrag; + + } + goal = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock]) + uspi->s_fpb; + tmp = ufs_new_fragments (inode, p, fragment - blockoff, + goal, required + blockoff, err); + } + /* + * We will extend last allocated block + */ + else if (lastblock == block) { + tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff), + SWAB32(*p), required + (blockoff - lastblockoff), err); + } + /* + * We will allocated new block before last allocat block + */ + else /* (lastblock > block) */ { + if (lastblock && (tmp = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock-1]))) + goal = tmp + uspi->s_fpb; + tmp = ufs_new_fragments (inode, p, fragment - blockoff, + goal, uspi->s_fpb, err); + } + if (!tmp) { + if ((!blockoff && SWAB32(*p)) || + (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag)) + goto repeat; + else + return NULL; + } + result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize); + inode->i_ctime = CURRENT_TIME; + if (IS_SYNC(inode)) + ufs_sync_inode (inode); + mark_inode_dirty(inode); + UFSD(("EXIT, result %u\n", tmp + blockoff)) + return result; +} + +static struct buffer_head * ufs_block_getfrag (struct inode * inode, + struct buffer_head * bh, unsigned fragment, unsigned new_fragment, + int create, unsigned blocksize, int * err) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * result; + unsigned tmp, goal, block, blockoff; + u32 * p; + unsigned swab; + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + block = ufs_fragstoblks (fragment); + blockoff = ufs_fragnum (fragment); + + UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment)) + + if (!bh) + return NULL; + if (!buffer_uptodate(bh)) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) { + brelse (bh); + return NULL; + } + } + + p = (u32 *) bh->b_data + block; +repeat: + tmp = SWAB32(*p); + if (tmp) { + result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize); + if (tmp == SWAB32(*p)) { + brelse (bh); + UFSD(("EXIT, result %u\n", tmp + blockoff)) + return result; + } + brelse (result); + goto repeat; + } + if (!create || new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize)) { + brelse (bh); + *err = -EFBIG; + return NULL; + } + if (block && (tmp = SWAB32(((u32*)bh->b_data)[block-1]) + uspi->s_fpb)) + goal = tmp + uspi->s_fpb; + else + goal = bh->b_blocknr + uspi->s_fpb; + tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err); + if (!tmp) { + if (SWAB32(*p)) { + printk("REPEAT\n"); + goto repeat; + } + else { + return NULL; + } + } + result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize); + mark_buffer_dirty(bh, 1); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + brelse (bh); + UFSD(("EXIT, resutl %u\n", tmp + blockoff)) + return result; +} + +struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment, + int create, int * err) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * bh; + unsigned f; + unsigned swab; + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + swab = sb->u.ufs_sb.s_swab; + *err = -EIO; + + UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment)) + if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) { + ufs_warning (sb, "ufs_getblk", "block > big"); + return NULL; + } + + *err = -ENOSPC; + f = fragment; + + /* + * Direct fragment + */ + if (fragment < UFS_NDIR_FRAGMENT) + return ufs_inode_getfrag (inode, fragment, fragment, create, 1, err); + /* + * Indirect fragment + */ + fragment -= UFS_NDIR_FRAGMENT; + if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) { + bh = ufs_inode_getfrag (inode, + UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift), + f, create, uspi->s_fpb, err); + return ufs_block_getfrag (inode, bh, + fragment & uspi->s_apbmask, + f, create, sb->s_blocksize, err); + } + /* + * Dindirect fragment + */ + fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); + if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) { + bh = ufs_inode_getfrag (inode, + UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift), + f, create, uspi->s_fpb, err); + bh = ufs_block_getfrag (inode, bh, + (fragment >> uspi->s_apbshift) & uspi->s_apbmask, + f, create, sb->s_blocksize, err); + return ufs_block_getfrag (inode, bh, + fragment & uspi->s_apbmask, + f, create, sb->s_blocksize, err); + } + /* + * Tindirect fragment + */ + fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); + bh = ufs_inode_getfrag (inode, + UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift), + f, create, uspi->s_fpb, err); + bh = ufs_block_getfrag (inode, bh, + (fragment >> uspi->s_2apbshift) & uspi->s_apbmask, + f, create, sb->s_blocksize, err); + bh = ufs_block_getfrag (inode, bh, + (fragment >> uspi->s_apbshift) & uspi->s_apbmask, + f, create, sb->s_blocksize, err); + return ufs_block_getfrag (inode, bh, + fragment & uspi->s_apbmask, + f, create, sb->s_blocksize, err); +} + + + +struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment, + int create, int * err) +{ + struct buffer_head * bh; + + UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment)) + bh = ufs_getfrag (inode, fragment, create, err); + if (!bh || buffer_uptodate(bh)) + return bh; + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (buffer_uptodate(bh)) + return bh; + brelse (bh); + *err = -EIO; + return NULL; +} + +void ufs_read_inode (struct inode * inode) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_inode * ufs_inode; + struct buffer_head * bh; + unsigned i; + unsigned flags, swab; + + UFSD(("ENTER, ino %lu\n", inode->i_ino)) + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + + if (inode->i_ino < UFS_ROOTINO || + inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { + ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); + return; + } + + bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize); + if (!bh) { + ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); + return; + } + ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino)); + + /* + * Copy data to the in-core inode. + */ + inode->i_mode = SWAB16(ufs_inode->ui_mode); + inode->i_nlink = SWAB16(ufs_inode->ui_nlink); + if (inode->i_nlink == 0) + ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); + + /* + * Linux has only 16-bit uid and gid, so we can't support EFT. + * Files are dynamically chown()ed to root. + */ + inode->i_uid = ufs_uid(ufs_inode); + if (inode->i_uid == UFS_USEEFT) { + inode->i_uid = 0; + } + if (inode->i_gid == UFS_USEEFT) { + inode->i_gid = 0; + } + + /* + * Linux i_size can be 32 on some architektures. We will mark + * big files as read only and let user access first 32 bits. + */ + inode->u.ufs_i.i_size = SWAB64(ufs_inode->ui_size); + inode->i_size = (off_t) inode->u.ufs_i.i_size; + if (sizeof(off_t) == 4 && (inode->u.ufs_i.i_size >> 32)) + inode->i_size = (__u32)-1; + + inode->i_atime = SWAB32(ufs_inode->ui_atime.tv_sec); + inode->i_ctime = SWAB32(ufs_inode->ui_ctime.tv_sec); + inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec); + inode->i_blocks = SWAB32(ufs_inode->ui_blocks); + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat) */ + inode->i_version = ++event; + + inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags); + inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen); + inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow); + inode->u.ufs_i.i_uid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_uid); + inode->u.ufs_i.i_gid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_gid); + inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag); + inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize); + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = to_kdev_t(SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0])); + else if (inode->i_blocks) { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) + inode->u.ufs_i.i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i]; + } + else { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) + inode->u.ufs_i.i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i]; + } + + brelse (bh); + + inode->i_op = NULL; + + if (S_ISREG(inode->i_mode)) + inode->i_op = &ufs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &ufs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ufs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISSOCK(inode->i_mode)) + ; /* nothing */ + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + +#ifdef UFS_INODE_DEBUG_MORE + ufs_print_inode (inode); +#endif + UFSD(("EXIT\n")) +} + +static int ufs_update_inode(struct inode * inode, int do_sync) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * bh; + struct ufs_inode * ufs_inode; + unsigned i; + unsigned swab; + + UFSD(("ENTER, ino %lu\n", inode->i_ino)) + + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + swab = sb->u.ufs_sb.s_swab; + + if (inode->i_ino < UFS_ROOTINO || + inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { + ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); + return -1; + } + + bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize); + if (!bh) { + ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); + return -1; + } + ufs_inode = (struct ufs_inode *) (bh->b_data + ufs_inotofsbo(inode->i_ino) * sizeof(struct ufs_inode)); + + ufs_inode->ui_mode = SWAB16(inode->i_mode); + ufs_inode->ui_nlink = SWAB16(inode->i_nlink); + + if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT) { + ufs_inode->ui_u3.ui_sun.ui_uid = SWAB32(inode->u.ufs_i.i_uid); + ufs_inode->ui_u1.oldids.ui_suid = (__u16)ufs_inode->ui_u3.ui_sun.ui_uid; + } + else { + ufs_inode->ui_u1.oldids.ui_suid = SWAB16(inode->i_uid); + ufs_inode->ui_u3.ui_sun.ui_uid = (__u32) ufs_inode->ui_u1.oldids.ui_suid; + } + if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT) { + ufs_inode->ui_u3.ui_sun.ui_gid = SWAB32(inode->u.ufs_i.i_gid); + ufs_inode->ui_u1.oldids.ui_sgid = (__u16)ufs_inode->ui_u3.ui_sun.ui_gid; + } + else { + ufs_inode->ui_u1.oldids.ui_sgid = SWAB16(inode->i_gid); + ufs_inode->ui_u3.ui_sun.ui_gid = (__u32) ufs_inode->ui_u1.oldids.ui_sgid; + } + + ufs_inode->ui_size = SWAB64((u64)inode->i_size); + ufs_inode->ui_atime.tv_sec = SWAB32(inode->i_atime); + ufs_inode->ui_atime.tv_usec = SWAB32(0); + ufs_inode->ui_ctime.tv_sec = SWAB32(inode->i_ctime); + ufs_inode->ui_ctime.tv_usec = SWAB32(0); + ufs_inode->ui_mtime.tv_sec = SWAB32(inode->i_mtime); + ufs_inode->ui_mtime.tv_usec = SWAB32(0); + ufs_inode->ui_blocks = SWAB32(inode->i_blocks); + + ufs_inode->ui_flags = SWAB32(inode->u.ufs_i.i_flags); + ufs_inode->ui_gen = SWAB32(inode->u.ufs_i.i_gen); + ufs_inode->ui_u3.ui_sun.ui_shadow = SWAB32(inode->u.ufs_i.i_shadow); + ufs_inode->ui_u3.ui_sun.ui_oeftflag = SWAB32(inode->u.ufs_i.i_oeftflag); + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + ufs_inode->ui_u2.ui_addr.ui_db[0] = SWAB32(kdev_t_to_nr(inode->i_rdev)); + else if (inode->i_blocks) { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) + ufs_inode->ui_u2.ui_addr.ui_db[i] = inode->u.ufs_i.i_u1.i_data[i]; + } + else { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) + ufs_inode->ui_u2.ui_symlink[i] = inode->u.ufs_i.i_u1.i_symlink[i]; + } + + if (!inode->i_nlink) + memset (ufs_inode, 0, sizeof(struct ufs_inode)); + + mark_buffer_dirty(bh, 1); + if (do_sync) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + + UFSD(("EXIT\n")) + return 0; +} + +void ufs_write_inode (struct inode * inode) +{ + ufs_update_inode (inode, 0); +} + +int ufs_sync_inode (struct inode *inode) +{ + return ufs_update_inode (inode, 1); +} + +void ufs_put_inode (struct inode * inode) +{ + UFSD(("ENTER & EXIT\n")) +} + +void ufs_delete_inode (struct inode * inode) +{ + /*inode->u.ufs_i.i_dtime = CURRENT_TIME;*/ + mark_inode_dirty(inode); + ufs_update_inode(inode, IS_SYNC(inode)); + inode->i_size = 0; + if (inode->i_blocks) + ufs_truncate (inode); + ufs_free_inode (inode); +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/namei.c linux/fs/ufs/namei.c --- v2.1.111/linux/fs/ufs/namei.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/namei.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,1147 @@ +/* + * linux/fs/ufs/namei.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/namei.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_NAMEI_DEBUG + +#ifdef UFS_NAMEI_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + +/* + * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure. + */ +static int ufs_match (int len, const char * const name, + struct ufs_dir_entry * de, unsigned flags, unsigned swab) +{ + if (!de || !SWAB32(de->d_ino) || len > UFS_MAXNAMLEN) + return 0; + /* + * "" means "." ---> so paths like "/usr/lib//libc.a" work + */ + if (!len && ufs_namlen(de) == 1 && (de->d_name[0] == '.') && + (de->d_name[1] == '\0')) + return 1; + if (len != ufs_namlen(de)) + return 0; + return !memcmp(name, de->d_name, len); +} + +/* + * ufs_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * ufs_find_entry (struct inode * dir, + const char * const name, int namelen, struct ufs_dir_entry ** res_dir) +{ + struct super_block * sb; + struct buffer_head * bh_use[NAMEI_RA_SIZE]; + struct buffer_head * bh_read[NAMEI_RA_SIZE]; + unsigned long offset; + int block, toread, i, err; + unsigned flags, swab; + + UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen)) + + *res_dir = NULL; + if (!dir) + return NULL; + + sb = dir->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + + if (namelen > UFS_MAXNAMLEN) + return NULL; + + memset (bh_use, 0, sizeof (bh_use)); + toread = 0; + for (block = 0; block < NAMEI_RA_SIZE; ++block) { + struct buffer_head * bh; + + if ((block << sb->s_blocksize_bits) >= dir->i_size) + break; + bh = ufs_getfrag (dir, block, 0, &err); + bh_use[block] = bh; + if (bh && !buffer_uptodate(bh)) + bh_read[toread++] = bh; + } + + for (block = 0, offset = 0; offset < dir->i_size; block++) { + struct buffer_head * bh; + struct ufs_dir_entry * de; + char * dlimit; + + if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { + ll_rw_block (READ, toread, bh_read); + toread = 0; + } + bh = bh_use[block % NAMEI_RA_SIZE]; + if (!bh) { + ufs_error (sb, "ufs_find_entry", + "directory #%lu contains a hole at offset %lu", dir->i_ino, offset); + offset += sb->s_blocksize; + continue; + } + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) { + /* + * read error: all bets are off + */ + break; + } + + de = (struct ufs_dir_entry *) bh->b_data; + dlimit = bh->b_data + sb->s_blocksize; + while ((char *) de < dlimit && offset < dir->i_size) { + if (!ufs_check_dir_entry ("ufs_find_entry", dir, de, bh, offset)) + goto failed; + if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) { + for (i = 0; i < NAMEI_RA_SIZE; ++i) { + if (bh_use[i] != bh) + brelse (bh_use[i]); + } + *res_dir = de; + UFSD(("EXIT\n")) + return bh; + } + offset += SWAB16(de->d_reclen); + de = (struct ufs_dir_entry *) + ((char *) de + SWAB16(de->d_reclen)); + } + + brelse (bh); + if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >= + dir->i_size) + bh = NULL; + else + bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err); + bh_use[block % NAMEI_RA_SIZE] = bh; + if (bh && !buffer_uptodate(bh)) + bh_read[toread++] = bh; + } + +failed: + for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]); + UFSD(("EXIT (FAILED)\n")) + return NULL; +} + +int ufs_lookup(struct inode * dir, struct dentry *dentry) +{ + struct super_block * sb; + struct inode * inode; + struct ufs_dir_entry * de; + struct buffer_head * bh; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + + if (dentry->d_name.len > UFS_MAXNAMLEN) + return -ENAMETOOLONG; + + bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + inode = NULL; + if (bh) { + unsigned long ino = SWAB32(de->d_ino); + brelse (bh); + inode = iget(sb, ino); + if (!inode) + return -EACCES; + } + d_add(dentry, inode); + UFSD(("EXIT\n")) + return 0; +} + +/* + * ufs_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ufs_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * ufs_add_entry (struct inode * dir, + const char * name, int namelen, struct ufs_dir_entry ** res_dir, + int *err ) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + unsigned long offset; + unsigned fragoff; + unsigned short rec_len; + struct buffer_head * bh; + struct ufs_dir_entry * de, * de1; + unsigned flags, swab; + + UFSD(("ENTER, name %s, namelen %u\n", name, namelen)) + + *err = -EINVAL; + *res_dir = NULL; + if (!dir || !dir->i_nlink) + return NULL; + + sb = dir->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + + if (namelen > UFS_MAXNAMLEN) + { + *err = -ENAMETOOLONG; + return NULL; + } + + if (!namelen) + return NULL; + /* + * Is this a busy deleted directory? Can't create new files if so + */ + if (dir->i_size == 0) + { + *err = -ENOENT; + return NULL; + } + bh = ufs_bread (dir, 0, 0, err); + if (!bh) + return NULL; + rec_len = UFS_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ufs_dir_entry *) bh->b_data; + *err = -ENOSPC; + while (1) { + if ((char *)de >= SECTOR_SIZE + bh->b_data) { + fragoff = offset & ~uspi->s_fmask; + if (fragoff != 0 && fragoff != SECTOR_SIZE) + ufs_error (sb, "ufs_add_entry", "internal error" + " fragoff %u", fragoff); + if (!fragoff) { + brelse (bh); + bh = NULL; + bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, err); + } + if (!bh) + return NULL; + if (dir->i_size <= offset) { + if (dir->i_size == 0) { + *err = -ENOENT; + return NULL; + } + de = (struct ufs_dir_entry *) (bh->b_data + fragoff); + de->d_ino = SWAB32(0); + de->d_reclen = SWAB16(SECTOR_SIZE); + de->d_u.d_namlen = SWAB16(0); + dir->i_size = offset + SECTOR_SIZE; + mark_inode_dirty(dir); + } else { + de = (struct ufs_dir_entry *) bh->b_data; + } + } + if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) { + *err = -ENOENT; + brelse (bh); + return NULL; + } + if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) { + *err = -EEXIST; + brelse (bh); + return NULL; + } + if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) || + (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)) + rec_len)) { + offset += SWAB16(de->d_reclen); + if (SWAB32(de->d_ino)) { + de1 = (struct ufs_dir_entry *) ((char *) de + + UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen))); + de1->d_reclen = SWAB16(SWAB16(de->d_reclen) - + UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen))); + de->d_reclen = SWAB16(UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen))); + de = de1; + } + de->d_ino = SWAB32(0); + de->d_u.d_namlen = SWAB16(namelen); + memcpy (de->d_name, name, namelen + 1); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * ufs_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + *res_dir = de; + *err = 0; + + UFSD(("EXIT\n")) + return bh; + } + offset += SWAB16(de->d_reclen); + de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen)); + } + brelse (bh); + UFSD(("EXIT (FAILED)\n")) + return NULL; +} + +/* + * ufs_delete_entry deletes a directory entry by merging it with the + * previous entry. + */ +static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir, + struct buffer_head * bh ) + +{ + struct super_block * sb; + struct ufs_dir_entry * de, * pde; + unsigned i; + unsigned flags, swab; + + UFSD(("ENTER\n")) + + sb = inode->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + i = 0; + pde = NULL; + de = (struct ufs_dir_entry *) bh->b_data; + + UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino), + SWAB16(de->d_reclen), ufs_namlen(de), de->d_name)) + + while (i < bh->b_size) { + if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) + return -EIO; + if (de == dir) { + if (pde) + pde->d_reclen = + SWAB16(SWAB16(pde->d_reclen) + + SWAB16(dir->d_reclen)); + dir->d_ino = SWAB32(0); + UFSD(("EXIT\n")) + return 0; + } + i += SWAB16(de->d_reclen); + if (i == SECTOR_SIZE) pde = NULL; + else pde = de; + de = (struct ufs_dir_entry *) + ((char *) de + SWAB16(de->d_reclen)); + if (i == SECTOR_SIZE && SWAB16(de->d_reclen) == 0) + break; + } + UFSD(("EXIT\n")) + return -ENOENT; +} + +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +int ufs_create (struct inode * dir, struct dentry * dentry, int mode) +{ + struct super_block * sb; + struct inode * inode; + struct buffer_head * bh; + struct ufs_dir_entry * de; + int err = -EIO; + unsigned swab; + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + + /* + * N.B. Several error exits in ufs_new_inode don't set err. + */ + UFSD(("ENTER\n")) + + inode = ufs_new_inode (dir, mode, &err); + if (!inode) + return err; + inode->i_op = &ufs_file_inode_operations; + inode->i_mode = mode; + mark_inode_dirty(inode); + bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) { + inode->i_nlink--; + mark_inode_dirty(inode); + iput (inode); + return err; + } + de->d_ino = SWAB32(inode->i_ino); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + d_instantiate(dentry, inode); + + UFSD(("EXIT\n")) + + return 0; +} + +int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) +{ + struct super_block * sb; + struct inode * inode; + struct buffer_head * bh; + struct ufs_dir_entry * de; + int err = -EIO; + unsigned swab; + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + + err = -ENAMETOOLONG; + if (dentry->d_name.len > UFS_MAXNAMLEN) + goto out; + + inode = ufs_new_inode (dir, mode, &err); + if (!inode) + goto out; + + inode->i_uid = current->fsuid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &ufs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ufs_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ufs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = to_kdev_t(rdev); + mark_inode_dirty(inode); + bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) + goto out_no_entry; + de->d_ino = SWAB32(inode->i_ino); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + d_instantiate(dentry, inode); + brelse(bh); + err = 0; +out: + return err; + +out_no_entry: + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + goto out; +} + +int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + struct super_block * sb; + struct inode * inode; + struct buffer_head * bh, * dir_block; + struct ufs_dir_entry * de; + int err; + unsigned swab; + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + + err = -ENAMETOOLONG; + if (dentry->d_name.len > UFS_MAXNAMLEN) + goto out; + + err = -EMLINK; + if (dir->i_nlink >= UFS_LINK_MAX) + goto out; + err = -EIO; + inode = ufs_new_inode (dir, S_IFDIR, &err); + if (!inode) + goto out; + + inode->i_op = &ufs_dir_inode_operations; + inode->i_size = SECTOR_SIZE; + dir_block = ufs_bread (inode, 0, 1, &err); + if (!dir_block) { + inode->i_nlink--; /* is this nlink == 0? */ + mark_inode_dirty(inode); + iput (inode); + return err; + } + inode->i_blocks = sb->s_blocksize / SECTOR_SIZE; + de = (struct ufs_dir_entry *) dir_block->b_data; + de->d_ino = SWAB32(inode->i_ino); + de->d_u.d_namlen = SWAB16(1); + de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1)); + strcpy (de->d_name, "."); + de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen)); + de->d_ino = SWAB32(dir->i_ino); + de->d_reclen = SWAB16(SECTOR_SIZE - UFS_DIR_REC_LEN(1)); + de->d_u.d_namlen = SWAB16(2); + strcpy (de->d_name, ".."); + inode->i_nlink = 2; + mark_buffer_dirty(dir_block, 1); + brelse (dir_block); + inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + mark_inode_dirty(inode); + bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) + goto out_no_entry; + de->d_ino = SWAB32(inode->i_ino); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + dir->i_nlink++; + mark_inode_dirty(dir); + d_instantiate(dentry, inode); + brelse (bh); + err = 0; +out: + return err; + +out_no_entry: + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput (inode); + goto out; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int ufs_empty_dir (struct inode * inode) +{ + struct super_block * sb; + unsigned long offset; + struct buffer_head * bh; + struct ufs_dir_entry * de, * de1; + int err; + unsigned swab; + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + + if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) || + !(bh = ufs_bread (inode, 0, 0, &err))) { + ufs_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no data block", + inode->i_ino); + return 1; + } + de = (struct ufs_dir_entry *) bh->b_data; + de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen)); + if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) || + strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) { + ufs_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no `.' or `..'", + inode->i_ino); + return 1; + } + offset = SWAB16(de->d_reclen) + SWAB16(de1->d_reclen); + de = (struct ufs_dir_entry *) ((char *) de1 + SWAB16(de1->d_reclen)); + while (offset < inode->i_size ) { + if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { + brelse (bh); + bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err); + if (!bh) { + ufs_error (sb, "empty_dir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, offset); + offset += sb->s_blocksize; + continue; + } + de = (struct ufs_dir_entry *) bh->b_data; + } + if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) { + brelse (bh); + return 1; + } + if (SWAB32(de->d_ino)) { + brelse (bh); + return 0; + } + offset += SWAB16(de->d_reclen); + de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen)); + } + brelse (bh); + return 1; +} + +int ufs_rmdir (struct inode * dir, struct dentry *dentry) +{ + struct super_block *sb; + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ufs_dir_entry * de; + unsigned swab; + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + + UFSD(("ENTER\n")) + + retval = -ENAMETOOLONG; + if (dentry->d_name.len > UFS_MAXNAMLEN) + goto out; + + retval = -ENOENT; + bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + if (!bh) + goto end_rmdir; + + inode = dentry->d_inode; + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize (inode, -1); + + retval = -EPERM; + if ((dir->i_mode & S_ISVTX) && + current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + + retval = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) + goto end_rmdir; + + retval = -EIO; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (SWAB32(de->d_ino) != inode->i_ino) + goto end_rmdir; + + down(&inode->i_sem); + /* + * Prune any child dentries so that this dentry becomes negative. + */ + if (dentry->d_count > 1) { + ufs_warning (sb, "ufs_rmdir", "d_count=%d, pruning\n", dentry->d_count); + shrink_dcache_parent(dentry); + } + if (!ufs_empty_dir (inode)) + retval = -ENOTEMPTY; + else if (SWAB32(de->d_ino) != inode->i_ino) + retval = -ENOENT; + else { + if (dentry->d_count > 1) { + /* + * Are we deleting the last instance of a busy directory? + * Better clean up if so. + * + * Make directory empty (it will be truncated when finally + * dereferenced). This also inhibits ufs_add_entry. + */ + inode->i_size = 0; + } + retval = ufs_delete_entry (dir, de, bh); + dir->i_version = ++event; + } + up(&inode->i_sem); + if (retval) + goto end_rmdir; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + if (inode->i_nlink != 2) + ufs_warning (inode->i_sb, "ufs_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); + inode->i_version = ++event; + inode->i_nlink = 0; + mark_inode_dirty(inode); + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(dir); + d_delete(dentry); + +end_rmdir: + brelse (bh); +out: + UFSD(("EXIT\n")) + + return retval; +} + +int ufs_unlink(struct inode * dir, struct dentry *dentry) +{ + struct super_block * sb; + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ufs_dir_entry * de; + unsigned flags, swab; + + sb = dir->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + + retval = -ENAMETOOLONG; + if (dentry->d_name.len > UFS_MAXNAMLEN) + goto out; + + retval = -ENOENT; + bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + UFSD(("de: ino %u, reclen %u, namelen %u, name %s\n", SWAB32(de->d_ino), + SWAB16(de->d_reclen), ufs_namlen(de), de->d_name)) + if (!bh) + goto end_unlink; + + inode = dentry->d_inode; + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize (inode, -1); + + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + goto end_unlink; + if ((dir->i_mode & S_ISVTX) && + current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) + goto end_unlink; + + retval = -EIO; + if (SWAB32(de->d_ino) != inode->i_ino) + goto end_unlink; + + if (!inode->i_nlink) { + ufs_warning (inode->i_sb, "ufs_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ufs_delete_entry (dir, de, bh); + if (retval) + goto end_unlink; + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(dir); + inode->i_nlink--; + mark_inode_dirty(inode); + inode->i_ctime = dir->i_ctime; + retval = 0; + d_delete(dentry); /* This also frees the inode */ + +end_unlink: + brelse (bh); +out: + return retval; +} + + +int ufs_link (struct dentry * old_dentry, struct inode * dir, + struct dentry *dentry) +{ + struct super_block * sb; + struct inode *inode = old_dentry->d_inode; + struct ufs_dir_entry * de; + struct buffer_head * bh; + int err; + unsigned swab; + + inode = old_dentry->d_inode; + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return -EPERM; + + if (inode->i_nlink >= UFS_LINK_MAX) + return -EMLINK; + + bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) + return err; + + de->d_ino = SWAB32(inode->i_ino); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + inode->i_nlink++; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + inode->i_count++; + d_instantiate(dentry, inode); + return 0; +} + +/* + * Create symbolic link. We use only slow symlinks at this time. + */ +int ufs_symlink (struct inode * dir, struct dentry * dentry, + const char * symname) +{ + struct super_block * sb; + struct ufs_dir_entry * de; + struct inode * inode; + struct buffer_head * bh, * name_block; + char * link; + unsigned i, l; + int err; + char c; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = dir->i_sb; + swab = sb->u.ufs_sb.s_swab; + bh = name_block = NULL; + err = -EIO; + + if (!(inode = ufs_new_inode (dir, S_IFLNK, &err))) { + return err; + } + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_op = &ufs_symlink_inode_operations; + for (l = 0; l < sb->s_blocksize - 1 && symname [l]; l++); + + /***if (l >= sizeof (inode->u.ufs_i.i_data)) {***/ + if (1) { + /* slow symlink */ + name_block = ufs_bread (inode, 0, 1, &err); + if (!name_block) { + inode->i_nlink--; + mark_inode_dirty(inode); + iput (inode); + return err; + } + link = name_block->b_data; + + } else { + /* fast symlink */ + link = (char *) inode->u.ufs_i.i_u1.i_data; + } + i = 0; + while (i < sb->s_blocksize - 1 && (c = *(symname++))) + link[i++] = c; + link[i] = 0; + if (name_block) { + mark_buffer_dirty(name_block, 1); + brelse (name_block); + } + inode->i_size = i; + mark_inode_dirty(inode); + + bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) + goto out_no_entry; + de->d_ino = SWAB32(inode->i_ino); + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + d_instantiate(dentry, inode); + err = 0; +out: + return err; + +out_no_entry: + inode->i_nlink--; + mark_inode_dirty(inode); + iput (inode); + goto out; +} + + +#define PARENT_INO(buffer) \ + ((struct ufs_dir_entry *) ((char *) buffer + \ + SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino +/* + * rename uses retrying to avoid race-conditions: at least they should be + * minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry, + struct inode * new_dir, struct dentry * new_dentry ) +{ + struct super_block * sb; + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ufs_dir_entry * old_de, * new_de; + int retval; + unsigned flags, swab; + + sb = old_dir->i_sb; + flags = sb->u.ufs_sb.s_flags; + swab = sb->u.ufs_sb.s_swab; + + UFSD(("ENTER\n")) + + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + new_de = NULL; + retval = -ENAMETOOLONG; + if (old_dentry->d_name.len > UFS_MAXNAMLEN) + goto end_rename; + + UFSD(("name %s, len %u\n", old_dentry->d_name.name, old_dentry->d_name.len)) + old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); + UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino), + SWAB16(old_de->d_reclen), ufs_namlen(old_de), old_de->d_name)) + + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = old_dentry->d_inode; + + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->fsuid != old_inode->i_uid && + current->fsuid != old_dir->i_uid && !fsuser()) + goto end_rename; + if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode)) + goto end_rename; + + new_inode = new_dentry->d_inode; + UFSD(("name %s, len %u\n", new_dentry->d_name.name, new_dentry->d_name.len)) + new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); + if (new_bh) { + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } else { + if (new_inode->i_sb->dq_op) + new_inode->i_sb->dq_op->initialize (new_inode, -1); + } + } + retval = 0; + if (new_inode == old_inode) + goto end_rename; + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (is_subdir(new_dentry, old_dentry)) + goto end_rename; + retval = -ENOTEMPTY; + if (!ufs_empty_dir (new_inode)) + goto end_rename; + retval = -EBUSY; + if (new_dentry->d_count > 1) + goto end_rename; + } + retval = -EPERM; + if (new_inode) { + if ((new_dir->i_mode & S_ISVTX) && + current->fsuid != new_inode->i_uid && + current->fsuid != new_dir->i_uid && !fsuser()) + goto end_rename; + if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode)) + goto end_rename; + } + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (is_subdir(new_dentry, old_dentry)) + goto end_rename; + dir_bh = ufs_bread (old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (SWAB32(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= UFS_LINK_MAX) + goto end_rename; + } + + if (!new_bh) + new_bh = ufs_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de, + &retval); + if (!new_bh) + goto end_rename; + new_dir->i_version = ++event; + + /* + * ok, that's it + */ + new_de->d_ino = SWAB32(old_inode->i_ino); + ufs_delete_entry (old_dir, old_de, old_bh); + + old_dir->i_version = ++event; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(new_inode); + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + mark_inode_dirty(old_dir); + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino); + mark_buffer_dirty(dir_bh, 1); + old_dir->i_nlink--; + mark_inode_dirty(old_dir); + if (new_inode) { + new_inode->i_nlink--; + mark_inode_dirty(new_inode); + } else { + new_dir->i_nlink++; + mark_inode_dirty(new_dir); + } + } + mark_buffer_dirty(old_bh, 1); + if (IS_SYNC(old_dir)) { + ll_rw_block (WRITE, 1, &old_bh); + wait_on_buffer (old_bh); + } + + mark_buffer_dirty(new_bh, 1); + if (IS_SYNC(new_dir)) { + ll_rw_block (WRITE, 1, &new_bh); + wait_on_buffer (new_bh); + } + + /* Update the dcache */ + d_move(old_dentry, new_dentry); + retval = 0; +end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + + UFSD(("EXIT\n")) + + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + * + * In the second extended file system, we use a lock flag stored in the memory + * super-block. This way, we really lock other renames only if they occur + * on the same file system + */ +int ufs_rename (struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir, struct dentry *new_dentry ) +{ + int result; + + UFSD(("ENTER\n")) + + while (old_dir->i_sb->u.ufs_sb.s_rename_lock) + sleep_on (&old_dir->i_sb->u.ufs_sb.s_rename_wait); + old_dir->i_sb->u.ufs_sb.s_rename_lock = 1; + result = do_ufs_rename (old_dir, old_dentry, new_dir, new_dentry); + old_dir->i_sb->u.ufs_sb.s_rename_lock = 0; + wake_up (&old_dir->i_sb->u.ufs_sb.s_rename_wait); + + UFSD(("EXIT\n")) + + return result; +} + diff -u --recursive --new-file v2.1.111/linux/fs/ufs/super.c linux/fs/ufs/super.c --- v2.1.111/linux/fs/ufs/super.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/super.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,690 @@ +/* + * linux/fs/ufs/super.c + * + * Copyright (C) 1996 + * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) + * Laboratory for Computer Science Research Computing Facility + * Rutgers, The State University of New Jersey + * + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * + * Kernel module support added on 96/04/26 by + * Stefan Reinauer + * + * Module usage counts added on 96/04/29 by + * Gertjan van Wingerde + * + * Clean swab support on 19970406 by + * Francois-Rene Rideau + * + * 4.4BSD (FreeBSD) support added on February 1st 1998 by + * Niels Kristian Bech Jensen partially based + * on code by Martin von Loewis . + * + * NeXTstep support added on February 5th 1998 by + * Niels Kristian Bech Jensen . + * + * write support Daniel Pirkl 1998 + * + + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + + +#undef UFS_SUPER_DEBUG +#undef UFS_SUPER_DEBUG_MORE + +#ifdef UFS_SUPER_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +#ifdef UFS_SUPER_DEBUG_MORE +/* + * Print contents of ufs_super_block, useful for debuging + */ +void ufs_print_super_stuff(struct ufs_super_block_first * usb1, + struct ufs_super_block_second * usb2, + struct ufs_super_block_third * usb3, unsigned swab) +{ + printk("\nufs_print_super_stuff\n"); + printk("size of usb: %lu\n", sizeof(struct ufs_super_block)); + printk(" magic: 0x%x\n", SWAB32(usb3->fs_magic)); + printk(" sblkno: %u\n", SWAB32(usb1->fs_sblkno)); + printk(" cblkno: %u\n", SWAB32(usb1->fs_cblkno)); + printk(" iblkno: %u\n", SWAB32(usb1->fs_iblkno)); + printk(" dblkno: %u\n", SWAB32(usb1->fs_dblkno)); + printk(" cgoffset: %u\n", SWAB32(usb1->fs_cgoffset)); + printk(" ~cgmask: 0x%x\n", ~SWAB32(usb1->fs_cgmask)); + printk(" size: %u\n", SWAB32(usb1->fs_size)); + printk(" dsize: %u\n", SWAB32(usb1->fs_dsize)); + printk(" ncg: %u\n", SWAB32(usb1->fs_ncg)); + printk(" bsize: %u\n", SWAB32(usb1->fs_bsize)); + printk(" fsize: %u\n", SWAB32(usb1->fs_fsize)); + printk(" frag: %u\n", SWAB32(usb1->fs_frag)); + printk(" fragshift: %u\n", SWAB32(usb1->fs_fragshift)); + printk(" ~fmask: %u\n", ~SWAB32(usb1->fs_fmask)); + printk(" fshift: %u\n", SWAB32(usb1->fs_fshift)); + printk(" sbsize: %u\n", SWAB32(usb1->fs_sbsize)); + printk(" spc: %u\n", SWAB32(usb1->fs_spc)); + printk(" cpg: %u\n", SWAB32(usb1->fs_cpg)); + printk(" ipg: %u\n", SWAB32(usb1->fs_ipg)); + printk(" fpg: %u\n", SWAB32(usb1->fs_fpg)); + printk(" csaddr: %u\n", SWAB32(usb1->fs_csaddr)); + printk(" cssize: %u\n", SWAB32(usb1->fs_cssize)); + printk(" cgsize: %u\n", SWAB32(usb1->fs_cgsize)); + printk(" fstodb: %u\n", SWAB32(usb1->fs_fsbtodb)); + printk(" postblformat: %u\n", SWAB32(usb3->fs_postblformat)); + printk(" nrpos: %u\n", SWAB32(usb3->fs_nrpos)); + printk(" ndir %u\n", SWAB32(usb1->fs_cstotal.cs_ndir)); + printk(" nifree %u\n", SWAB32(usb1->fs_cstotal.cs_nifree)); + printk(" nbfree %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree)); + printk(" nffree %u\n", SWAB32(usb1->fs_cstotal.cs_nffree)); +} + + +/* + * Print contents of ufs_cylinder_group, useful for debuging + */ +void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab) +{ + printk("\nufs_print_cylinder_stuff\n"); + printk("size of ucg: %lu\n", sizeof(struct ufs_cylinder_group)); + printk(" magic: %x\n", SWAB32(cg->cg_magic)); + printk(" time: %u\n", SWAB32(cg->cg_time)); + printk(" cgx: %u\n", SWAB32(cg->cg_cgx)); + printk(" ncyl: %u\n", SWAB16(cg->cg_ncyl)); + printk(" niblk: %u\n", SWAB16(cg->cg_niblk)); + printk(" ndblk: %u\n", SWAB32(cg->cg_ndblk)); + printk(" cs_ndir: %u\n", SWAB32(cg->cg_cs.cs_ndir)); + printk(" cs_nbfree: %u\n", SWAB32(cg->cg_cs.cs_nbfree)); + printk(" cs_nifree: %u\n", SWAB32(cg->cg_cs.cs_nifree)); + printk(" cs_nffree: %u\n", SWAB32(cg->cg_cs.cs_nffree)); + printk(" rotor: %u\n", SWAB32(cg->cg_rotor)); + printk(" frotor: %u\n", SWAB32(cg->cg_frotor)); + printk(" irotor: %u\n", SWAB32(cg->cg_irotor)); + printk(" frsum: %u, %u, %u, %u, %u, %u, %u, %u\n", + SWAB32(cg->cg_frsum[0]), SWAB32(cg->cg_frsum[1]), + SWAB32(cg->cg_frsum[2]), SWAB32(cg->cg_frsum[3]), + SWAB32(cg->cg_frsum[4]), SWAB32(cg->cg_frsum[5]), + SWAB32(cg->cg_frsum[6]), SWAB32(cg->cg_frsum[7])); + printk(" btotoff: %u\n", SWAB32(cg->cg_btotoff)); + printk(" boff: %u\n", SWAB32(cg->cg_boff)); + printk(" iuseoff: %u\n", SWAB32(cg->cg_iusedoff)); + printk(" freeoff: %u\n", SWAB32(cg->cg_freeoff)); + printk(" nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff)); +} +#endif /* UFS_SUPER_DEBUG_MORE */ + +/* + * Called while file system is mounted, read super block + * and create important imtermal structures. + */ +struct super_block * ufs_read_super ( + struct super_block * sb, + void * data, + int silent) +{ + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_super_block_second * usb2; + struct ufs_super_block_third * usb3; + struct ufs_buffer_head * ubh; + unsigned char * base, * space; + unsigned size, blks, i; + unsigned block_size, super_block_size; + unsigned flags, swab; + s64 tmp; + static unsigned offsets[] = {0, 96, 160}; /* different superblock locations */ + + UFSD(("ENTER\n")) + + uspi = NULL; + ubh = NULL; + base = space = NULL; + sb->u.ufs_sb.s_ucg = NULL; + flags = 0; + swab = 0; + + /* sb->s_dev and sb->s_flags are set by our caller + * data is the mystery argument to sys_mount() + * + * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt, + * and s_type when we return. + */ + + MOD_INC_USE_COUNT; + lock_super (sb); + + sb->u.ufs_sb.s_uspi = uspi = + kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); + if (!uspi) + goto failed; + + block_size = BLOCK_SIZE; + super_block_size = BLOCK_SIZE * 2; + + uspi->s_fsize = block_size; + uspi->s_fmask = ~(BLOCK_SIZE - 1); + uspi->s_fshift = BLOCK_SIZE_BITS; + uspi->s_sbsize = super_block_size; + i = 0; + uspi->s_sbbase = offsets[i]; + +again: + set_blocksize (sb->s_dev, block_size); + + /* + * read ufs super block from device + */ + ubh = ubh_bread2 (sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size); + if (!ubh) + goto failed; + + usb1 = ubh_get_usb_first(USPI_UBH); + usb2 = ubh_get_usb_second(USPI_UBH); + usb3 = ubh_get_usb_third(USPI_UBH); + + /* + * Check ufs magic number + */ + if (usb3->fs_magic != UFS_MAGIC) { + switch (le32_to_cpup(&usb3->fs_magic)) { + case UFS_MAGIC: + swab = UFS_LITTLE_ENDIAN; break; + case UFS_CIGAM: + swab = UFS_BIG_ENDIAN; break; + default: + /* + * Try another super block location + */ + if (++i < sizeof(offsets)/sizeof(unsigned)) { + ubh_brelse2(ubh); + ubh = NULL; + uspi->s_sbbase = offsets[i]; + goto again; + } + else { + printk("ufs_read_super: super block loacation not in { 0, 96, 160} or bad magic number\n"); + goto failed; + } + } + } + + /* + * Check block and fragment sizes + */ + uspi->s_bsize = SWAB32(usb1->fs_bsize); + uspi->s_fsize = SWAB32(usb1->fs_fsize); + uspi->s_sbsize = SWAB32(usb1->fs_sbsize); + + if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192) { + printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize); + goto failed; + } + if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) { + printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize); + goto failed; + } + + /* + * Block size is not 1024, set block_size to 512, + * free buffers and read it again + */ + if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) { + ubh_brelse2(ubh); + ubh = NULL; + uspi->s_fmask = SWAB32(usb1->fs_fmask); + uspi->s_fshift = SWAB32(usb1->fs_fshift); + goto again; + } + +#ifdef UFS_SUPER_DEBUG_MORE + ufs_print_super_stuff (usb1, usb2, usb3, swab); +#endif + /* + * Check file system type + */ + flags |= UFS_VANILLA; + /* XXX more consistency check */ + UFSD(("ufs_read_super: maxsymlinklen 0x%8.8x\n", usb3->fs_u.fs_44.fs_maxsymlinklen)) + if (usb3->fs_u.fs_44.fs_maxsymlinklen >= 0) { + if (usb3->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) { + UFSD(("44BSD\n")) + flags |= UFS_44BSD; + sb->s_flags |= MS_RDONLY; + } else { + UFSD(("OLD\n")) + sb->s_flags |= UFS_OLD; /* 4.2BSD */ + } + } else if (uspi->s_sbbase > 0) { + UFSD(("NEXT\n")) + flags |= UFS_NEXT; + sb->s_flags |= MS_RDONLY; + } else { + UFSD(("SUN\n")) + flags |= UFS_SUN; + } + + /* + * Check, if file system was correctly unmounted. + * If not, make it read only. + */ + if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) || + ((flags & UFS_ST_MASK) == UFS_ST_OLD) || + ((flags & UFS_ST_MASK) == UFS_ST_NEXT) || + (((flags & UFS_ST_MASK) == UFS_ST_SUN) && + ufs_state(usb3) == UFS_FSOK - usb1->fs_time)) { + switch(usb1->fs_clean) { + case UFS_FSCLEAN: + UFSD(("fs is clean\n")) + break; + case UFS_FSSTABLE: + UFSD(("fs is stable\n")) + break; + case UFS_FSACTIVE: + printk("ufs_read_super: fs is active\n"); + sb->s_flags |= MS_RDONLY; + break; + case UFS_FSBAD: + printk("ufs_read_super: fs is bad\n"); + sb->s_flags |= MS_RDONLY; + break; + default: + printk("ufs_read_super: can't grok fs_clean 0x%x\n", + usb1->fs_clean); + sb->s_flags |= MS_RDONLY; + break; + } + } else { + printk("ufs_read_super: fs needs fsck\n"); + sb->s_flags |= MS_RDONLY; + } + + sb->s_flags &= ~MS_RDONLY; + /* + * Read ufs_super_block into internal data structures + */ + sb->s_blocksize = SWAB32(usb1->fs_fsize); + sb->s_blocksize_bits = SWAB32(usb1->fs_fshift); + sb->s_op = &ufs_super_ops; + sb->dq_op = 0; /* XXX */ + sb->s_magic = SWAB32(usb3->fs_magic); + + uspi->s_sblkno = SWAB32(usb1->fs_sblkno); + uspi->s_cblkno = SWAB32(usb1->fs_cblkno); + uspi->s_iblkno = SWAB32(usb1->fs_iblkno); + uspi->s_dblkno = SWAB32(usb1->fs_dblkno); + uspi->s_cgoffset = SWAB32(usb1->fs_cgoffset); + uspi->s_cgmask = SWAB32(usb1->fs_cgmask); + uspi->s_size = SWAB32(usb1->fs_size); + uspi->s_dsize = SWAB32(usb1->fs_dsize); + uspi->s_ncg = SWAB32(usb1->fs_ncg); + /* s_bsize already set */ + /* s_fsize already set */ + uspi->s_fpb = SWAB32(usb1->fs_frag); + uspi->s_minfree = SWAB32(usb1->fs_minfree); + uspi->s_bmask = SWAB32(usb1->fs_bmask); + uspi->s_fmask = SWAB32(usb1->fs_fmask); + uspi->s_bshift = SWAB32(usb1->fs_bshift); + uspi->s_fshift = SWAB32(usb1->fs_fshift); + uspi->s_fpbshift = SWAB32(usb1->fs_fragshift); + uspi->s_fsbtodb = SWAB32(usb1->fs_fsbtodb); + /* s_sbsize already set */ + uspi->s_csmask = SWAB32(usb1->fs_csmask); + uspi->s_csshift = SWAB32(usb1->fs_csshift); + uspi->s_nindir = SWAB32(usb1->fs_nindir); + uspi->s_inopb = SWAB32(usb1->fs_inopb); + uspi->s_nspf = SWAB32(usb1->fs_nspf); + uspi->s_npsect = SWAB32(usb1->fs_npsect); + uspi->s_interleave = SWAB32(usb1->fs_interleave); + uspi->s_trackskew = SWAB32(usb1->fs_trackskew); + uspi->s_csaddr = SWAB32(usb1->fs_csaddr); + uspi->s_cssize = SWAB32(usb1->fs_cssize); + uspi->s_cgsize = SWAB32(usb1->fs_cgsize); + uspi->s_ntrak = SWAB32(usb1->fs_ntrak); + uspi->s_nsect = SWAB32(usb1->fs_nsect); + uspi->s_spc = SWAB32(usb1->fs_spc); + uspi->s_ipg = SWAB32(usb1->fs_ipg); + uspi->s_fpg = SWAB32(usb1->fs_fpg); + uspi->s_cpc = SWAB32(usb2->fs_cpc); + ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0]; + ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1]; + uspi->s_qbmask = SWAB64(tmp); + ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0]; + ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1]; + uspi->s_qfmask = SWAB64(tmp); + uspi->s_postblformat = SWAB32(usb3->fs_postblformat); + uspi->s_nrpos = SWAB32(usb3->fs_nrpos); + uspi->s_postbloff = SWAB32(usb3->fs_postbloff); + uspi->s_rotbloff = SWAB32(usb3->fs_rotbloff); + + /* + * Compute another fraquently used values + */ + uspi->s_fpbmask = uspi->s_fpb - 1; + uspi->s_apbshift = uspi->s_bshift - 2; + uspi->s_2apbshift = uspi->s_apbshift * 2; + uspi->s_3apbshift = uspi->s_apbshift * 3; + uspi->s_apb = 1 << uspi->s_apbshift; + uspi->s_2apb = 1 << uspi->s_2apbshift; + uspi->s_3apb = 1 << uspi->s_3apbshift; + uspi->s_apbmask = uspi->s_apb - 1; + uspi->s_nspfshift = uspi->s_fshift - SECTOR_BITS; + uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift; + uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift; + + sb->u.ufs_sb.s_flags = flags; + sb->u.ufs_sb.s_swab = swab; + sb->u.ufs_sb.s_rename_lock = 0; + sb->u.ufs_sb.s_rename_wait = NULL; + + sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL); + + /* + * Read cs structures from (usually) first data block + * on the device. + */ + size = uspi->s_cssize; + blks = howmany(size, uspi->s_fsize); + base = space = kmalloc(size, GFP_KERNEL); + if (!base) + goto failed; + for (i = 0; i < blks; i += uspi->s_fpb) { + size = uspi->s_bsize; + if (i + uspi->s_fpb > blks) + size = (blks - i) * uspi->s_fsize; + ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size); + if (!ubh) + goto failed; + ubh_ubhcpymem (space, ubh, size); + sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space; + space += size; + ubh_brelse (ubh); + ubh = NULL; + } + + /* + * Read cylinder group (we read only first fragment from block + * at this time) and prepare internal data structures for cg caching. + */ + if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL))) + goto failed; + for (i = 0; i < uspi->s_ncg; i++) + sb->u.ufs_sb.s_ucg[i] = NULL; + for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { + sb->u.ufs_sb.s_ucpi[i] = NULL; + sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY; + } + for (i = 0; i < uspi->s_ncg; i++) { + UFSD(("read cg %u\n", i)) + if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize))) + goto failed; + if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data)) + goto failed; +#ifdef UFS_SUPER_DEBUG_MORE + ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab); +#endif + } + for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { + if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) + goto failed; + sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY; + } + sb->u.ufs_sb.s_cg_loaded = 0; + + unlock_super(sb); + UFSD(("EXIT\n")) + return(sb); + +failed: + if (ubh) ubh_brelse2 (ubh); + if (uspi) kfree (uspi); + if (base) kfree (base); + + if (sb->u.ufs_sb.s_ucg) { + for (i = 0; i < uspi->s_ncg; i++) + if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]); + kfree (sb->u.ufs_sb.s_ucg); + for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) + if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]); + } + sb->s_dev = 0; + unlock_super (sb); + MOD_DEC_USE_COUNT; + UFSD(("EXIT (FAILED)\n")) + return(NULL); +} + +/* + * Put super block, release internal structures + */ +void ufs_put_super (struct super_block * sb) +{ + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head * ubh; + unsigned char * base, * space; + unsigned size, blks, i; + + UFSD(("ENTER\n")) + + uspi = sb->u.ufs_sb.s_uspi; + size = uspi->s_cssize; + blks = howmany(size, uspi->s_fsize); + base = space = (char*) sb->u.ufs_sb.s_csp[0]; + for (i = 0; i < blks; i += uspi->s_fpb) { + size = uspi->s_bsize; + if (i + uspi->s_fpb > blks) + size = (blks - i) * uspi->s_fsize; + ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size); + if (!ubh) + goto go_on; + ubh_memcpyubh (ubh, space, size); + space += size; + ubh_mark_buffer_uptodate (ubh, 1); + ubh_mark_buffer_dirty (ubh, 0); + ubh_brelse (ubh); + } + +go_on: + for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { + ufs_put_cylinder (sb, i); + kfree (sb->u.ufs_sb.s_ucpi[i]); + } + for (i = 0; i < uspi->s_ncg; i++) + brelse (sb->u.ufs_sb.s_ucg[i]); + kfree (sb->u.ufs_sb.s_ucg); + kfree (base); + ubh_brelse2 (USPI_UBH); + kfree (sb->u.ufs_sb.s_uspi); + sb->s_dev = 0; + MOD_DEC_USE_COUNT; + return; +} + +/* + * Write super block to device + */ +void ufs_write_super (struct super_block * sb) { + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct ufs_super_block_third * usb3; + unsigned swab; + + UFSD(("ENTER\n")) + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + usb3 = ubh_get_usb_third(USPI_UBH); + + if (!(sb->s_flags & MS_RDONLY)) { + if (SWAB16(usb3->fs_u.fs_sun.fs_state) & UFS_FSOK) + usb3->fs_u.fs_sun.fs_state = SWAB16(SWAB16(usb3->fs_u.fs_sun.fs_state) & ~UFS_FSOK); + usb1->fs_time = SWAB32(CURRENT_TIME); + usb3->fs_u.fs_sun.fs_state = SWAB32(UFS_FSOK - SWAB32(usb1->fs_time)); + ubh_mark_buffer_dirty (USPI_UBH, 1); + } + sb->s_dirt = 0; + UFSD(("EXIT\n")) +} + +/* + * Copy some info about file system to user + */ +int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) +{ + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + struct statfs tmp; + struct statfs *sp = &tmp; + unsigned long used, avail; + unsigned swab; + + UFSD(("ENTER\n")) + + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first (USPI_UBH); + + sp->f_type = UFS_MAGIC; + sp->f_bsize = sb->s_blocksize; + sp->f_blocks = uspi->s_dsize; + sp->f_bfree = (SWAB32(usb1->fs_cstotal.cs_nbfree) << uspi->s_fpbshift )+ + SWAB32(usb1->fs_cstotal.cs_nffree); + + avail = sp->f_blocks - (sp->f_blocks / 100) * uspi->s_minfree; + used = sp->f_blocks - sp->f_bfree; + if (avail > used) + sp->f_bavail = avail - used; + else + sp->f_bavail = 0; + sp->f_files = uspi->s_ncg * uspi->s_ipg; + sp->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree); + sp->f_fsid.val[0] = SWAB32(usb1->fs_id[0]); + sp->f_fsid.val[1] = SWAB32(usb1->fs_id[1]); + sp->f_namelen = UFS_MAXNAMLEN; + + UFSD(("EXIT\n")) + + return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0; +} + + +static char error_buf[1024]; + +void ufs_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n", + kdevname(sb->s_dev), function, error_buf); +} + +void ufs_error (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + va_list args; + + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + + if (!(sb->s_flags & MS_RDONLY)) { + usb1->fs_clean = UFS_FSBAD; + ubh_mark_buffer_dirty(USPI_UBH, 1); + sb->s_dirt = 1; + sb->s_flags |= MS_RDONLY; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n", + kdevname(sb->s_dev), function, error_buf); +} + +void ufs_panic (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + struct ufs_sb_private_info * uspi; + struct ufs_super_block_first * usb1; + va_list args; + + uspi = sb->u.ufs_sb.s_uspi; + usb1 = ubh_get_usb_first(USPI_UBH); + + if (!(sb->s_flags & MS_RDONLY)) { + usb1->fs_clean = UFS_FSBAD; + ubh_mark_buffer_dirty(USPI_UBH, 1); + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + /* this is to prevent panic from syncing this filesystem */ + if (sb->s_lock) + sb->s_lock = 0; + sb->s_flags |= MS_RDONLY; + printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n", + kdevname(sb->s_dev), function, error_buf); +/* panic ("UFS-fs panic (device %s): %s: %s\n", + kdevname(sb->s_dev), function, error_buf); +*/ +} + + +static struct super_operations ufs_super_ops = { + ufs_read_inode, + ufs_write_inode, + ufs_put_inode, + ufs_delete_inode, + NULL, /* notify_change() */ + ufs_put_super, + ufs_write_super, + ufs_statfs, + NULL, /* XXX - ufs_remount() */ +}; + +static struct file_system_type ufs_fs_type = { + "ufs", + FS_REQUIRES_DEV, + ufs_read_super, + NULL +}; + + +int init_ufs_fs(void) +{ + return(register_filesystem(&ufs_fs_type)); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + return init_ufs_fs(); +} + +void cleanup_module(void) +{ + unregister_filesystem(&ufs_fs_type); +} +#endif + diff -u --recursive --new-file v2.1.111/linux/fs/ufs/swab.h linux/fs/ufs/swab.h --- v2.1.111/linux/fs/ufs/swab.h Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/swab.h Sun Jul 26 01:20:22 1998 @@ -0,0 +1,114 @@ +/* + * linux/fs/ufs/ufs_swab.h + * + * Copyright (C) 1997 Francois-Rene Rideau + * Copyright (C) 1998 Jakub Jelinek + */ + +#ifndef _UFS_SWAB_H +#define _UFS_SWAB_H + +/* + * Notes: + * HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes + * in case there are ufs implementations that have strange bytesexes, + * you'll need to modify code here as well as in ufs_super.c and ufs_fs.h + * to support them. + */ + +#include +#include + +/* + * These are only valid inside ufs routines, + * after swab has been initialized to sb->u.ufs_sb.s_swab + */ +#define SWAB16(x) ufs_swab16(swab,x) +#define SWAB32(x) ufs_swab32(swab,x) +#define SWAB64(x) ufs_swab64(swab,x) + +/* + * We often use swabing, when we want to increment/decrement some value, so these + * macros might become handy and increase readability. (Daniel) + */ +#define INC_SWAB16(x) x=ufs_swab16_add(swab,x,1) +#define INC_SWAB32(x) x=ufs_swab32_add(swab,x,1) +#define INC_SWAB64(x) x=ufs_swab64_add(swab,x,1) +#define DEC_SWAB16(x) x=ufs_swab16_add(swab,x,-1) +#define DEC_SWAB32(x) x=ufs_swab32_add(swab,x,-1) +#define DEC_SWAB64(x) x=ufs_swab64_add(swab,x,-1) +#define ADD_SWAB16(x,y) x=ufs_swab16_add(swab,x,y) +#define ADD_SWAB32(x,y) x=ufs_swab32_add(swab,x,y) +#define ADD_SWAB64(x,y) x=ufs_swab64_add(swab,x,y) +#define SUB_SWAB16(x,y) x=ufs_swab16_add(swab,x,-(y)) +#define SUB_SWAB32(x,y) x=ufs_swab32_add(swab,x,-(y)) +#define SUB_SWAB64(x,y) x=ufs_swab64_add(swab,x,-(y)) + +#ifndef __PDP_ENDIAN +extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) { + if (swab) + return swab16(x); + else + return x; +} +extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) { + if (swab) + return swab32(x); + else + return x; +} +extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) { + if (swab) + return swab64(x); + else + return x; +} +extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) { + if (swab) + return swab16(swab16(x)+y); + else + return x + y; +} +extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) { + if (swab) + return swab32(swab32(x)+y); + else + return x + y; +} +extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) { + if (swab) + return swab64(swab64(x)+y); + else + return x + y; +} +#else /* __PDP_ENDIAN */ +extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) { + if (swab & UFS_LITTLE_ENDIAN) + return le16_to_cpu(x); + else + return be16_to_cpu(x); +} +extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) { + if (swab & UFS_LITTLE_ENDIAN) + return le32_to_cpu(x); + else + return be32_to_cpu(x); +} +extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) { + if (swab & UFS_LITTLE_ENDIAN) + return le64_to_cpu(x); + else + return be64_to_cpu(x); +} +extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) { + return ufs_swab16(swab, ufs_swab16(swab, x) + y); +} +extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) { + return ufs_swab32(swab, ufs_swab32(swab, x) + y); +} +extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) { + return ufs_swab64(swab, ufs_swab64(swab, x) + y); +} +#endif /* __PDP_ENDIAN */ + +#endif /* _UFS_SWAB_H */ diff -u --recursive --new-file v2.1.111/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c --- v2.1.111/linux/fs/ufs/symlink.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/symlink.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,138 @@ +/* + * linux/ufs/ufs/symlink.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/symlink.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 symlink handling code + */ + +#include + +#include +#include +#include +#include +#include +#include + + +#undef UFS_SYMLINK_DEBUG + +#ifdef UFS_SYMLINK_DEBUG +#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + + +static struct dentry * ufs_follow_link(struct dentry * dentry, + struct dentry * base) +{ + struct inode * inode; + struct buffer_head * bh; + int error; + char * link; + + UFSD(("ENTER\n")) + + inode = dentry->d_inode; + bh = NULL; + /* slow symlink */ + if (inode->i_blocks) { + if (!(bh = ufs_bread (inode, 0, 0, &error))) { + dput(base); + return ERR_PTR(-EIO); + } + link = bh->b_data; + } + /* fast symlink */ + else { + link = (char *) inode->u.ufs_i.i_u1.i_symlink; + } + UPDATE_ATIME(inode); + base = lookup_dentry(link, base, 1); + if (bh) + brelse(bh); + UFSD(("EXIT\n")) + return base; +} + +static int ufs_readlink (struct dentry * dentry, char * buffer, int buflen) +{ + struct super_block * sb; + struct inode * inode; + struct buffer_head * bh; + char * link; + int i; + + UFSD(("ENTER\n")) + + inode = dentry->d_inode; + sb = inode->i_sb; + bh = NULL; + if (buflen > sb->s_blocksize - 1) + buflen = sb->s_blocksize - 1; + /* slow symlink */ + if (inode->i_blocks) { + int err; + bh = ufs_bread (inode, 0, 0, &err); + if (!bh) { + if(err < 0) /* indicate type of error */ + return err; + return 0; + } + link = bh->b_data; + } + /* fast symlink */ + else { + link = (char *) inode->u.ufs_i.i_u1.i_symlink; + } + i = 0; + while (i < buflen && link[i]) + i++; + if (copy_to_user(buffer, link, i)) + i = -EFAULT; + UPDATE_ATIME(inode); + if (bh) + brelse (bh); + UFSD(("ENTER\n")) + return i; +} + +struct inode_operations ufs_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + ufs_readlink, /* readlink */ + ufs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; diff -u --recursive --new-file v2.1.111/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c --- v2.1.111/linux/fs/ufs/truncate.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/truncate.c Sun Jul 26 23:30:27 1998 @@ -0,0 +1,473 @@ +/* + * linux/fs/ufs/truncate.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles Uiversity, Faculty of Mathematics and Physics + * + * from + * + * linux/fs/ext2/truncate.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/truncate.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +/* + * Real random numbers for secure rm added 94/02/18 + * Idea from Pierre del Perugia + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_TRUNCATE_DEBUG + +#ifdef UFS_TRUNCATE_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + +/* + * Secure deletion currently doesn't work. It interacts very badly + * with buffers shared with memory mappings, and for that reason + * can't be done in the truncate() routines. It should instead be + * done separately in "release()" before calling the truncate routines + * that will release the actual file blocks. + * + * Linus + */ + +#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize) +#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize) + +static int ufs_trunc_direct (struct inode * inode) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * bh; + u32 * p; + unsigned frag1, frag2, frag3, frag4, block1, block2; + unsigned frag_to_free, free_count; + unsigned i, j, tmp; + int retry; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + + frag_to_free = 0; + free_count = 0; + retry = 0; + + frag1 = DIRECT_FRAGMENT; + frag4 = min (UFS_NDIR_FRAGMENT, inode->u.ufs_i.i_lastfrag); + frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); + frag3 = frag4 & ~uspi->s_fpbmask; + block1 = block2 = 0; + if (frag2 > frag3) { + frag2 = frag4; + frag3 = frag4 = 0; + } + else if (frag2 < frag3) { + block1 = ufs_fragstoblks (frag2); + block2 = ufs_fragstoblks (frag3); + } + + UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4)) + + if (frag1 >= frag2) + goto next1; + + /* + * Free first free fragments + */ + p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag1); + tmp = SWAB32(*p); + if (!tmp ) + ufs_panic (sb, "ufs_trunc_direct", "internal error"); + frag1 = ufs_fragnum (frag1); + frag2 = ufs_fragnum (frag2); + for (j = frag1; j < frag2; j++) { + bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize); + if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) { + retry = 1; + brelse (bh); + goto next1; + } + bforget (bh); + } + inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift; + mark_inode_dirty(inode); + ufs_free_fragments (inode, tmp + frag1, frag2 - frag1); + frag_to_free = tmp + frag1; + +next1: + /* + * Free whole blocks + */ + for (i = block1 ; i < block2; i++) { + p = inode->u.ufs_i.i_u1.i_data + i; + tmp = SWAB32(*p); + if (!tmp) + continue; + for (j = 0; j < uspi->s_fpb; j++) { + bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize); + if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) { + retry = 1; + brelse (bh); + goto next2; + } + bforget (bh); + } + *p = SWAB32(0); + inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); + if (free_count == 0) { + frag_to_free = tmp; + free_count = uspi->s_fpb; + } else if (free_count > 0 && frag_to_free == tmp - free_count) + free_count += uspi->s_fpb; + else { + ufs_free_blocks (inode, frag_to_free, free_count); + frag_to_free = tmp; + free_count = uspi->s_fpb; + } +next2: + } + + if (free_count > 0) + ufs_free_blocks (inode, frag_to_free, free_count); + + if (frag3 >= frag4) + goto next3; + + /* + * Free last free fragments + */ + p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag3); + tmp = SWAB32(*p); + if (!tmp ) + ufs_panic(sb, "ufs_truncate_direct", "internal error"); + frag4 = ufs_fragnum (frag4); + for (j = 0; j < frag4; j++) { + bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize); + if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) { + retry = 1; + brelse (bh); + goto next1; + } + bforget (bh); + } + *p = SWAB32(0); + inode->i_blocks -= frag4 << uspi->s_nspfshift; + mark_inode_dirty(inode); + ufs_free_fragments (inode, tmp, frag4); + next3: + + UFSD(("EXIT\n")) + return retry; +} + + +static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head * ind_ubh; + struct buffer_head * bh; + u32 * ind; + unsigned indirect_block, i, j, tmp; + unsigned frag_to_free, free_count; + int retry; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + + frag_to_free = 0; + free_count = 0; + retry = 0; + + tmp = SWAB32(*p); + if (!tmp) + return 0; + ind_ubh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize); + if (tmp != SWAB32(*p)) { + ubh_brelse (ind_ubh); + return 1; + } + if (!ind_ubh) { + *p = SWAB32(0); + return 0; + } + + indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; + for (i = indirect_block; i < uspi->s_apb; i++) { + ind = ubh_get_addr32 (ind_ubh, i); + tmp = SWAB32(*ind); + if (!tmp) + continue; + for (j = 0; j < uspi->s_fpb; j++) { + bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize); + if ((bh && bh->b_count != 1) || tmp != SWAB32(*ind)) { + retry = 1; + brelse (bh); + goto next; + } + bforget (bh); + } + *ind = SWAB32(0); + ubh_mark_buffer_dirty(ind_ubh, 1); + if (free_count == 0) { + frag_to_free = tmp; + free_count = uspi->s_fpb; + } else if (free_count > 0 && frag_to_free == tmp - free_count) + free_count += uspi->s_fpb; + else { + ufs_free_blocks (inode, frag_to_free, free_count); + frag_to_free = tmp; + free_count = uspi->s_fpb; + } + inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); +next: + } + + if (free_count > 0) { + ufs_free_blocks (inode, frag_to_free, free_count); + } + for (i = 0; i < uspi->s_apb; i++) + if (SWAB32(*ubh_get_addr32(ind_ubh,i))) + break; + if (i >= uspi->s_apb) { + if (ubh_max_bcount(ind_ubh) != 1) { + retry = 1; + } + else { + tmp = SWAB32(*p); + *p = SWAB32(0); + inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); + ufs_free_blocks (inode, tmp, uspi->s_fpb); + ubh_bforget(ind_ubh); + ind_ubh = NULL; + } + } + if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { + ubh_ll_rw_block (WRITE, 1, &ind_ubh); + ubh_wait_on_buffer (ind_ubh); + } + ubh_brelse (ind_ubh); + + UFSD(("EXIT\n")) + + return retry; +} + +static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head * dind_bh; + unsigned i, tmp, dindirect_block; + u32 * dind; + int retry = 0; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + + dindirect_block = (DIRECT_BLOCK > offset) + ? ((DIRECT_BLOCK - offset) / uspi->s_apb) : 0; + retry = 0; + + tmp = SWAB32(*p); + if (!tmp) + return 0; + dind_bh = ubh_bread (inode->i_dev, tmp, uspi->s_bsize); + if (tmp != SWAB32(*p)) { + ubh_brelse (dind_bh); + return 1; + } + if (!dind_bh) { + *p = SWAB32(0); + return 0; + } + + for (i = dindirect_block ; i < uspi->s_apb ; i++) { + dind = ubh_get_addr32 (dind_bh, i); + tmp = SWAB32(*dind); + if (!tmp) + continue; + retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); + ubh_mark_buffer_dirty(dind_bh, 1); + } + + for (i = 0; i < uspi->s_apb; i++) + if (SWAB32(*ubh_get_addr32 (dind_bh, i))) + break; + if (i >= uspi->s_apb) { + if (ubh_max_bcount(dind_bh) != 1) + retry = 1; + else { + tmp = SWAB32(*p); + *p = SWAB32(0); + inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); + ufs_free_blocks (inode, tmp, uspi->s_fpb); + ubh_bforget(dind_bh); + dind_bh = NULL; + } + } + if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { + ubh_ll_rw_block (WRITE, 1, &dind_bh); + ubh_wait_on_buffer (dind_bh); + } + ubh_brelse (dind_bh); + + UFSD(("EXIT\n")) + + return retry; +} + +static int ufs_trunc_tindirect (struct inode * inode) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head * tind_bh; + unsigned tindirect_block, tmp, i; + u32 * tind, * p; + int retry; + unsigned swab; + + UFSD(("ENTER\n")) + + sb = inode->i_sb; + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + retry = 0; + + tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) + ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) / uspi->s_2apb) : 0; + p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK; + if (!(tmp = SWAB32(*p))) + return 0; + tind_bh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize); + if (tmp != SWAB32(*p)) { + ubh_brelse (tind_bh); + return 1; + } + if (!tind_bh) { + *p = SWAB32(0); + return 0; + } + + for (i = tindirect_block ; i < uspi->s_apb ; i++) { + tind = ubh_get_addr32 (tind_bh, i); + retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); + ubh_mark_buffer_dirty(tind_bh, 1); + } + for (i = 0; i < uspi->s_apb; i++) + if (SWAB32(*ubh_get_addr32 (tind_bh, i))) + break; + if (i >= uspi->s_apb) { + if (ubh_max_bcount(tind_bh) != 1) + retry = 1; + else { + tmp = SWAB32(*p); + *p = SWAB32(0); + inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); + ufs_free_blocks (inode, tmp, uspi->s_fpb); + ubh_bforget(tind_bh); + tind_bh = NULL; + } + } + if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { + ubh_ll_rw_block (WRITE, 1, &tind_bh); + ubh_wait_on_buffer (tind_bh); + } + ubh_brelse (tind_bh); + + UFSD(("EXIT\n")) + return retry; +} + +void ufs_truncate (struct inode * inode) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * bh; + unsigned offset; + int err, retry; + + UFSD(("ENTER\n")) + sb = inode->i_sb; + uspi = sb->u.ufs_sb.s_uspi; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + while (1) { + retry = ufs_trunc_direct(inode); + retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK, + (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]); + retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb, + (u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]); + retry |= ufs_trunc_tindirect (inode); + if (!retry) + break; + if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) + ufs_sync_inode (inode); + current->counter = 0; + schedule (); + + + } + offset = inode->i_size & uspi->s_fshift; + if (offset) { + bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err); + if (bh) { + memset (bh->b_data + offset, 0, uspi->s_fsize - offset); + mark_buffer_dirty (bh, 0); + brelse (bh); + } + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize); + mark_inode_dirty(inode); + UFSD(("EXIT\n")) +} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c --- v2.1.111/linux/fs/ufs/ufs_dir.c Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_dir.c Wed Dec 31 16:00:00 1969 @@ -1,191 +0,0 @@ -/* - * linux/fs/ufs/ufs_dir.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * swab support by Francois-Rene Rideau 19970406 - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - */ - -#include - -#include "ufs_swab.h" - -/* - * This is blatantly stolen from ext2fs - */ -static int -ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) -{ - struct inode *inode = filp->f_dentry->d_inode; - int error = 0; - unsigned long offset, lblk, blk; - int i, stored; - struct buffer_head * bh; - struct ufs_direct * de; - struct super_block * sb; - int de_reclen; - __u32 flags; - - /* Isn't that already done in the upper layer??? - * the VFS layer really needs some explicit documentation! - */ - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; - - sb = inode->i_sb; - flags = sb->u.ufs_sb.s_flags; - - if (flags & UFS_DEBUG) { - printk("ufs_readdir: ino %lu f_pos %lu\n", - inode->i_ino, (unsigned long) filp->f_pos); - ufs_print_inode(inode); - } - - stored = 0; - bh = NULL; - offset = filp->f_pos & (sb->s_blocksize - 1); - - while (!error && !stored && filp->f_pos < inode->i_size) { - lblk = (filp->f_pos) >> sb->s_blocksize_bits; - /* XXX - ufs_bmap() call needs error checking */ - blk = ufs_bmap(inode, lblk); - bh = bread (sb->s_dev, blk, sb->s_blocksize); - if (!bh) { - /* XXX - error - skip to the next block */ - printk("ufs_readdir: " - "dir inode %lu has a hole at offset %lu\n", - inode->i_ino, (unsigned long int)filp->f_pos); - filp->f_pos += sb->s_blocksize - offset; - continue; - } - -revalidate: - /* If the dir block has changed since the last call to - * readdir(2), then we might be pointing to an invalid - * dirent right now. Scan from the start of the block - * to make sure. */ - if (filp->f_version != inode->i_version) { - for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ufs_direct *) - (bh->b_data + i); - /* It's too expensive to do a full - * dirent test each time round this - * loop, but we do have to test at - * least that it is non-zero. A - * failure will be detected in the - * dirent test below. */ - de_reclen = SWAB16(de->d_reclen); - if (de_reclen < 1) - break; - i += de_reclen; - } - offset = i; - filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) - | offset; - filp->f_version = inode->i_version; - } - - while (!error && filp->f_pos < inode->i_size - && offset < sb->s_blocksize) { - de = (struct ufs_direct *) (bh->b_data + offset); - /* XXX - put in a real ufs_check_dir_entry() */ - if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) { - /* SWAB16() was unneeded -- compare to 0 */ - filp->f_pos = (filp->f_pos & - (sb->s_blocksize - 1)) + - sb->s_blocksize; - brelse(bh); - return stored; - } -#if 0 /* XXX */ - if (!ext2_check_dir_entry ("ext2_readdir", inode, de, - /* XXX - beware about de having to be swabped somehow */ - bh, offset)) { - /* On error, skip the f_pos to the - next block. */ - filp->f_pos = (filp->f_pos & - (sb->s_blocksize - 1)) + - sb->s_blocksize; - brelse (bh); - return stored; - } -#endif /* XXX */ - offset += SWAB16(de->d_reclen); - if (de->d_ino) { - /* SWAB16() was unneeded -- compare to 0 */ - /* We might block in the next section - * if the data destination is - * currently swapped out. So, use a - * version stamp to detect whether or - * not the directory has been modified - * during the copy operation. */ - unsigned long version = inode->i_version; - - if (flags & UFS_DEBUG) { - printk("ufs_readdir: filldir(%s,%u)\n", - de->d_name, SWAB32(de->d_ino)); - } - error = filldir(dirent, de->d_name, NAMLEN(de), - filp->f_pos, SWAB32(de->d_ino)); - if (error) - break; - if (version != inode->i_version) - goto revalidate; - stored ++; - } - filp->f_pos += SWAB16(de->d_reclen); - } - offset = 0; - brelse (bh); - } -#if 0 /* XXX */ - if (!IS_RDONLY(inode)) { - inode->i_atime = CURRENT_TIME; - inode->i_dirt = 1; - } -#endif /* XXX */ - return 0; -} - -static struct file_operations ufs_dir_operations = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - ufs_readdir, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* release */ - file_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ -}; - -struct inode_operations ufs_dir_inode_operations = { - &ufs_dir_operations, /* default directory file operations */ - NULL, /* create */ - ufs_lookup, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ -}; diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c --- v2.1.111/linux/fs/ufs/ufs_file.c Tue Oct 21 05:26:13 1997 +++ linux/fs/ufs/ufs_file.c Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -/* - * linux/fs/ufs/ufs_file.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * $Id: ufs_file.c,v 1.9 1997/07/17 02:24:13 davem Exp $ - * - */ - -#include -#include - -static struct file_operations ufs_file_operations = { - NULL, /* lseek */ - generic_file_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - generic_file_mmap, /* mmap */ - NULL, /* open */ - NULL, /* release */ - file_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ -}; - -struct inode_operations ufs_file_inode_operations = { - &ufs_file_operations, /* default directory file operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - generic_readpage, /* readpage */ - NULL, /* writepage */ - ufs_bmap, /* bmap */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ -}; - diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c --- v2.1.111/linux/fs/ufs/ufs_inode.c Wed Jun 24 22:54:10 1998 +++ linux/fs/ufs/ufs_inode.c Wed Dec 31 16:00:00 1969 @@ -1,334 +0,0 @@ -/* - * linux/fs/ufs/ufs_inode.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * Clean swab support on 19970406 - * by Francois-Rene Rideau - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - * - * NeXTstep support added on February 5th 1998 by - * Niels Kristian Bech Jensen . - */ - -#undef DEBUG_UFS_INODE -/*#define DEBUG_UFS_INODE 1*/ -/* Uncomment the line above when hacking ufs inode code */ - -#include -#include -#include - -#include "ufs_swab.h" - -void ufs_print_inode(struct inode * inode) -{ - printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" - " sz %lu blks %lu cnt %u\n", - inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, - inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count); - printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x" - " 0x%x 0x%x 0x%x 0x%x>\n", - inode->u.ufs_i.i_u1.i_data[0], inode->u.ufs_i.i_u1.i_data[1], - inode->u.ufs_i.i_u1.i_data[2], inode->u.ufs_i.i_u1.i_data[3], - inode->u.ufs_i.i_u1.i_data[4], inode->u.ufs_i.i_u1.i_data[5], - inode->u.ufs_i.i_u1.i_data[6], inode->u.ufs_i.i_u1.i_data[7], - inode->u.ufs_i.i_u1.i_data[8], inode->u.ufs_i.i_u1.i_data[9], - inode->u.ufs_i.i_u1.i_data[10], inode->u.ufs_i.i_u1.i_data[11]); - printk(" gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n", - inode->u.ufs_i.i_gen, - inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK], - inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK], - inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]); -} - -#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_u1.i_data[(nr)]) - -static inline int block_bmap (struct inode *inode, int block, int nr) -{ - struct buffer_head *bh; - int tmp; - __u32 flags = inode->i_sb->u.ufs_sb.s_flags; - /* XXX Split in fsize big blocks (Can't bread 8Kb). */ - tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2); - bh = bread (inode->i_dev, inode->i_sb->u.ufs_sb.s_blockbase + block + - tmp, inode->i_sb->s_blocksize); - if (!bh) - return 0; - nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2; - tmp = SWAB32(((__u32 *)bh->b_data)[nr]); - brelse (bh); - return tmp; -} - -int ufs_bmap (struct inode * inode, int block) -{ - int i; - int addr_per_block = UFS_ADDR_PER_BLOCK(inode->i_sb); - int addr_per_block_bits = UFS_ADDR_PER_BLOCK_BITS(inode->i_sb); - int lbn = ufs_lbn (inode->i_sb, block); - int boff = ufs_boff (inode->i_sb, block); - - if (lbn < 0) { - ufs_warning (inode->i_sb, "ufs_bmap", "block < 0"); - return 0; - } - if (lbn >= UFS_NDADDR + addr_per_block + - (1 << (addr_per_block_bits * 2)) + - ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { - ufs_warning (inode->i_sb, "ufs_bmap", "block > big"); - return 0; - } - if (lbn < UFS_NDADDR) - return (inode->i_sb->u.ufs_sb.s_blockbase + - ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff)); - lbn -= UFS_NDADDR; - if (lbn < addr_per_block) { - i = inode_bmap (inode, UFS_IND_BLOCK); - if (!i) - return 0; - return (inode->i_sb->u.ufs_sb.s_blockbase + - ufs_dbn (inode->i_sb, - block_bmap (inode, i, lbn), boff)); - } - lbn -= addr_per_block; - if (lbn < (1 << (addr_per_block_bits * 2))) { - i = inode_bmap (inode, UFS_DIND_BLOCK); - if (!i) - return 0; - i = block_bmap (inode, i, lbn >> addr_per_block_bits); - if (!i) - return 0; - return (inode->i_sb->u.ufs_sb.s_blockbase + - ufs_dbn (inode->i_sb, - block_bmap (inode, i, lbn & (addr_per_block-1)), - boff)); - } - lbn -= (1 << (addr_per_block_bits * 2)); - i = inode_bmap (inode, UFS_TIND_BLOCK); - if (!i) - return 0; - i = block_bmap (inode, i, lbn >> (addr_per_block_bits * 2)); - if (!i) - return 0; - i = block_bmap (inode, i, - (lbn >> addr_per_block_bits) & (addr_per_block - 1)); - if (!i) - return 0; - return (inode->i_sb->u.ufs_sb.s_blockbase + - ufs_dbn (inode->i_sb, - block_bmap (inode, i, lbn & (addr_per_block-1)), boff)); -} - -/* XXX - ufs_read_inode is a mess */ -void ufs_read_inode(struct inode * inode) -{ - struct super_block * sb; - struct ufs_inode * ufsip; - struct buffer_head * bh; - __u32 flags = inode->i_sb->u.ufs_sb.s_flags; - - sb = inode->i_sb; - - if (ufs_ino_ok(inode)) { - printk("ufs_read_inode: bad inum %lu\n", inode->i_ino); - - return; - } - -#ifdef DEBUG_UFS_INODE - printk("ufs_read_inode: ino %lu cg %u cgino %u ipg %u inopb %u\n", - inode->i_ino, ufs_ino2cg(inode), - (inode->i_ino%sb->u.ufs_sb.s_inopb), - sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb); -#endif - bh = bread(inode->i_dev, - inode->i_sb->u.ufs_sb.s_blockbase + - ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + - (inode->i_ino%sb->u.ufs_sb.s_ipg)/ - (sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag), - sb->s_blocksize); - if (!bh) { - printk("ufs_read_inode: can't read inode %lu from dev %d/%d\n", - inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); - return; - } - - ufsip = (struct ufs_inode *)bh->b_data; - ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag)); - - /* - * Copy data to the in-core inode. - */ - inode->i_mode = SWAB16(ufsip->ui_mode); - inode->i_nlink = SWAB16(ufsip->ui_nlink); - if (inode->i_nlink == 0) { - /* XXX */ - printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); - inode->i_nlink = 1; - printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n", - inode->i_ino, - ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + - (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, - MAJOR(inode->i_dev), MINOR(inode->i_dev)); - } - /* XXX - debugging */ - if (SWAB32(ufsip->ui_gen) == 0) { - printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n", - inode->i_ino, - ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + - (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, - MAJOR(inode->i_dev), MINOR(inode->i_dev)); - } - /* - * Since Linux currently only has 16-bit uid_t and gid_t, we can't - * really support EFTs. For the moment, we use 0 as the uid and gid - * if an inode has a uid or gid that won't fit in 16 bits. This way - * random users can't get at these files, since they get dynamically - * "chown()ed" to root. - */ - if (UFS_UID(ufsip) >= UFS_USEEFT) { - inode->i_uid = 0; - printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", - UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev), inode->i_uid); - } else { - inode->i_uid = UFS_UID(ufsip); - } - if (UFS_GID(ufsip) >= UFS_USEEFT) { - inode->i_gid = 0; - printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", - UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev), inode->i_gid); - } else { - inode->i_gid = UFS_GID(ufsip); - } - - /* - * Linux i_size is 32 bits on most architectures, - * so some files on a UFS filesystem may not - * be readable. I let people access the first 32 bits worth of them. - * for the rw code, we may want to mark these inodes as read-only. - * XXX - bug Linus to make i_size a __u64 instead of a __u32. - */ - inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size); - /* KRR - Just type cast inode->u.ufs_i.i_size into off_t and - * worry about overflow later - */ - inode->i_size = (off_t)inode->u.ufs_i.i_size; - - /* - * Linux doesn't keep tv_usec around in the kernel, so we discard it. - * XXX - I'm not sure what I should do about writing things. I may - * want to keep this data, but for the moment I think I'll just write - * zeros for these fields when writing out inodes. - */ - inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec); - inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec); - inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec); - inode->i_blksize = sb->u.ufs_sb.s_fsize; - inode->i_blocks = SWAB32(ufsip->ui_blocks); - inode->i_version = ++event; /* see linux/kernel/sched.c */ - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ufs_file_inode_operations; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ufs_dir_inode_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &ufs_symlink_inode_operations; - } else if (S_ISCHR(inode->i_mode)) { - inode->i_op = &chrdev_inode_operations; - } else if (S_ISBLK(inode->i_mode)) { - inode->i_op = &blkdev_inode_operations; - } else if (S_ISFIFO(inode->i_mode)) { - init_fifo(inode); - } else if (S_ISSOCK(inode->i_mode)) { - /* nothing */ - } else { - printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n", - inode->i_mode, inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev)); - /* XXX - debugging */ - ufs_print_inode(inode); - inode->i_op = &ufs_file_inode_operations; - } - - /* - * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane. - */ - if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode)) { - int i; - - if (inode->i_blocks) { - for (i = 0; i < UFS_NDADDR; i++) { - inode->u.ufs_i.i_u1.i_data[i] = - SWAB32(ufsip->ui_u2.ui_addr.ui_db[i]); - } - for (i = 0; i < UFS_NINDIR; i++) { - inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK + i] = - SWAB32(ufsip->ui_u2.ui_addr.ui_ib[i]); - } - } else /* fast symlink */ { - memcpy(inode->u.ufs_i.i_u1.i_symlink, - ufsip->ui_u2.ui_symlink, 60); - } - } - - /* KRR - I need to check the SunOS header files, but for the time - * being, I'm going to tread ui_db[0] and [1] as a __u64 and swab - * them appropriately. This should clean up any real endian problems, - * but we'll still need to add size checks in the write portion of - * the code. - */ - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db); - } - - inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags); - inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */ - inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_u3.ui_sun.ui_shadow); /* XXX */ - inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_u3.ui_sun.ui_uid); - inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_u3.ui_sun.ui_gid); - inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_u3.ui_sun.ui_oeftflag); - - brelse(bh); - - if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) { - ufs_print_inode(inode); - } - - return; -} - -void ufs_put_inode (struct inode * inode) -{ - if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) { - printk("ufs_put_inode:\n"); - ufs_print_inode(inode); - } - - if (inode->i_nlink) - return; - - printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n", - inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); - ufs_print_inode(inode); - panic("ufs_put_inode: fs is read only, and nlink == 0"); - - /* XXX - this code goes here eventually - inode->i_size = 0; - if (inode->i_blocks) - ufs_truncate(inode); - ufs_free_inode(inode); - */ - - return; -} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c --- v2.1.111/linux/fs/ufs/ufs_namei.c Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_namei.c Wed Dec 31 16:00:00 1969 @@ -1,195 +0,0 @@ -/* - * linux/fs/ufs/ufs_namei.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * Clean swab support by Francois-Rene Rideau 19970406 - * Ported to 2.1.62 by Francois-Rene Rideau 19971109 - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - */ - -#include -#include -#include -#include "ufs_swab.h" - -/* - * NOTE1: unlike strncmp, ufs_match returns 1 for success, 0 for failure - * (stolen from ext2fs.) - * NOTE2: flags *is* used, though this is hidden by macros like NAMLEN. - */ -static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 flags) -{ - if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */ - return 0; - /* - * "" means "." ---> so paths like "/usr/lib//libc.a" work - */ - if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') && - (d->d_name[1] == '\0')) - return 1; - if (len != NAMLEN(d)) - return 0; - return !memcmp(name, d->d_name, len); -} - -int ufs_lookup (struct inode *dir, struct dentry *dentry) -{ - /* XXX - this is all fucked up! */ - unsigned long int lfragno, fragno; - struct buffer_head * bh; - struct ufs_direct * d; - struct super_block * sb = dir->i_sb; - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; - __u32 flags; - struct inode *inode; - - /* XXX - isn't that already done by the upper layer? */ - if (!dir || !S_ISDIR(dir->i_mode)) - return -EBADF; - - flags = sb->u.ufs_sb.s_flags; - - if (flags & UFS_DEBUG) - printk("Passed name: %s\nPassed length: %d\n", name, len); - - /* debugging hacks: - * Touching /xyzzy in a filesystem toggles debugging messages. - */ - if ((len == 5) && !(memcmp(name, "xyzzy", len)) && - (dir->i_ino == UFS_ROOTINO)) { - sb->u.ufs_sb.s_flags ^= UFS_DEBUG; - printk("UFS debugging %s\n", - (sb->u.ufs_sb.s_flags & UFS_DEBUG) ? - "on": "off"); - goto not_found; - /*return(-ENOENT);*/ - } - - /* - * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c - */ - if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) && - (dir->i_ino == UFS_ROOTINO)) { - sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE; - printk("UFS inode debugging %s\n", - (sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? - "on": "off"); - goto not_found; - /*return(-ENOENT);*/ - } - - /* - * Touching /xyzzy.n in a filesystem toggles debugging for ufs_namei.c - */ - if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) && - (dir->i_ino == UFS_ROOTINO)) { - sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI; - printk("UFS namei debugging %s\n", - (sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? - "on": "off"); - goto not_found; - /*return(-ENOENT);*/ - } - - /* - * Touching /xyzzy.l in a filesystem toggles debugging for ufs_symlink.c - */ - if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) && - (dir->i_ino == UFS_ROOTINO)) { - sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS; - printk("UFS symlink debugging %s\n", - (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? - "on": "off"); - goto not_found; - /*return(-ENOENT);*/ - } - - /* Now for the real thing */ - - if (flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { - printk("ufs_lookup: called for ino %lu name %s\n", - dir->i_ino, name); - } - - for (lfragno = 0; lfragno < dir->i_blocks; lfragno++) { - fragno = ufs_bmap(dir, lfragno); - /* ufs_bmap() reads the block (frag) size in s_blocksize */ - /* XXX - ufs_bmap() call needs error checking */ - if (flags & UFS_DEBUG) { - printk("ufs_lookup: ino %lu lfragno %lu fragno %lu\n", - dir->i_ino, lfragno, fragno); - } - if (fragno == 0) { - /* XXX - bug bug bug */ - goto not_found; - /*return(-ENOENT);*/ - } - bh = bread(dir->i_dev, fragno, sb->s_blocksize); - if (bh == NULL) { - printk("ufs_lookup: bread failed: " - "ino %lu, lfragno %lu", - dir->i_ino, lfragno); - return(-EIO); - } - d = (struct ufs_direct *)(bh->b_data); - while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <= - sb->s_blocksize) { - /* XXX - skip block if d_reclen or d_namlen is 0 */ - if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) { - /* no need to SWAB16(): test against 0 */ - if (flags & UFS_DEBUG) { - printk("ufs_lookup: skipped space in directory, ino %lu\n", - dir->i_ino); - } - break; - } - if (flags & UFS_DEBUG) { - printk("lfragno 0x%lx " - "direct d 0x%x " - "d_ino %u " - "d_reclen %u " - "d_namlen %u d_name `%s'\n", - lfragno, - (unsigned int)((unsigned long)d), - SWAB32(d->d_ino), - SWAB16(d->d_reclen), - NAMLEN(d),d->d_name); - } - if ((NAMLEN(d) == len) && - /* XXX - don't use strncmp() - see ext2fs */ - (ufs_match(len, name, d, flags))) { - /* We have a match */ -/* XXX - I only superficially understand how things work, - * so use at your own risk... -- Fare' - */ - inode = iget(sb, SWAB32(d->d_ino)); - brelse(bh); - if(!inode) { return -EACCES; } - d_add(dentry,inode); - return(0); - } else { - /* XXX - bounds checking */ - if (flags & UFS_DEBUG) { - printk("ufs_lookup: " - "wanted (%s,%d) got (%s,%d)\n", - name, len, - d->d_name, NAMLEN(d)); - } - } - d = (struct ufs_direct *)((char *)d + - SWAB16(d->d_reclen)); - } - brelse(bh); - } - not_found: - d_add(dentry,NULL); - return(0); -} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v2.1.111/linux/fs/ufs/ufs_super.c Mon Apr 6 17:41:01 1998 +++ linux/fs/ufs/ufs_super.c Wed Dec 31 16:00:00 1969 @@ -1,384 +0,0 @@ -/* - * linux/fs/ufs/ufs_super.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * - */ - -/* - * Kernel module support added on 96/04/26 by - * Stefan Reinauer - * - * Module usage counts added on 96/04/29 by - * Gertjan van Wingerde - * - * Clean swab support on 19970406 by - * Francois-Rene Rideau - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - * - * NeXTstep support added on February 5th 1998 by - * Niels Kristian Bech Jensen . - */ - -#undef DEBUG_UFS_SUPER -/*#define DEBUG_UFS_SUPER 1*/ -/* Uncomment the line above when hacking ufs superblock code */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "ufs_swab.h" - -struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent); -void ufs_put_super (struct super_block * sb); -int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); - -static struct super_operations ufs_super_ops = { - ufs_read_inode, - NULL, /* XXX - ufs_write_inode() */ - ufs_put_inode, - NULL, /* XXX - ufs_delete_inode() */ - NULL, /* XXX - notify_change() */ - ufs_put_super, - NULL, /* XXX - ufs_write_super() */ - ufs_statfs, - NULL, /* XXX - ufs_remount() */ -}; - -static struct file_system_type ufs_fs_type = { - "ufs", - FS_REQUIRES_DEV, - ufs_read_super, - NULL -}; - -__initfunc(int init_ufs_fs(void)) -{ - return(register_filesystem(&ufs_fs_type)); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - return init_ufs_fs(); -} - -void cleanup_module(void) -{ - unregister_filesystem(&ufs_fs_type); -} -#endif - -static char error_buf[1024]; - -void ufs_warning (struct super_block * sb, const char * function, - const char * fmt, ...) -{ - va_list args; - - va_start (args, fmt); - vsprintf (error_buf, fmt, args); - va_end (args); - printk (KERN_WARNING "UFS warning (device %s): %s: %s\n", - kdevname(sb->s_dev), function, error_buf); -} - -#ifdef DEBUG_UFS_SUPER -static void -ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) -{ - __u32 flags = sb->u.ufs_sb.s_flags; - - printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno); - printk("fs_size: 0x%8.8x\n", usb->fs_size); - printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg); - printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize); - printk("fs_fsize: 0x%8.8x\n", usb->fs_fsize); - printk("fs_frag: 0x%8.8x\n", usb->fs_frag); - printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir); - printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb); - printk("fs_optim: 0x%8.8x\n", usb->fs_optim); - printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl); - printk("fs_clean: 0x%8.8x\n", usb->fs_clean); - printk("fs_state: 0x%8.8x\n", UFS_STATE(usb)); - printk("fs_magic: 0x%8.8x\n", usb->fs_magic); - printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt); - - return; -} -#endif - -struct super_block * -ufs_read_super(struct super_block * sb, void * data, int silent) -{ - struct ufs_superblock * usb; /* normalized to local byteorder */ - struct buffer_head * bh1, *bh2; - __u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */ - static int offsets[] = { 0, 96, 160 }; /* different superblock locations */ - int i; - - /* sb->s_dev and sb->s_flags are set by our caller - * data is the mystery argument to sys_mount() - * - * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt, - * and s_type when we return. - */ - - MOD_INC_USE_COUNT; - lock_super (sb); - set_blocksize (sb->s_dev, BLOCK_SIZE); - - /* XXX - make everything read only for testing */ - sb->s_flags |= MS_RDONLY; - - for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) { - if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE, - BLOCK_SIZE)) || - !(bh2 = bread(sb->s_dev, offsets[i] + - UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) { - brelse(bh1); - printk ("ufs_read_super: unable to read superblock\n"); - goto ufs_read_super_lose; - } - /* XXX - redo this so we can free it later... */ - usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); - if (usb == NULL) { - brelse(bh1); - brelse(bh2); - printk ("ufs_read_super: get_free_page() failed\n"); - goto ufs_read_super_lose; - } - - memcpy((char *)usb, bh1->b_data, BLOCK_SIZE); - memcpy((char *)usb + BLOCK_SIZE, bh2->b_data, - sizeof(struct ufs_superblock) - BLOCK_SIZE); - - brelse(bh1); - brelse(bh2); - - switch (le32_to_cpup(&usb->fs_magic)) { - case UFS_MAGIC: - flags |= UFS_LITTLE_ENDIAN; - ufs_superblock_le_to_cpus(usb); - goto found; - case UFS_CIGAM: - flags |= UFS_BIG_ENDIAN; - ufs_superblock_be_to_cpus(usb); - goto found; - /* usb is now normalized to local byteorder */ - default: - } - } - printk ("ufs_read_super: bad magic number 0x%8.8x " - "on dev %d/%d\n", usb->fs_magic, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - goto ufs_read_super_lose; -found: -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]); -#endif - /* We found a UFS filesystem on this device. */ - - /* XXX - parse args */ - - if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) { - printk("ufs_read_super: invalid fs_bsize = %d\n", - usb->fs_bsize); - goto ufs_read_super_lose; - } - - if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) { - printk("ufs_read_super: invalid fs_fsize = %d\n", - usb->fs_fsize); - goto ufs_read_super_lose; - } - if (usb->fs_fsize != BLOCK_SIZE) { - set_blocksize (sb->s_dev, usb->fs_fsize); - } - - flags |= UFS_VANILLA; - /* XXX more consistency check */ -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: maxsymlinklen 0x%8.8x\n", - usb->fs_u.fs_44.fs_maxsymlinklen); -#endif - if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) { - if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) { - flags |= UFS_44BSD; - } else { - flags |= UFS_OLD; /* 4.2BSD */ - } - } else if (offsets[i] > 0) { - flags |= UFS_NEXT; - } else { - flags |= UFS_SUN; - } - -#ifdef DEBUG_UFS_SUPER - ufs_print_super_stuff(sb, usb); -#endif - if ( ((flags&UFS_ST_MASK)==UFS_ST_44BSD) - || ((flags&UFS_ST_MASK)==UFS_ST_OLD) - || ((flags&UFS_ST_MASK)==UFS_ST_NEXT) - || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN) - && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) { - switch(usb->fs_clean) { - case UFS_FSACTIVE: /* 0x00 */ - printk("ufs_read_super: fs is active\n"); - sb->s_flags |= MS_RDONLY; - break; - case UFS_FSCLEAN: /* 0x01 */ -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs is clean\n"); -#endif - break; - case UFS_FSSTABLE: /* 0x02 */ -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs is stable\n"); -#endif - break; - case UFS_FSOSF1: /* 0x03 */ - /* XXX is this correct for DEC OSF/1? */ -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: fs is clean and stable (OSF/1)\n"); -#endif - break; - case UFS_FSBAD: /* 0xFF */ - printk("ufs_read_super: fs is bad\n"); - sb->s_flags |= MS_RDONLY; - break; - default: - printk("ufs_read_super: can't grok fs_clean 0x%x\n", - usb->fs_clean); - sb->s_flags |= MS_RDONLY; - break; - } - } else { - printk("ufs_read_super: fs needs fsck\n"); - sb->s_flags |= MS_RDONLY; - /* XXX - make it read only or barf if it's not (/, /usr) */ - } - - /* XXX - sanity check sb fields */ - - /* KRR - Why are we not using fs_bsize for blocksize? */ - sb->s_blocksize = usb->fs_fsize; - sb->s_blocksize_bits = usb->fs_fshift; - /* XXX - sb->s_lock */ - sb->s_op = &ufs_super_ops; - sb->dq_op = 0; /* XXX */ - sb->s_magic = usb->fs_magic; - /* sb->s_time */ - /* sb->s_wait */ - /* XXX - sb->u.ufs_sb */ - sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */ - sb->u.ufs_sb.s_flags = flags ; - sb->u.ufs_sb.s_ncg = usb->fs_ncg; - sb->u.ufs_sb.s_ipg = usb->fs_ipg; - sb->u.ufs_sb.s_fpg = usb->fs_fpg; - sb->u.ufs_sb.s_fsize = usb->fs_fsize; - sb->u.ufs_sb.s_fmask = usb->fs_fmask; - sb->u.ufs_sb.s_fshift = usb->fs_fshift; - sb->u.ufs_sb.s_bsize = usb->fs_bsize; - sb->u.ufs_sb.s_bmask = usb->fs_bmask; - sb->u.ufs_sb.s_bshift = usb->fs_bshift; - sb->u.ufs_sb.s_iblkno = usb->fs_iblkno; - sb->u.ufs_sb.s_dblkno = usb->fs_dblkno; - sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset; - sb->u.ufs_sb.s_cgmask = usb->fs_cgmask; - sb->u.ufs_sb.s_inopb = usb->fs_inopb; - sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift; - sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask) - >> usb->fs_fshift); - sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ - sb->u.ufs_sb.s_blockbase = offsets[i]; - sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL); - -#ifdef DEBUG_UFS_SUPER - printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb); -#endif - /* - * XXX - read cg structs? - */ - - unlock_super(sb); - return(sb); - -ufs_read_super_lose: - /* XXX - clean up */ - set_blocksize (sb->s_dev, BLOCK_SIZE); - sb->s_dev = 0; - unlock_super (sb); - MOD_DEC_USE_COUNT; - return(NULL); -} - -void ufs_put_super (struct super_block * sb) -{ - if (sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("ufs_put_super\n"); /* XXX */ - } - - - /* XXX - sync fs data, set state to ok, and flush buffers */ - set_blocksize (sb->s_dev, BLOCK_SIZE); - - /* XXX - free allocated kernel memory */ - /* includes freeing usb page */ - - MOD_DEC_USE_COUNT; - - return; -} - -int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) -{ - struct statfs tmp; - struct statfs *sp = &tmp; - struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb; - /* fsb was already normalized during mounting */ - unsigned long used, avail; - - if (sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("ufs_statfs\n"); /* XXX */ - } - - sp->f_type = sb->s_magic; - sp->f_bsize = sb->s_blocksize; - sp->f_blocks = fsb->fs_dsize; - sp->f_bfree = fsb->fs_cstotal.cs_nbfree * - fsb->fs_frag + - fsb->fs_cstotal.cs_nffree; - - avail = sp->f_blocks - (sp->f_blocks / 100) * - fsb->fs_minfree; - used = sp->f_blocks - sp->f_bfree; - if (avail > used) - sp->f_bavail = avail - used; - else - sp->f_bavail = 0; - - sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg; - sp->f_ffree = fsb->fs_cstotal.cs_nifree; - sp->f_fsid.val[0] = fsb->fs_id[0]; - sp->f_fsid.val[1] = fsb->fs_id[1]; - sp->f_namelen = UFS_MAXNAMLEN; - - return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0; -} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_swab.c linux/fs/ufs/ufs_swab.c --- v2.1.111/linux/fs/ufs/ufs_swab.c Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_swab.c Wed Dec 31 16:00:00 1969 @@ -1,178 +0,0 @@ -/* - * linux/fs/ufs/ufs_swab.c - * - * Copyright (C) 1997 - * Francois-Rene Rideau - * - */ - -/* - * For inspiration, you might wanna check sys/ufs/ffs/fs.h from whateverBSD - * - * NOTES - * 19970406 - Fare - * 1) I began from old very preliminary 2.0.x sources, - * but it was underfeatured; - * I later saw that 2.1.1 sources had a *global* UFS byteswap flag. - * EVIL: imagine that a swabbed partition be mounted - * while a non-swabbed partition are active (that sucks!) - * I merged that source tree with mine. - * 2) I hope no one is using obNNUUXXIIous byteorder. - * That's the only thing I might have broken, - * though I rather think it's a fix: - * instead of __u64 like BSD, - * the former driver used an explicitly bigendian array of __u32! - * 3) I provide a few macros that use GCC C Extensions. - * Port to other compilers would require avoiding them. - * in any case, 64 bit (long long) support is required, - * unless you're ready to workaround - * 4) the swab routines below depend on the precise name and order - * of the structure elements. Watch out any modification in ufs_fs.h!!! - * 5) putting byteswapping stuff in ufs_swab* seems cleaner to me. - * 6) These sources should work with both 2.0 and 2.1 kernels... - * - * 19971013 - Fare - * 1) Ported to 2.1.57 - * 2) instead of byteswapping, use [bl]e_to_cpu: - * it might be that we run on a VAX! - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - * - * HOWTO continue adding swab support: - * basically, anywhere metadata is bread() (i.e. mapped to block device), - * data should either be SWAB()ed on the fly, - * or copied to a buffer and globally bswap_ufs_*() there. - * - */ - -#include -#include "ufs_swab.h" - -static __inline__ void n_be16_to_cpus(__u16*p,unsigned n) { -#ifndef __BIG_ENDIAN - unsigned i; - for(i=0;imember))-(char*)(p))) -#define __length_since(p,member) \ - ((unsigned)(sizeof(*p)-__length_before(p,member))) -#define __length_between(p,begin,after_end) \ - ((unsigned)(__length_before(p,after_end)-__length_before(p,begin))) -#define be32_to_cpus__between(s,begin,after_end) \ - n_be32_to_cpus((__u32*)&((s).begin), \ - __length_between(&s,begin,after_end)/4) -#define le32_to_cpus__between(s,begin,after_end) \ - n_le32_to_cpus((__u32*)&((s).begin), \ - __length_between(&s,begin,after_end)/4) -#define be32_to_cpus__since(s,begin) \ - n_be32_to_cpus((__u32*)&((s).begin), \ - __length_since(&s,begin)/4) -#define le32_to_cpus__since(s,begin) \ - n_le32_to_cpus((__u32*)&((s).begin), \ - __length_since(&s,begin)/4) -#define be16_to_cpus__between(s,begin,after_end) \ - n_be16_to_cpus((__u16*)&((s).begin), \ - __length_between(&s,begin,after_end)/2) -#define le16_to_cpus__between(s,begin,after_end) \ - n_le16_to_cpus((__u16*)&((s).begin), \ - __length_between(&s,begin,after_end)/2) - -/* - * Here are the whole-structure swabping routines... - * They were fun to design, but I don't understand why we - * need a copy of the superblock, anyway. -- Fare' - */ - -extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) { -#ifndef __BIG_ENDIAN - __u16 sb_type = 1; /* SUN type superblock */ - - if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) - sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */ - - be32_to_cpus__between(*usb,fs_link,fs_fmod); - /* XXX - I dunno what to do w/ fs_csp, - * but it is unused by the current code, so that's ok for now. - */ - be32_to_cpus(&usb->fs_cpc); - if (sb_type) { - be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon); - be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask); - /* Might fail on strictly aligning 64-bit big-endian - * architectures. Ouch! - */ - be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask); - be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask); - } else { - be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon); - be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize); - be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize); - be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask); - be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask); - be32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state); - } - be32_to_cpus__between(*usb,fs_postblformat,fs_magic); -#endif -} -extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) { -#ifndef __LITTLE_ENDIAN - __u16 sb_type = 1; /* SUN type superblock */ - - if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) - sb_type = 0; /* 4.4BSD (FreeBSD) type superblock */ - - le32_to_cpus__between(*usb,fs_link,fs_fmod); - /* XXX - I dunno what to do w/ fs_csp, - * but it is unused by the current code, so that's ok for now. - */ - le32_to_cpus(&usb->fs_cpc); - if (sb_type) { - le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon); - le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask); - /* Might fail on strictly aligning 64-bit big-endian - * architectures. Ouch! - */ - le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask); - le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask); - } else { - le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon); - le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize); - le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize); - le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask); - le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask); - le32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state); - } - le32_to_cpus__between(*usb,fs_postblformat,fs_magic); -#endif -} diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_swab.h linux/fs/ufs/ufs_swab.h --- v2.1.111/linux/fs/ufs/ufs_swab.h Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_swab.h Wed Dec 31 16:00:00 1969 @@ -1,121 +0,0 @@ -/* - * linux/fs/ufs/ufs_swab.h - * - * Copyright (C) 1997 - * Francois-Rene Rideau - * - */ - -#ifndef _UFS_SWAB_H -#define _UFS_SWAB_H - - -/* - * Notes: - * (1) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes - * in case there are ufs implementations that have strange bytesexes, - * you'll need to modify code here as well as in ufs_super.c and ufs_fs.h - * to support them. - * (2) for a read/write ufs driver, we should distinguish - * between byteswapping for read or write accesses! - * naming should then be UFS16_TO_CPU and suches. - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - */ - -#include -#include - -/* - * These are only valid inside ufs routines, after a variable named flags - * has been made visible in current scope and properly initialized: - __u32 flags = sb->u.ufs_sb.s_flags ; - */ -#define SWAB16(x) ufs_swab16(flags,x) -#define SWAB32(x) ufs_swab32(flags,x) -#define SWAB64(x) ufs_swab64(flags,x) - -extern __inline__ __const__ __u16 ufs_swab16(__u32 flags, __u16 x) { - if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { - return le16_to_cpu(x); - } else { - return be16_to_cpu(x); - } -} -extern __inline__ __const__ __u32 ufs_swab32(__u32 flags, __u32 x) { - if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { - return le32_to_cpu(x); - } else { - return be32_to_cpu(x); - } -} -extern __inline__ __const__ __u64 ufs_swab64(__u32 flags, __u64 x) { - if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) { - return le64_to_cpu(x); - } else { - return be64_to_cpu(x); - } -} - - -/* - * These are for in-core superblock normalization. - * It might or not be a bad idea once we go to a read/write driver, - * as all critical info should be copied to the sb info structure anyway. - * So better replace them with a static inline function - * ufs_superblock_to_sb_info() in ufs_super.c - */ -extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb); -extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb); - - -/* - * These also implicitly depend on variable flags... - * NAMLEN(foo) is already normalized to local format, so don't SWAB16() it! - */ - -#define NAMLEN(direct) ufs_namlen(flags,direct) -extern __inline__ __u16 ufs_namlen(__u32 flags, struct ufs_direct * direct) { - if ( (flags&UFS_DE_MASK) == UFS_DE_OLD) { - return SWAB16(direct->d_u.d_namlen); - } else /* UFS_DE_44BSD */ { - return direct->d_u.d_44.d_namlen; - } -} - -/* Here is how the uid is computed: - if the file system is 4.2BSD, get it from oldids. - if it has sun extension and oldids is USEEFT, get it from ui_sun. - if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd). - depends on implicit variable flags being initialized from - __u32 flags = sb->u.ufs_sb.s_flags; -*/ -#define UFS_UID(ino) ufs_uid(flags,ino) -#define UFS_GID(ino) ufs_gid(flags,ino) - -extern __inline__ __u32 ufs_uid(__u32 flags,struct ufs_inode * ino) { - switch(flags&UFS_UID_MASK) { - case UFS_UID_EFT: - return SWAB32(ino->ui_u3.ui_sun.ui_uid) ; - case UFS_UID_44BSD: - return SWAB32(ino->ui_u3.ui_44.ui_uid) ; - case UFS_UID_OLD: - default: - return SWAB16(ino->ui_u1.oldids.suid) ; - } -} -extern __inline__ __u32 ufs_gid(__u32 flags,struct ufs_inode * ino) { - switch(flags&UFS_UID_MASK) { - case UFS_UID_EFT: - return SWAB32(ino->ui_u3.ui_sun.ui_gid) ; - case UFS_UID_44BSD: - return SWAB32(ino->ui_u3.ui_44.ui_gid) ; - case UFS_UID_OLD: - default: - return SWAB16(ino->ui_u1.oldids.sgid) ; - } -} - -#endif /* _UFS_SWAB_H */ diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v2.1.111/linux/fs/ufs/ufs_symlink.c Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_symlink.c Wed Dec 31 16:00:00 1969 @@ -1,146 +0,0 @@ -/* - * linux/fs/ufs/ufs_symlink.c - * - * Copyright (C) 1996 - * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) - * Laboratory for Computer Science Research Computing Facility - * Rutgers, The State University of New Jersey - * - * Ported to 2.1.62 by Francois-Rene Rideau 19971109 - * - * 4.4BSD (FreeBSD) support added on February 1st 1998 by - * Niels Kristian Bech Jensen partially based - * on code by Martin von Loewis . - */ - -#include -#include -#include - -#include - -extern int ufs_bmap (struct inode *, int); - -static int -ufs_readlink(struct dentry * dentry, char * buffer, int buflen) -{ - struct inode * inode = dentry->d_inode; - struct super_block * sb = inode->i_sb; - unsigned long int block; - struct buffer_head * bh = NULL; - char * link; - int i; - char c; - - if (sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { - printk("ufs_readlink: called on ino %lu dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); - } - - if (!S_ISLNK(inode->i_mode)) { - return -EINVAL; - } - - if (buflen > sb->s_blocksize - 1) - buflen = sb->s_blocksize - 1; - if (inode->i_blocks) { - /* XXX - error checking */ - block = ufs_bmap(inode, 0); - if (sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { - printk("ufs_readlink: bmap got %lu for ino %lu\n", - block, inode->i_ino); - } - bh = bread(inode->i_dev, block, sb->s_blocksize); - if (!bh) { - printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev)); - return 0; - } - link = bh->b_data; - /* no need to bswap */ - } else /* fast symlink */ { - link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]); - } - i = 0; - while (i < buflen && (c = link[i])) { - i++; - put_user (c, buffer++); - } - brelse (bh); - return i; -} - -/* - * XXX - blatantly stolen from minix fs - */ -static struct dentry * -ufs_follow_link(struct dentry * dentry, struct dentry * base) -{ - struct inode * inode = dentry->d_inode; - unsigned long int block; - struct buffer_head * bh = NULL; - char * link; - - if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { - printk("ufs_follow_link: called on ino %lu dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); - } - - if (inode->i_blocks) { - /* read the link from disk */ - /* XXX - error checking */ - block = ufs_bmap(inode, 0); - bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize); - if (bh == NULL) { - printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev)); - dput(base); - return ERR_PTR(-EIO); - } - link = bh->b_data; - } else /* fast symlink */ { - link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]); - } - base = lookup_dentry(link, base, 1); - brelse (bh); - return base; -} - - -static struct file_operations ufs_symlink_operations = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* release */ - NULL, /* fsync */ /* XXX - is this ok? */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ -}; - -struct inode_operations ufs_symlink_inode_operations = { - &ufs_symlink_operations, /* default directory file operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - &ufs_readlink, /* readlink */ - &ufs_follow_link, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL, /* permission */ -}; diff -u --recursive --new-file v2.1.111/linux/fs/ufs/util.c linux/fs/ufs/util.c --- v2.1.111/linux/fs/ufs/util.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/util.c Sun Jul 26 01:20:22 1998 @@ -0,0 +1,197 @@ +/* + * linux/fs/ufs/util.c + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles Uiversity, Faculty of Mathematics and Physics + */ + +#include +#include + +#include "swab.h" +#include "util.h" + +#undef UFS_UTILS_DEBUG + +#ifdef UFS_UTILS_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + + +struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi, + kdev_t dev, unsigned fragment, unsigned size) +{ + struct ufs_buffer_head * ubh; + unsigned i, j, count; + if (size & ~uspi->s_fmask) + return NULL; + count = size >> uspi->s_fshift; + if (count > UFS_MAXFRAG) + return NULL; + ubh = (struct ufs_buffer_head *) + kmalloc (sizeof (struct ufs_buffer_head), GFP_KERNEL); + if (!ubh) + return NULL; + ubh->fragment = fragment; + ubh->count = count; + for (i = 0; i < count; i++) + if (!(ubh->bh[i] = bread (dev, fragment + i, uspi->s_fsize))) + goto failed; + for (; i < UFS_MAXFRAG; i++) + ubh->bh[i] = NULL; + return ubh; +failed: + for (j = 0; j < i; j++) + brelse (ubh->bh[j]); + return NULL; +} + +struct ufs_buffer_head * _ubh_bread2_ (struct ufs_sb_private_info * uspi, + kdev_t dev, unsigned fragment, unsigned size) +{ + unsigned i, j, count; + if (size & ~uspi->s_fmask) + return NULL; + count = size >> uspi->s_fshift; + if (count <= 0 || count > UFS_MAXFRAG) + return NULL; + USPI_UBH->fragment = fragment; + USPI_UBH->count = count; + for (i = 0; i < count; i++) + if (!(USPI_UBH->bh[i] = bread (dev, fragment + i, uspi->s_fsize))) + goto failed; + for (; i < UFS_MAXFRAG; i++) + USPI_UBH->bh[i] = NULL; + return USPI_UBH; +failed: + for (j = 0; j < i; j++) + brelse (USPI_UBH->bh[j]); + return NULL; +} + +void ubh_brelse (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for (i = 0; i < ubh->count; i++) + brelse (ubh->bh[i]); + kfree (ubh); +} + +void ubh_brelse2 (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) { + brelse (ubh->bh[i]); + ubh->bh[i] = NULL; + } +} + +void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh, int flag) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) + mark_buffer_dirty (ubh->bh[i], flag); +} + +void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) + mark_buffer_uptodate (ubh->bh[i], flag); +} + +void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[]) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < nr; i++ ) + ll_rw_block (rw, ubh[i]->count, ubh[i]->bh); +} + +void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) + wait_on_buffer (ubh->bh[i]); +} + +unsigned ubh_max_bcount (struct ufs_buffer_head * ubh) +{ + unsigned i; + unsigned max = 0; + if (!ubh) + return 0; + for ( i = 0; i < ubh->count; i++ ) + if ( ubh->bh[i]->b_count > max ) + max = ubh->bh[i]->b_count; + if (max == 0) + printk("Je cosi shnileho v kralovstvi Danskem!\n"); + return max; +} + +void ubh_bforget (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] ) + bforget (ubh->bh[i]); +} + +int ubh_buffer_dirty (struct ufs_buffer_head * ubh) +{ + unsigned i; + unsigned result = 0; + if (!ubh) + return 0; + for ( i = 0; i < ubh->count; i++ ) + result |= buffer_dirty(ubh->bh[i]); + return result; +} + +void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi, + unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size) +{ + unsigned len, bhno; + if ( size > (ubh->count << uspi->s_fshift) ) + size = ubh->count << uspi->s_fshift; + bhno = 0; + while ( size ) { + len = min (size, uspi->s_fsize); + memcpy (mem, ubh->bh[bhno]->b_data, len); + mem += uspi->s_fsize; + size -= len; + bhno++; + } +} + +void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi, + struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size) +{ + unsigned len, bhno; + if ( size > (ubh->count << uspi->s_fshift) ) + size = ubh->count << uspi->s_fshift; + bhno = 0; + while ( size ) { + len = min (size, uspi->s_fsize); + memcpy (ubh->bh[bhno]->b_data, mem, len); + mem += uspi->s_fsize; + size -= len; + bhno++; + } +} + \ No newline at end of file diff -u --recursive --new-file v2.1.111/linux/fs/ufs/util.h linux/fs/ufs/util.h --- v2.1.111/linux/fs/ufs/util.h Wed Dec 31 16:00:00 1969 +++ linux/fs/ufs/util.h Sun Jul 26 01:20:22 1998 @@ -0,0 +1,322 @@ +/* + * linux/fs/ufs/util.h + * + * Copyright (C) 1998 + * Daniel Pirkl + * Charles University, Faculty of Mathematics and Physics + */ + +#include +#include "swab.h" + + +/* + * some usefull marcos + */ +#define in_range(b,first,len) ((b)>=(first)&&(b)<(first)+(len)) +#define howmany(x,y) (((x)+(y)-1)/(y)) +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + + +/* + * current filesystem state; method depends on flags + */ +#define ufs_state(usb3) \ + (((flags & UFS_ST_MASK) == UFS_ST_OLD) \ + ? (usb3)->fs_u.fs_sun.fs_state /* old normal way */ \ + : (usb3)->fs_u.fs_44.fs_state /* 4.4BSD way */) + +/* + * namlen, it's format depends of flags + */ +#define ufs_namlen(de) _ufs_namlen_(de,flags,swab) +static inline __u16 _ufs_namlen_(struct ufs_dir_entry * de, unsigned flags, unsigned swab) { + if ((flags & UFS_DE_MASK) == UFS_DE_OLD) { + return SWAB16(de->d_u.d_namlen); + } else /* UFS_DE_44BSD */ { + return de->d_u.d_44.d_namlen; + } +} + +/* + * Here is how the uid is computed: + * if the file system is 4.2BSD, get it from oldids. + * if it has sun extension and oldids is USEEFT, get it from ui_sun. + * if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd). + */ +#define ufs_uid(inode) _ufs_uid_(inode,flags,swab) +static inline __u32 _ufs_uid_(struct ufs_inode * inode, unsigned flags, unsigned swab) { + switch (flags & UFS_UID_MASK) { + case UFS_UID_EFT: + return SWAB32(inode->ui_u3.ui_sun.ui_uid); + case UFS_UID_44BSD: + return SWAB32(inode->ui_u3.ui_44.ui_uid); + case UFS_UID_OLD: + default: + return SWAB16(inode->ui_u1.oldids.ui_suid); + } +} + +#define ufs_gid(inode) _ufs_gid_(inode,flags,swab) +static inline __u32 _ufs_gid_(struct ufs_inode * inode, unsigned flags, unsigned swab) { + switch (flags & UFS_UID_MASK) { + case UFS_UID_EFT: + return SWAB32(inode->ui_u3.ui_sun.ui_gid); + case UFS_UID_44BSD: + return SWAB32(inode->ui_u3.ui_44.ui_gid); + case UFS_UID_OLD: + default: + return SWAB16(inode->ui_u1.oldids.ui_sgid); + } +} + +/* + * marcros used for retyping + */ +#define UCPI_UBH ((struct ufs_buffer_head *)ucpi) +#define USPI_UBH ((struct ufs_buffer_head *)uspi) + +/* + * This functions manipulate with ufs_buffers + */ +#define ubh_bread(dev,fragment,size) _ubh_bread_(uspi,dev,fragment,size) +extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned); +#define ubh_bread2(dev,fragment,size) _ubh_bread2_(uspi,dev,fragment,size) +extern struct ufs_buffer_head * _ubh_bread2_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned); +extern void ubh_brelse (struct ufs_buffer_head *); +extern void ubh_brelse2 (struct ufs_buffer_head *); +extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int); +extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); +extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); +extern void ubh_wait_on_buffer (struct ufs_buffer_head *); +extern unsigned ubh_max_bcount (struct ufs_buffer_head *); +extern void ubh_bforget (struct ufs_buffer_head *); +extern int ubh_buffer_dirty (struct ufs_buffer_head *); +#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size) +extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struct ufs_buffer_head *, unsigned); +#define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size) +extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned); + +/* + * macros to get important structures from ufs_buffer_head + */ +#define ubh_get_usb_first(ubh) \ + ((struct ufs_super_block_first *)((ubh)->bh[0]->b_data)) + +#define ubh_get_usb_second(ubh) \ + ((struct ufs_super_block_second *)(ubh)-> \ + bh[SECTOR_SIZE >> uspi->s_fshift]->b_data + (SECTOR_SIZE & ~uspi->s_fmask)) + +#define ubh_get_usb_third(ubh) \ + ((struct ufs_super_block_third *)((ubh)-> \ + bh[SECTOR_SIZE*2 >> uspi->s_fshift]->b_data + (SECTOR_SIZE*2 & ~uspi->s_fmask))) + +#define ubh_get_ucg(ubh) \ + ((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data)) + +/* + * Extract byte from ufs_buffer_head + * Extract the bits for a block from a map inside ufs_buffer_head + */ +#define ubh_get_addr8(ubh,begin) \ + ((u8*)(ubh)->bh[(begin) >> uspi->s_fshift]->b_data + ((begin) & ~uspi->s_fmask)) + +#define ubh_get_addr16(ubh,begin) \ + (((u16*)((ubh)->bh[(begin) >> (uspi->s_fshift-1)]->b_data)) + ((begin) & (uspi->fsize>>1) - 1))) + +#define ubh_get_addr32(ubh,begin) \ + (((u32*)((ubh)->bh[(begin) >> (BLOCK_SIZE_BITS-2)]->b_data)) + \ + ((begin) & ((BLOCK_SIZE>>2) - 1))) + +#define ubh_get_addr ubh_get_addr8 + +#define ubh_blkmap(ubh,begin,bit) \ + ((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb))) + +/* + * Macros for access to superblock array structures + */ +#define ubh_postbl(ubh,cylno,i) \ + ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \ + ? (*(__s16*)(ubh_get_addr(ubh, \ + (unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \ + + (((cylno) * 16 + (i)) << 1) ) )) \ + : (*(__s16*)(ubh_get_addr(ubh, \ + uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) )))) + +#define ubh_rotbl(ubh,i) \ + ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \ + ? (*(__u8*)(ubh_get_addr(ubh, \ + (unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \ + : (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i))))) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve. + */ +#define ufs_freespace(usb, percentreserved) \ + (ufs_blkstofrags(SWAB32((usb)->fs_cstotal.cs_nbfree)) + \ + SWAB32((usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100)) + +/* + * Macros for access to cylinder group array structures + */ +#define ubh_cg_blktot(ucpi,cylno) \ + (*((__u32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2)))) + +#define ubh_cg_blks(ucpi,cylno,rpos) \ + (*((__u16*)ubh_get_addr(UCPI_UBH, \ + (ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 )))) + +/* + * Bitmap operation + * This functions work like classical bitmap operations. The diference + * is that we havn't the whole bitmap in one continuous part of memory, + * but in a few buffers. + * The parameter of each function is super_block, ufs_buffer_head and + * position of the begining of the bitmap. + */ +#define ubh_setbit(ubh,begin,bit) \ + (*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) |= (1 << ((bit) & 7))) + +#define ubh_clrbit(ubh,begin,bit) \ + (*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) &= ~(1 << ((bit) & 7))) + +#define ubh_isset(ubh,begin,bit) \ + (*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) & (1 << ((bit) & 7))) + +#define ubh_isclr(ubh,begin,bit) (!ubh_isset(ubh,begin,bit)) + +#define ubh_find_first_zero_bit(ubh,begin,size) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,0) +#define ubh_find_next_zero_bit(ubh,begin,size,offset) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,offset) +static inline unsigned _ubh_find_next_zero_bit_( + struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, + unsigned begin, unsigned size, unsigned offset) +{ + unsigned base, rest; + + begin <<= 3; + size += begin; + offset += begin; + base = offset >> (uspi->s_fshift + 3); + offset &= ((uspi->s_fsize << 3) - 1); + for (;;) { + rest = min (size, uspi->s_fsize << 3); + size -= rest; + offset = ext2_find_next_zero_bit (ubh->bh[base]->b_data, rest, offset); + if (offset < rest || !size) + break; + base++; + offset = 0; + } + return (base << (uspi->s_fshift + 3)) + offset - begin; +} + +#define ubh_isblockclear(ubh,begin,block) (!_ubh_isblockset_(uspi,ubh,begin,block)) +#define ubh_isblockset(ubh,begin,block) _ubh_isblockset_(uspi,ubh,begin,block) +static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi, + struct ufs_buffer_head * ubh, unsigned begin, unsigned block) +{ + switch (uspi->s_fpb) { + case 8: + return (*ubh_get_addr (ubh, begin + block) == 0xff); + case 4: + return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2))); + case 2: + return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1))); + case 1: + return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07))); + } + return 0; +} + +#define ubh_clrblock(ubh,begin,block) _ubh_clrblock_(uspi,ubh,begin,block) +static inline void _ubh_clrblock_(struct ufs_sb_private_info * uspi, + struct ufs_buffer_head * ubh, unsigned begin, unsigned block) +{ + switch (uspi->s_fpb) { + case 8: + *ubh_get_addr (ubh, begin + block) = 0x00; + return; + case 4: + *ubh_get_addr (ubh, begin + (block >> 1)) &= ~(0x0f << ((block & 0x01) << 2)); + return; + case 2: + *ubh_get_addr (ubh, begin + (block >> 2)) &= ~(0x03 << ((block & 0x03) << 1)); + return; + case 1: + *ubh_get_addr (ubh, begin + (block >> 3)) &= ~(0x01 << ((block & 0x07))); + return; + } +} + +#define ubh_setblock(ubh,begin,block) _ubh_setblock_(uspi,ubh,begin,block) +static inline void _ubh_setblock_(struct ufs_sb_private_info * uspi, + struct ufs_buffer_head * ubh, unsigned begin, unsigned block) +{ + switch (uspi->s_fpb) { + case 8: + *ubh_get_addr(ubh, begin + block) = 0xff; + return; + case 4: + *ubh_get_addr(ubh, begin + (block >> 1)) |= (0x0f << ((block & 0x01) << 2)); + return; + case 2: + *ubh_get_addr(ubh, begin + (block >> 2)) |= (0x03 << ((block & 0x03) << 1)); + return; + case 1: + *ubh_get_addr(ubh, begin + (block >> 3)) |= (0x01 << ((block & 0x07))); + return; + } +} + +static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap, + unsigned * fraglist, int cnt) +{ + struct ufs_sb_private_info * uspi; + unsigned fragsize, pos; + unsigned swab; + + swab = sb->u.ufs_sb.s_swab; + uspi = sb->u.ufs_sb.s_uspi; + + fragsize = 0; + for (pos = 0; pos < uspi->s_fpb; pos++) { + if (blockmap & (1 << pos)) { + fragsize++; + } + else if (fragsize > 0) { + ADD_SWAB32(fraglist[fragsize], cnt); + fragsize = 0; + } + } + if (fragsize > 0 && fragsize < uspi->s_fpb) + ADD_SWAB32(fraglist[fragsize], cnt); +} + +#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask) +static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, + unsigned begin, unsigned size, unsigned char * table, unsigned char mask) +{ + unsigned rest, offset; + unsigned char * cp; + + + offset = begin & ~uspi->s_fmask; + begin >>= uspi->s_fshift; + for (;;) { + if ((offset + size) < uspi->s_fsize) + rest = size; + else + rest = uspi->s_fsize - offset; + size -= rest; + cp = ubh->bh[begin]->b_data + offset; + while ((table[*cp++] & mask) == 0 && --rest); + if (rest || !size) + break; + begin++; + offset = 0; + } + return (size + rest); +} diff -u --recursive --new-file v2.1.111/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.1.111/linux/include/asm-i386/bugs.h Tue Jul 21 00:15:32 1998 +++ linux/include/asm-i386/bugs.h Sun Jul 26 11:54:52 1998 @@ -19,10 +19,6 @@ #include #include -#ifdef CONFIG_MTRR -# include -#endif - #define CONFIG_BUGi386 __initfunc(static void no_halt(char *s, int *ints)) @@ -333,7 +329,4 @@ check_amd_k6(); check_pentium_f00f(); system_utsname.machine[1] = '0' + boot_cpu_data.x86; -#if defined(CONFIG_MTRR) - mtrr_init (); -#endif } diff -u --recursive --new-file v2.1.111/linux/include/linux/console_struct.h linux/include/linux/console_struct.h --- v2.1.111/linux/include/linux/console_struct.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/console_struct.h Sun Jul 26 14:40:19 1998 @@ -15,6 +15,8 @@ */ #define CUR_DEFAULT CUR_UNDERLINE +#include + #define NPAR 16 struct vc_data { @@ -33,7 +35,7 @@ unsigned char vc_ulcolor; /* Color for underline mode */ unsigned char vc_halfcolor; /* Color for half intensity mode */ unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */ - unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars or font or 0 if not supported */ + unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */ unsigned int vc_x, vc_y; /* Cursor position */ unsigned int vc_top, vc_bottom; /* Scrolling region */ unsigned int vc_state; /* Escape sequence parser state */ @@ -84,6 +86,8 @@ unsigned int vc_bell_duration; /* Console bell duration */ unsigned int vc_cursor_type; struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ + unsigned long vc_uni_pagedir; + unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ /* additional information is in vt_kern.h */ }; diff -u --recursive --new-file v2.1.111/linux/include/linux/consolemap.h linux/include/linux/consolemap.h --- v2.1.111/linux/include/linux/consolemap.h Mon Jun 16 16:36:00 1997 +++ linux/include/linux/consolemap.h Sun Jul 26 14:40:19 1998 @@ -8,7 +8,8 @@ #define IBMPC_MAP 2 #define USER_MAP 3 -extern int hashtable_contents_valid; -extern unsigned char inverse_translate(int glyph); +struct vc_data; + +extern unsigned char inverse_translate(struct vc_data *conp, int glyph); extern unsigned short *set_translate(int m); -extern int conv_uni_to_pc(long ucs); +extern int conv_uni_to_pc(struct vc_data *conp, long ucs); diff -u --recursive --new-file v2.1.111/linux/include/linux/fb.h linux/include/linux/fb.h --- v2.1.111/linux/include/linux/fb.h Tue Jul 21 00:15:33 1998 +++ linux/include/linux/fb.h Sun Jul 26 14:40:19 1998 @@ -272,6 +272,8 @@ struct display_switch *dispsw; /* low level operations */ u_short scrollmode; /* Scroll Method */ short yscroll; /* Hardware scrolling */ + unsigned char fgshift, bgshift; + unsigned short charmask; /* 0xff or 0x1ff */ }; @@ -333,6 +335,38 @@ /* From here on everything is device dependent */ }; + + /* + * `Generic' versions of the frame buffer device operations + */ + +extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +extern int fbgen_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +extern int fbgen_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + + /* + * Helper functions + */ + +extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info_gen *info); +extern void fbgen_set_disp(int con, struct fb_info_gen *info); +extern void fbgen_install_cmap(int con, struct fb_info_gen *info); +extern int fbgen_update_var(int con, struct fb_info *info); +extern int fbgen_switch(int con, struct fb_info *info); +extern void fbgen_blank(int blank, struct fb_info *info); struct fb_videomode { diff -u --recursive --new-file v2.1.111/linux/include/linux/in6.h linux/include/linux/in6.h --- v2.1.111/linux/include/linux/in6.h Fri Feb 6 15:33:34 1998 +++ linux/include/linux/in6.h Sun Jul 26 23:35:56 1998 @@ -126,5 +126,6 @@ #define IPV6_MULTICAST_LOOP 19 #define IPV6_ADD_MEMBERSHIP 20 #define IPV6_DROP_MEMBERSHIP 21 +#define IPV6_ROUTER_ALERT 22 #endif diff -u --recursive --new-file v2.1.111/linux/include/linux/kd.h linux/include/linux/kd.h --- v2.1.111/linux/include/linux/kd.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/kd.h Sun Jul 26 14:40:19 1998 @@ -149,6 +149,9 @@ #define KD_FONT_FLAG_GLOBAL 1 /* Change on _all_ consoles */ #define KD_FONT_FLAG_DONT_RECALC 2 /* Don't recalculate hw charcell size [compat] */ +#ifdef __KERNEL__ +#define KD_FONT_FLAG_NEW 0x80000000 /* Indicate new KDFONTOP interface, which should be more strict */ +#endif /* note: 0x4B00-0x4B4E all have had a value at some time; don't reuse for the time being */ diff -u --recursive --new-file v2.1.111/linux/include/linux/nfsd/syscall.h linux/include/linux/nfsd/syscall.h --- v2.1.111/linux/include/linux/nfsd/syscall.h Fri Feb 6 15:34:24 1998 +++ linux/include/linux/nfsd/syscall.h Sat Jul 25 11:27:24 1998 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -54,29 +55,29 @@ struct nfsctl_export { char ex_client[NFSCLNT_IDMAX+1]; char ex_path[NFS_MAXPATHLEN+1]; - dev_t ex_dev; - ino_t ex_ino; + __kernel_dev_t ex_dev; + __kernel_ino_t ex_ino; int ex_flags; - uid_t ex_anon_uid; - gid_t ex_anon_gid; + __kernel_uid_t ex_anon_uid; + __kernel_gid_t ex_anon_gid; }; /* UGIDUPDATE */ struct nfsctl_uidmap { char * ug_ident; - uid_t ug_uidbase; + __kernel_uid_t ug_uidbase; int ug_uidlen; - uid_t * ug_udimap; - uid_t ug_gidbase; + __kernel_uid_t * ug_udimap; + __kernel_gid_t ug_gidbase; int ug_gidlen; - gid_t * ug_gdimap; + __kernel_gid_t * ug_gdimap; }; /* GETFH */ struct nfsctl_fhparm { struct sockaddr gf_addr; - dev_t gf_dev; - ino_t gf_ino; + __kernel_dev_t gf_dev; + __kernel_ino_t gf_ino; int gf_version; }; diff -u --recursive --new-file v2.1.111/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.111/linux/include/linux/proc_fs.h Tue Jul 21 00:15:33 1998 +++ linux/include/linux/proc_fs.h Sun Jul 26 23:35:56 1998 @@ -109,6 +109,7 @@ PROC_NET_AX25_ROUTE, PROC_NET_AX25, PROC_NET_AX25_CALLS, + PROC_NET_BMAC, PROC_NET_NR_NODES, PROC_NET_NR_NEIGH, PROC_NET_NR, diff -u --recursive --new-file v2.1.111/linux/include/linux/selection.h linux/include/linux/selection.h --- v2.1.111/linux/include/linux/selection.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/selection.h Sun Jul 26 14:40:19 1998 @@ -40,4 +40,7 @@ extern void getconsxy(int currcons, char *p); extern void putconsxy(int currcons, char *p); +extern u16 vcs_scr_readw(int currcons, u16 *org); +extern void vcs_scr_writew(int currcons, u16 val, u16 *org); + #endif diff -u --recursive --new-file v2.1.111/linux/include/linux/simp.h linux/include/linux/simp.h --- v2.1.111/linux/include/linux/simp.h Wed Jul 16 19:22:51 1997 +++ linux/include/linux/simp.h Wed Dec 31 16:00:00 1969 @@ -1,39 +0,0 @@ -/* - * include/linux/simp.h -- simple allocator for cached objects - * - * This is meant as a faster and simpler (not full-featured) replacement - * for SLAB, thus the name "simp" :-) - * - * (C) 1997 Thomas Schoebel-Theuer - */ - -#ifndef SIMP_H -#define SIMP_H - -/* used for constructors / destructors */ -typedef void (*structor)(void *); - -/* create an object cache */ -/* positive clearable_offset means the next two pointers at that offset - * can be internally used for freelist pointers when the object is - * deallocated / not in use; - * if there is no space inside the element that can be reused for - * this purpose, supply -1. Using positive offsets is essential for - * saving space with very small-sized objects. - * - * Note for big-sized objects in the range of whole pages, use - * the fast Linux page allocator instead, directly. - */ -extern struct simp * simp_create(char * name, long size, - structor first_ctor, - structor again_ctor, - structor dtor); - -/* alloc / dealloc routines */ -extern void * simp_alloc(struct simp * simp); -extern void simp_free(void * objp); - -/* garbage collection */ -extern long simp_garbage(void); - -#endif diff -u --recursive --new-file v2.1.111/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.1.111/linux/include/linux/skbuff.h Thu May 14 19:47:44 1998 +++ linux/include/linux/skbuff.h Sun Jul 26 23:35:56 1998 @@ -151,6 +151,8 @@ extern int skb_tailroom(struct sk_buff *skb); extern void skb_reserve(struct sk_buff *skb, unsigned int len); extern void skb_trim(struct sk_buff *skb, unsigned int len); +extern void skb_over_panic(struct sk_buff *skb, int len, void *here); +extern void skb_under_panic(struct sk_buff *skb, int len, void *here); /* Internal */ extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb) @@ -437,10 +439,6 @@ return result; } - -extern const char skb_put_errstr[]; -extern const char skb_push_errstr[]; - /* * Add data to an sk_buff */ @@ -452,9 +450,9 @@ skb->len+=len; if(skb->tail>skb->end) { - __label__ here; - panic(skb_put_errstr,&&here,len); -here: ; + __label__ here; + skb_over_panic(skb, len, &&here); +here: ; } return tmp; } @@ -466,8 +464,8 @@ if(skb->datahead) { __label__ here; - panic(skb_push_errstr, &&here,len); -here: ; + skb_under_panic(skb, len, &&here); +here: ; } return skb->data; } diff -u --recursive --new-file v2.1.111/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.111/linux/include/linux/socket.h Wed Jun 24 22:54:12 1998 +++ linux/include/linux/socket.h Sun Jul 26 23:35:56 1998 @@ -183,6 +183,7 @@ #define PF_ROUTE AF_ROUTE #define PF_PACKET AF_PACKET #define PF_ASH AF_ASH +#define PF_ECONET AF_ECONET #define PF_ATMSVC AF_ATMSVC #define PF_SNA AF_SNA diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h --- v2.1.111/linux/include/linux/ufs_fs.h Thu May 7 22:51:55 1998 +++ linux/include/linux/ufs_fs.h Sun Jul 26 01:20:22 1998 @@ -21,10 +21,6 @@ #ifndef __LINUX_UFS_FS_H #define __LINUX_UFS_FS_H -#undef UFS_HEAVY_DEBUG -/*#define UFS_HEAVY_DEBUG 1*/ -/* Uncomment the line above when hacking ufs code */ - #include #include #include @@ -35,11 +31,15 @@ #define UFS_SBLOCK 8192 #define UFS_SBSIZE 8192 +#define SECTOR_SIZE 512 +#define SECTOR_BITS 9 #define UFS_MAGIC 0x00011954 #define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ -#define UFS_FSIZE 1024 -#define UFS_BSIZE 8192 +#define UFS_BSIZE 8192 +#define UFS_MINBSIZE 4096 +#define UFS_FSIZE 1024 +#define UFS_MAXFRAG (UFS_BSIZE / UFS_FSIZE) #define UFS_NDADDR 12 #define UFS_NINDIR 3 @@ -48,7 +48,13 @@ #define UFS_DIND_BLOCK (UFS_NDADDR + 1) #define UFS_TIND_BLOCK (UFS_NDADDR + 2) +#define UFS_NDIR_FRAGMENT (UFS_NDADDR << uspi->s_fpbshift) +#define UFS_IND_FRAGMENT (UFS_IND_BLOCK << uspi->s_fpbshift) +#define UFS_DIND_FRAGMENT (UFS_DIND_BLOCK << uspi->s_fpbshift) +#define UFS_TIND_FRAGMENT (UFS_TIND_BLOCK << uspi->s_fpbshift) + #define UFS_ROOTINO 2 +#define UFS_FIRST_INO (UFS_ROOTINO + 1) #define UFS_USEEFT ((__u16)65535) @@ -87,62 +93,109 @@ #define UFS_HURD 0x00000130 #define UFS_SUN 0x00000200 #define UFS_NEXT 0x00000400 -/* we preserve distinction in flavor identification even without difference, - * because yet-to-be-supported features may introduce difference in the future - */ -/* last but not least, debug flags */ -#define UFS_DEBUG 0x01000000 -#define UFS_DEBUG_INODE 0x02000000 -#define UFS_DEBUG_NAMEI 0x04000000 -#define UFS_DEBUG_LINKS 0x08000000 - -#ifdef UFS_HEAVY_DEBUG -# define UFS_DEBUG_INITIAL UFS_DEBUG -#else -# define UFS_DEBUG_INITIAL 0 -#endif /* fs_inodefmt options */ #define UFS_42INODEFMT -1 #define UFS_44INODEFMT 2 -#define UFS_ADDR_PER_BLOCK(sb) ((sb)->u.ufs_sb.s_bsize >> 2) -#define UFS_ADDR_PER_BLOCK_BITS(sb) ((sb)->u.ufs_sb.s_bshift - 2) +/* + * MINFREE gives the minimum acceptable percentage of file system + * blocks which may be free. If the freelist drops below this level + * only the superuser may continue to allocate blocks. This may + * be set to 0 if no reserve of free blocks is deemed necessary, + * however throughput drops by fifty percent if the file system + * is run at between 95% and 100% full; thus the minimum default + * value of fs_minfree is 5%. However, to get good clustering + * performance, 10% is a better choice. hence we use 10% as our + * default value. With 10% free space, fragmentation is not a + * problem, so we choose to optimize for time. + */ +#define UFS_MINFREE 5 +#define UFS_DEFAULTOPT UFS_OPTTIME + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define ufs_fsbtodb(uspi, b) ((b) << (uspi)->s_fsbtodb) +#define ufs_dbtofsb(uspi, b) ((b) >> (uspi)->s_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc file system addresses of cylinder group data structures. + */ +#define ufs_cgbase(c) (uspi->s_fpg * (c)) +#define ufs_cgstart(c) (ufs_cgbase(c) + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask)) +#define ufs_cgsblock(c) (ufs_cgstart(c) + uspi->s_sblkno) /* super blk */ +#define ufs_cgcmin(c) (ufs_cgstart(c) + uspi->s_cblkno) /* cg block */ +#define ufs_cgimin(c) (ufs_cgstart(c) + uspi->s_iblkno) /* inode blk */ +#define ufs_cgdmin(c) (ufs_cgstart(c) + uspi->s_dblkno) /* 1st data */ + +/* + * Macros for handling inode numbers: + * inode number to file system block offset. + * inode number to cylinder group number. + * inode number to file system block address. + */ +#define ufs_inotocg(x) ((x) / uspi->s_ipg) +#define ufs_inotocgoff(x) ((x) % uspi->s_ipg) +#define ufs_inotofsba(x) (ufs_cgimin(ufs_inotocg(x)) + ufs_inotocgoff(x) / uspi->s_inopf) +#define ufs_inotofsbo(x) ((x) % uspi->s_inopf) + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +#define ufs_dtog(d) ((d) / uspi->s_fpg) +#define ufs_dtogd(d) ((d) % uspi->s_fpg) + +/* + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define ufs_cbtocylno(bno) \ + ((bno) * uspi->s_nspf / uspi->s_spc) +#define ufs_cbtorpos(bno) \ + ((((bno) * uspi->s_nspf % uspi->s_spc / uspi->s_nsect \ + * uspi->s_trackskew + (bno) * uspi->s_nspf % uspi->s_spc \ + % uspi->s_nsect * uspi->s_interleave) % uspi->s_nsect \ + * uspi->s_nrpos) / uspi->s_npsect) -/* Test if the inode number is valid. */ -#define ufs_ino_ok(inode) ((inode->i_ino < 2) && \ - (inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1))) - -/* Convert (sb,cg) to the first physical block number for that cg. */ -#define ufs_cgstart(sb, cg) \ - (((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask))) - -/* Convert (sb,cg) to the first phys. block number for inodes in that cg. */ -#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno) -#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno) - -/* Convert an inode number to a cg number. */ -/* XXX - this can be optimized if s_ipg is a power of 2. */ -#define ufs_ino2cg(inode) ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg) - -/* current filesystem state; method depends on flags */ -#define UFS_STATE(usb) \ - ( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \ - ? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \ - : (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ ) +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define ufs_blkoff(loc) ((loc) & uspi->s_qbmask) +#define ufs_fragoff(loc) ((loc) & uspi->s_qfmask) +#define ufs_lblktosize(blk) ((blk) << uspi->s_bshift) +#define ufs_lblkno(loc) ((loc) >> uspi->s_bshift) +#define ufs_numfrags(loc) ((loc) >> uspi->s_fshift) +#define ufs_blkroundup(size) (((size) + uspi->s_qbmask) & uspi->s_bmask) +#define ufs_fragroundup(size) (((size) + uspi->s_qfmask) & uspi->s_fmask) +#define ufs_fragstoblks(frags) ((frags) >> uspi->s_fpbshift) +#define ufs_blkstofrags(blks) ((blks) << uspi->s_fpbshift) +#define ufs_fragnum(fsb) ((fsb) & uspi->s_fpbmask) +#define ufs_blknum(fsb) ((fsb) & ~uspi->s_fpbmask) #define UFS_MAXNAMLEN 255 +#define UFS_MAXMNTLEN 512 +#define UFS_MAXCSBUFS 31 +#define UFS_LINK_MAX EXT2_LINK_MAX -#define ufs_lbn(sb, block) ((block) >> (sb)->u.ufs_sb.s_lshift) -#define ufs_boff(sb, block) ((block) & ~((sb)->u.ufs_sb.s_lmask)) -#define ufs_dbn(sb, block, boff) ((block) + ufs_boff((sb), (boff))) +/* + * UFS_DIR_PAD defines the directory entries boundaries + * (must be a multiple of 4) + */ +#define UFS_DIR_PAD 4 +#define UFS_DIR_ROUND (UFS_DIR_PAD - 1) +#define UFS_DIR_REC_LEN(name_len) (((name_len) + 1 + 8 + UFS_DIR_ROUND) & ~UFS_DIR_ROUND) struct ufs_timeval { __s32 tv_sec; __s32 tv_usec; }; -struct ufs_direct { +struct ufs_dir_entry { __u32 d_ino; /* inode number of this entry */ __u16 d_reclen; /* length of this entry */ union { @@ -155,9 +208,6 @@ __u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */ }; -#define MAXMNTLEN 512 -#define MAXCSBUFS 32 - struct ufs_csum { __u32 cs_ndir; /* number of directories */ __u32 cs_nbfree; /* number of free blocks */ @@ -168,7 +218,7 @@ /* * This is the actual superblock, as it is laid out on the disk. */ -struct ufs_superblock { +struct ufs_super_block { __u32 fs_link; /* UNUSED */ __u32 fs_rlink; /* UNUSED */ __u32 fs_sblkno; /* addr of super-block in filesys */ @@ -237,15 +287,18 @@ __u8 fs_clean; /* file system is clean flag */ __u8 fs_ronly; /* mounted read-only flag */ __u8 fs_flags; /* currently unused flag */ - __u8 fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + __u8 fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */ /* these fields retain the current block allocation info */ __u32 fs_cgrotor; /* last cg searched */ - __u32 fs_csp[MAXCSBUFS]; /* list of fs_cs info buffers */ + __u32 fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */ + __u32 fs_maxcluster; __u32 fs_cpc; /* cyl per cycle in postbl */ __u16 fs_opostbl[16][8]; /* old rotation block list head */ union { struct { - __s32 fs_sparecon[55];/* reserved for future constants */ + __s32 fs_sparecon[53];/* reserved for future constants */ + __s32 fs_reclaim; + __s32 fs_sparecon2[1]; __s32 fs_state; /* file system state time stamp */ __u32 fs_qbmask[2]; /* ~usb_bmask */ __u32 fs_qfmask[2]; /* ~usb_fmask */ @@ -255,7 +308,7 @@ __s32 fs_contigsumsize;/* size of cluster summary array */ __s32 fs_maxsymlinklen;/* max length of an internal symlink */ __s32 fs_inodefmt; /* format of on-disk inodes */ - __u32 fs_maxfilesize[2];/* max representable file size */ + __u32 fs_maxfilesize[2]; /* max representable file size */ __u32 fs_qbmask[2]; /* ~usb_bmask */ __u32 fs_qfmask[2]; /* ~usb_fmask */ __s32 fs_state; /* file system state time stamp */ @@ -270,6 +323,59 @@ }; /* + * Preference for optimization. + */ +#define UFS_OPTTIME 0 /* minimize allocation time */ +#define UFS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Rotational layout table format types + */ +#define UFS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ +#define UFS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ + +/* + * Convert cylinder group to base address of its global summary info. + */ +#define fs_cs(indx) \ + u.ufs_sb.s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask] + +/* + * Cylinder group block for a file system. + * + * Writable fields in the cylinder group are protected by the associated + * super block lock fs->fs_lock. + */ +#define CG_MAGIC 0x090255 +#define ufs_cg_chkmagic(ucg) (SWAB32((ucg)->cg_magic) == CG_MAGIC) + +/* + * size of this structure is 172 B + */ +struct ufs_cylinder_group { + __u32 cg_link; /* linked list of cyl groups */ + __u32 cg_magic; /* magic number */ + __u32 cg_time; /* time last written */ + __u32 cg_cgx; /* we are the cgx'th cylinder group */ + __u16 cg_ncyl; /* number of cyl's this cg */ + __u16 cg_niblk; /* number of inode blocks this cg */ + __u32 cg_ndblk; /* number of data blocks this cg */ + struct ufs_csum cg_cs; /* cylinder summary information */ + __u32 cg_rotor; /* position of last used block */ + __u32 cg_frotor; /* position of last used frag */ + __u32 cg_irotor; /* position of last used inode */ + __u32 cg_frsum[UFS_MAXFRAG]; /* counts of available frags */ + __u32 cg_btotoff; /* (__u32) block totals per cylinder */ + __u32 cg_boff; /* (short) free block positions */ + __u32 cg_iusedoff; /* (char) used inode map */ + __u32 cg_freeoff; /* (u_char) free block map */ + __u32 cg_nextfreeoff; /* (u_char) next available space */ + __u32 cg_sparecon[16]; /* reserved for future use */ + __u8 cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ +}; + +/* * structure of an on-disk inode */ struct ufs_inode { @@ -277,11 +383,11 @@ __u16 ui_nlink; /* 0x2 */ union { struct { - __u16 suid; /* 0x4 */ - __u16 sgid; /* 0x6 */ + __u16 ui_suid; /* 0x4 */ + __u16 ui_sgid; /* 0x6 */ } oldids; - __u32 inumber; /* 0x4 lsf: inode number */ - __u32 author; /* 0x4 GNU HURD: author */ + __u32 ui_inumber; /* 0x4 lsf: inode number */ + __u32 ui_author; /* 0x4 GNU HURD: author */ } ui_u1; __u64 ui_size; /* 0x8 */ struct ufs_timeval ui_atime; /* 0x10 access */ @@ -333,43 +439,73 @@ #define UFS_SF_IMMUTABLE 0x00020000 /* immutable (can't "change") */ #define UFS_SF_APPEND 0x00040000 /* append-only */ #define UFS_SF_NOUNLINK 0x00100000 /* can't be removed or renamed */ - - -#ifdef __KERNEL__ -/* - * Function prototypes - */ - -/* ufs_inode.c */ -extern int ufs_bmap (struct inode *, int); -extern void ufs_read_inode(struct inode * inode); -extern void ufs_put_inode(struct inode * inode); -extern void ufs_print_inode (struct inode *); - -/* ufs_namei.c */ -extern int ufs_lookup (struct inode *, struct dentry *); +#ifdef __KERNEL__ -/* ufs_super.c */ -extern void ufs_warning (struct super_block *, const char *, const char *, ...) - __attribute__ ((format (printf, 3, 4))); -extern int init_ufs_fs(void); +/* acl.c */ +extern int ufs_permission (struct inode *, int); -/* - * Inodes and files operations - */ +/* balloc.c */ +extern void ufs_free_fragments (struct inode *, unsigned, unsigned); +extern void ufs_free_blocks (struct inode *, unsigned, unsigned); +extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *); + +/* cylinder.c */ +extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned); +extern void ufs_put_cylinder (struct super_block *, unsigned); -/* ufs_dir.c */ +/* dir.c */ extern struct inode_operations ufs_dir_inode_operations; extern struct file_operations ufs_dir_operations; +extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long); -/* ufs_file.c */ +/* file.c */ extern struct inode_operations ufs_file_inode_operations; extern struct file_operations ufs_file_operations; -/* ufs_symlink.c */ +/* ialloc.c */ +extern void ufs_free_inode (struct inode *inode); +extern struct inode * ufs_new_inode (const struct inode *, int, int *); + +/* inode.c */ +extern int ufs_bmap (struct inode *, int); +extern void ufs_read_inode (struct inode *); +extern void ufs_put_inode (struct inode *); +extern void ufs_write_inode (struct inode *); +extern int ufs_sync_inode (struct inode *); +extern void ufs_print_inode (struct inode *); +extern void ufs_write_inode (struct inode *); +extern void ufs_delete_inode (struct inode *); +extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *); +extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *); + +/* namei.c */ +extern int ufs_lookup (struct inode *, struct dentry *); +extern int ufs_mkdir(struct inode *, struct dentry *, int); +extern int ufs_rmdir (struct inode *, struct dentry *); +extern int ufs_unlink (struct inode *, struct dentry *); +extern int ufs_create (struct inode *, struct dentry *, int); +extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int ufs_mknod (struct inode *, struct dentry *, int, int); +extern int ufs_symlink (struct inode *, struct dentry *, const char *); +extern int ufs_link (struct dentry *, struct inode *, struct dentry *); + +/* super.c */ +extern struct super_operations ufs_super_ops; +extern struct file_system_type ufs_fs_type; +extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); +extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); +extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); + +extern int init_ufs_fs(void); +extern void ufs_write_super (struct super_block *); +extern void ufs_print_cylinder_stuff(struct ufs_cylinder_group *, __u32); + +/* symlink.c */ extern struct inode_operations ufs_symlink_inode_operations; -extern struct file_operations ufs_symlink_operations; + +/* truncate.c */ +extern void ufs_truncate (struct inode *); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h --- v2.1.111/linux/include/linux/ufs_fs_i.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/ufs_fs_i.h Sun Jul 26 01:20:22 1998 @@ -8,6 +8,8 @@ * * NeXTstep support added on February 5th 1998 by * Niels Kristian Bech Jensen . + * + * write support by Daniel Pirkl */ #ifndef _LINUX_UFS_FS_I_H @@ -16,7 +18,7 @@ struct ufs_inode_info { union { __u32 i_data[15]; - __u8 i_symlink[4*15]; /* fast symlink */ + __u8 i_symlink[4*15]; } i_u1; __u64 i_size; __u32 i_flags; @@ -25,6 +27,8 @@ __u32 i_uid; __u32 i_gid; __u32 i_oeftflag; + __u16 i_osync; + __u32 i_lastfrag; }; #endif /* _LINUX_UFS_FS_I_H */ diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h --- v2.1.111/linux/include/linux/ufs_fs_sb.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/ufs_fs_sb.h Sun Jul 26 01:20:22 1998 @@ -1,4 +1,4 @@ -/* +/* * linux/include/linux/ufs_fs_sb.h * * Copyright (C) 1996 @@ -6,8 +6,10 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * NeXTstep support added on February 5th 1998 by - * Niels Kristian Bech Jensen . + * $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $ + * + * Write support by Daniel Pirkl (daniel.pirkl@email.cz) + * Charles University (Prague), Faculty of Mathematics and Physics */ #ifndef __LINUX_UFS_FS_SB_H @@ -15,27 +17,210 @@ #include +/* + * This structure is used for reading disk structures larger + * than the size of fragment. + */ +struct ufs_buffer_head { + unsigned fragment; /* first fragment */ + unsigned count; /* number of fragments */ + struct buffer_head * bh[UFS_MAXFRAG]; /* buffers */ +}; + +struct ufs_cg_private_info { + struct ufs_cylinder_group ucg; + __u32 c_cgx; /* number of cylidner group */ + __u16 c_ncyl; /* number of cyl's this cg */ + __u16 c_niblk; /* number of inode blocks this cg */ + __u32 c_ndblk; /* number of data blocks this cg */ + __u32 c_rotor; /* position of last used block */ + __u32 c_frotor; /* position of last used frag */ + __u32 c_irotor; /* position of last used inode */ + __u32 c_btotoff; /* (__u32) block totals per cylinder */ + __u32 c_boff; /* (short) free block positions */ + __u32 c_iusedoff; /* (char) used inode map */ + __u32 c_freeoff; /* (u_char) free block map */ + __u32 c_nextfreeoff; /* (u_char) next available space */ +}; + + +struct ufs_sb_private_info { + struct ufs_buffer_head s_ubh; /* buffer containing super block */ + __u32 s_sblkno; /* offset of super-blocks in filesys */ + __u32 s_cblkno; /* offset of cg-block in filesys */ + __u32 s_iblkno; /* offset of inode-blocks in filesys */ + __u32 s_dblkno; /* offset of first data after cg */ + __u32 s_cgoffset; /* cylinder group offset in cylinder */ + __u32 s_cgmask; /* used to calc mod fs_ntrak */ + __u32 s_size; /* number of blocks (fragments) in fs */ + __u32 s_dsize; /* number of data blocks in fs */ + __u32 s_ncg; /* number of cylinder groups */ + __u32 s_bsize; /* size of basic blocks */ + __u32 s_fsize; /* size of fragments */ + __u32 s_fpb; /* fragments per block */ + __u32 s_minfree; /* minimum percentage of free blocks */ + __u32 s_bmask; /* `blkoff'' calc of blk offsets */ + __u32 s_fmask; /* s_fsize mask */ + __u32 s_bshift; /* `lblkno'' calc of logical blkno */ + __u32 s_fshift; /* s_fsize shift */ + __u32 s_fpbshift; /* fragments per block shift */ + __u32 s_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + __u32 s_sbsize; /* actual size of super block */ + __u32 s_csmask; /* csum block offset */ + __u32 s_csshift; /* csum block number */ + __u32 s_nindir; /* value of NINDIR */ + __u32 s_inopb; /* value of INOPB */ + __u32 s_nspf; /* value of NSPF */ + __u32 s_npsect; /* # sectors/track including spares */ + __u32 s_interleave; /* hardware sector interleave */ + __u32 s_trackskew; /* sector 0 skew, per track */ + __u32 s_csaddr; /* blk addr of cyl grp summary area */ + __u32 s_cssize; /* size of cyl grp summary area */ + __u32 s_cgsize; /* cylinder group size */ + __u32 s_ntrak; /* tracks per cylinder */ + __u32 s_nsect; /* sectors per track */ + __u32 s_spc; /* sectors per cylinder */ + __u32 s_ipg; /* inodes per group */ + __u32 s_fpg; /* fragments per group */ + __u32 s_cpc; /* cyl per cycle in postbl */ + __s64 s_qbmask; /* ~usb_bmask */ + __s64 s_qfmask; /* ~usb_fmask */ + __s32 s_postblformat; /* format of positional layout tables */ + __s32 s_nrpos; /* number of rotational positions */ + __s32 s_postbloff; /* (__s16) rotation block list head */ + __s32 s_rotbloff; /* (__u8) blocks for each rotation */ + + __u32 s_fpbmask; /* fragments per block mask */ + __u32 s_apb; /* address per block */ + __u32 s_2apb; /* address per block^2 */ + __u32 s_3apb; /* address per block^3 */ + __u32 s_apbmask; /* address per block mask */ + __u32 s_apbshift; /* address per block shift */ + __u32 s_2apbshift; /* address per block shift * 2 */ + __u32 s_3apbshift; /* address per block shift * 3 */ + __u32 s_nspfshift; /* number of sector per fragment shift */ + __u32 s_nspb; /* number of sector per block */ + __u32 s_inopf; /* inodes per fragment */ + __u32 s_sbbase; /* offset of NeXTstep superblock */ +}; + + +#define UFS_MAX_GROUP_LOADED 1 +#define UFS_CGNO_EMPTY uspi->s_ncg + struct ufs_sb_info { - struct ufs_superblock * s_raw_sb; - __u32 s_flags; /* internal flags for UFS code */ - __u32 s_ncg; /* used in ufs_read_inode */ - __u32 s_ipg; /* used in ufs_read_inode */ - __u32 s_fpg; - __u32 s_fsize; - __u32 s_fshift; - __u32 s_fmask; - __u32 s_bsize; - __u32 s_bmask; - __u32 s_bshift; - __u32 s_iblkno; - __u32 s_dblkno; - __u32 s_cgoffset; - __u32 s_cgmask; - __u32 s_inopb; - __u32 s_lshift; - __u32 s_lmask; - __u32 s_fsfrag; - __u32 s_blockbase; /* offset of NeXTstep superblock */ + struct ufs_sb_private_info * s_uspi; + struct ufs_csum * s_csp[UFS_MAXCSBUFS]; + int s_rename_lock; + struct wait_queue * s_rename_wait; + unsigned s_swab; + unsigned s_flags; + struct buffer_head ** s_ucg; + struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED]; + unsigned s_cgno[UFS_MAX_GROUP_LOADED]; + unsigned short s_cg_loaded; +}; + +/* + * Sizes of this structures are: + * ufs_super_block_first 512 + * ufs_super_block_second 512 + * ufs_super_block_third 356 + */ +struct ufs_super_block_first { + __u32 fs_link; + __u32 fs_rlink; + __u32 fs_sblkno; + __u32 fs_cblkno; + __u32 fs_iblkno; + __u32 fs_dblkno; + __u32 fs_cgoffset; + __u32 fs_cgmask; + __u32 fs_time; + __u32 fs_size; + __u32 fs_dsize; + __u32 fs_ncg; + __u32 fs_bsize; + __u32 fs_fsize; + __u32 fs_frag; + __u32 fs_minfree; + __u32 fs_rotdelay; + __u32 fs_rps; + __u32 fs_bmask; + __u32 fs_fmask; + __u32 fs_bshift; + __u32 fs_fshift; + __u32 fs_maxcontig; + __u32 fs_maxbpg; + __u32 fs_fragshift; + __u32 fs_fsbtodb; + __u32 fs_sbsize; + __u32 fs_csmask; + __u32 fs_csshift; + __u32 fs_nindir; + __u32 fs_inopb; + __u32 fs_nspf; + __u32 fs_optim; + __u32 fs_npsect; + __u32 fs_interleave; + __u32 fs_trackskew; + __u32 fs_id[2]; + __u32 fs_csaddr; + __u32 fs_cssize; + __u32 fs_cgsize; + __u32 fs_ntrak; + __u32 fs_nsect; + __u32 fs_spc; + __u32 fs_ncyl; + __u32 fs_cpg; + __u32 fs_ipg; + __u32 fs_fpg; + struct ufs_csum fs_cstotal; + __u8 fs_fmod; + __u8 fs_clean; + __u8 fs_ronly; + __u8 fs_flags; + __u8 fs_fsmnt[UFS_MAXMNTLEN - 212]; + +}; + +struct ufs_super_block_second { + __u8 fs_fsmnt[212]; + __u32 fs_cgrotor; + __u32 fs_csp[UFS_MAXCSBUFS]; + __u32 fs_maxcluster; + __u32 fs_cpc; + __u16 fs_opostbl[82]; +}; + +struct ufs_super_block_third { + __u16 fs_opostbl[46]; + union { + struct { + __s32 fs_sparecon[53];/* reserved for future constants */ + __s32 fs_reclaim; + __s32 fs_sparecon2[1]; + __s32 fs_state; /* file system state time stamp */ + __u32 fs_qbmask[2]; /* ~usb_bmask */ + __u32 fs_qfmask[2]; /* ~usb_fmask */ + } fs_sun; + struct { + __s32 fs_sparecon[50];/* reserved for future constants */ + __s32 fs_contigsumsize;/* size of cluster summary array */ + __s32 fs_maxsymlinklen;/* max length of an internal symlink */ + __s32 fs_inodefmt; /* format of on-disk inodes */ + __u32 fs_maxfilesize[2]; /* max representable file size */ + __u32 fs_qbmask[2]; /* ~usb_bmask */ + __u32 fs_qfmask[2]; /* ~usb_fmask */ + __s32 fs_state; /* file system state time stamp */ + } fs_44; + } fs_u; + __s32 fs_postblformat; + __s32 fs_nrpos; + __s32 fs_postbloff; + __s32 fs_rotbloff; + __s32 fs_magic; + __u8 fs_space[1]; }; #endif /* __LINUX_UFS_FS_SB_H */ diff -u --recursive --new-file v2.1.111/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h --- v2.1.111/linux/include/linux/vt_kern.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/vt_kern.h Sun Jul 26 14:40:19 1998 @@ -6,6 +6,7 @@ * with information needed by the vt package */ +#include #include /* @@ -16,7 +17,9 @@ * fixed. The linux/Documentation directory includes a code snippet * to save and restore the text font. */ +#ifdef CONFIG_VGA_CONSOLE #define BROKEN_GRAPHICS_PROGRAMS 1 +#endif extern struct vt_struct { int vc_num; /* The console number */ @@ -66,10 +69,12 @@ int con_get_trans_old(unsigned char * table); int con_set_trans_new(unsigned short * table); int con_get_trans_new(unsigned short * table); -void con_clear_unimap(struct unimapinit *ui); -int con_set_unimap(ushort ct, struct unipair *list); -int con_get_unimap(ushort ct, ushort *uct, struct unipair *list); -void con_set_default_unimap(void); +int con_clear_unimap(int currcons, struct unimapinit *ui); +int con_set_unimap(int currcons, ushort ct, struct unipair *list); +int con_get_unimap(int currcons, ushort ct, ushort *uct, struct unipair *list); +int con_set_default_unimap(int currcons); +void con_free_unimap(int currcons); +void con_protect_unimap(int currcons, int rdonly); /* vt.c */ diff -u --recursive --new-file v2.1.111/linux/include/net/ip6_route.h linux/include/net/ip6_route.h --- v2.1.111/linux/include/net/ip6_route.h Thu Mar 26 15:57:06 1998 +++ linux/include/net/ip6_route.h Sun Jul 26 23:35:57 1998 @@ -100,6 +100,7 @@ extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb); extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); +extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); extern void rt6_ifdown(struct device *dev); diff -u --recursive --new-file v2.1.111/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.1.111/linux/include/net/ipv6.h Thu May 14 19:47:44 1998 +++ linux/include/net/ipv6.h Sun Jul 26 23:35:57 1998 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $ + * $Id: ipv6.h,v 1.12 1998/07/15 05:05:02 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -117,6 +117,31 @@ __u8 nexthdr; __u8 *nhptr; }; + +struct ipv6_tlvtype +{ + u8 type; + u8 len; +}; + +struct ip6_ra_chain +{ + struct ip6_ra_chain *next; + struct sock *sk; + int sel; + void (*destructor)(struct sock *); +}; + +extern struct ip6_ra_chain *ip6_ra_chain; + +extern int ip6_ra_control(struct sock *sk, int sel, + void (*destructor)(struct sock *)); + + +extern int ip6_call_ra_chain(struct sk_buff *skb, int sel); + +extern int ip6_dstopt_unknown(struct sk_buff *skb, + struct ipv6_tlvtype *hdr); extern int ipv6_routing_header(struct sk_buff **skb, struct device *dev, diff -u --recursive --new-file v2.1.111/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.111/linux/include/net/sock.h Tue Jul 21 00:15:33 1998 +++ linux/include/net/sock.h Sun Jul 26 23:35:57 1998 @@ -469,6 +469,9 @@ #ifdef CONFIG_NETLINK struct netlink_opt af_netlink; #endif +#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) + struct econet_opt *af_econet; +#endif } protinfo; /* IP 'private area' or will be eventually. */ diff -u --recursive --new-file v2.1.111/linux/include/net/x25.h linux/include/net/x25.h --- v2.1.111/linux/include/net/x25.h Sun Nov 30 14:00:39 1997 +++ linux/include/net/x25.h Sun Jul 26 23:35:57 1998 @@ -147,6 +147,7 @@ extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *); extern void x25_destroy_socket(struct sock *); extern int x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int); +extern void x25_kill_by_neigh(struct x25_neigh *); #include @@ -161,6 +162,7 @@ extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *); extern int x25_create_facilities(unsigned char *, struct x25_facilities *); extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *); +extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); /* x25_in.c */ extern int x25_process_rx_frame(struct sock *, struct sk_buff *); diff -u --recursive --new-file v2.1.111/linux/init/main.c linux/init/main.c --- v2.1.111/linux/init/main.c Sun Jul 26 11:57:19 1998 +++ linux/init/main.c Sun Jul 26 11:54:52 1998 @@ -48,6 +48,10 @@ #include #endif +#ifdef CONFIG_MTRR +# include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -1106,11 +1110,21 @@ #if defined(CONFIG_QUOTA) dquot_init_hash(); #endif + printk("POSIX conformance testing by UNIFIX\n"); + check_bugs(); + #ifdef __SMP__ smp_init(); #endif - printk("POSIX conformance testing by UNIFIX\n"); - check_bugs(); + +#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ +/* + * We should probably create some architecture-dependent "fixup after + * everything is up" style function where this would belong better + * than in init/main.c.. + */ + mtrr_init (); +#endif sock_init(); #ifdef CONFIG_SYSCTL diff -u --recursive --new-file v2.1.111/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.111/linux/kernel/sched.c Sun Jul 26 11:57:19 1998 +++ linux/kernel/sched.c Sun Jul 26 11:56:39 1998 @@ -105,10 +105,19 @@ static inline void reschedule_idle(struct task_struct * p) { + /* * For SMP, we try to see if the CPU the task used * to run on is idle.. */ +#if 0 + /* + * Disable this for now. Ingo has some interesting + * code that looks too complex, and I have some ideas, + * but in the meantime.. One problem is that "wakeup()" + * can be (and is) called before we've even initialized + * SMP completely, so.. + */ #ifdef __SMP__ int want_cpu = p->processor; @@ -131,6 +140,7 @@ } } while (--i > 0); } +#endif #endif if (p->policy != SCHED_OTHER || p->counter > current->counter + 3) current->need_resched = 1; diff -u --recursive --new-file v2.1.111/linux/mm/memory.c linux/mm/memory.c --- v2.1.111/linux/mm/memory.c Wed Jul 1 19:38:57 1998 +++ linux/mm/memory.c Sun Jul 26 13:55:43 1998 @@ -127,16 +127,23 @@ */ void clear_page_tables(struct task_struct * tsk) { + pgd_t * page_dir = tsk->mm->pgd; int i; - pgd_t * page_dir; - page_dir = tsk->mm->pgd; - if (!page_dir || page_dir == swapper_pg_dir) { - printk("%s trying to clear kernel page-directory: not good\n", tsk->comm); - return; - } + if (!page_dir || page_dir == swapper_pg_dir) + goto out_bad; for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) free_one_pgd(page_dir + i); + + /* keep the page table cache within bounds */ + check_pgt_cache(); + return; + +out_bad: + printk(KERN_ERR + "clear_page_tables: %s trying to clear kernel pgd\n", + tsk->comm); + return; } /* @@ -146,19 +153,26 @@ */ void free_page_tables(struct mm_struct * mm) { + pgd_t * page_dir = mm->pgd; int i; - pgd_t * page_dir; - page_dir = mm->pgd; - if (page_dir) { - if (page_dir == swapper_pg_dir) { - printk("free_page_tables: Trying to free kernel pgd\n"); - return; - } - for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) - free_one_pgd(page_dir + i); - pgd_free(page_dir); - } + if (!page_dir) + goto out; + if (page_dir == swapper_pg_dir) + goto out_bad; + for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) + free_one_pgd(page_dir + i); + pgd_free(page_dir); + + /* keep the page table cache within bounds */ + check_pgt_cache(); +out: + return; + +out_bad: + printk(KERN_ERR + "free_page_tables: Trying to free kernel pgd\n"); + return; } int new_page_tables(struct task_struct * tsk) diff -u --recursive --new-file v2.1.111/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.111/linux/mm/mmap.c Sun Jul 26 11:57:20 1998 +++ linux/mm/mmap.c Sun Jul 26 13:51:42 1998 @@ -196,9 +196,14 @@ if ((prot & PROT_WRITE) && !(file->f_mode & 2)) return -EACCES; + /* Make sure we don't allow writing to an append-only file.. */ + if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2)) + return -EACCES; + /* make sure there are no mandatory locks on the file. */ if (locks_verify_locked(file->f_dentry->d_inode)) return -EAGAIN; + /* fall through */ case MAP_PRIVATE: if (!(file->f_mode & 1)) diff -u --recursive --new-file v2.1.111/linux/mm/simp.c linux/mm/simp.c --- v2.1.111/linux/mm/simp.c Wed Apr 8 19:36:29 1998 +++ linux/mm/simp.c Wed Dec 31 16:00:00 1969 @@ -1,435 +0,0 @@ -#define NULL 0 -/* - * mm/simp.c -- simple allocator for cached objects - * - * (C) 1997 Thomas Schoebel-Theuer - */ - -#include -#include -#include -#include -#include - -/* The next two defines can be independently enabled for debugging */ -/*#define DEBUG*/ -/*#define DEAD_BEEF*/ - -#ifdef DEAD_BEEF -#define DEBUG_BEEF 1 -#else -#define DEBUG_BEEF 0 -#endif - -#ifdef __SMP__ -#define NR_PROCESSORS NR_CPUS -#define GLOBAL_SIZE CHUNK_SIZE -#else -#define NR_PROCESSORS 1 -#define GLOBAL_SIZE PAGE_SIZE -#endif - -#define POSTBUFFER_SIZE 63 -#define ORDER 2 -#define CHUNK_SIZE (PAGE_SIZE*(1<lock); - } - - spin_lock(&global->lock); - simp = &global->simps[global->nr_simps++]; - spin_unlock(&global->lock); - - if(global->nr_simps >= MAX_SIMPS) { - printk("SIMP: too many simps allocated\n"); - return NULL; - } - memset(simp, 0, sizeof(struct simp)); - spin_lock_init(&simp->lock); - strncpy(simp->name, name, 15); - simp->size = size; - simp->real_size = real_size = ALIGN_CACHE(size); - /* allow aggregation of very small objects in 2-power fractions of - * cachelines */ - fraction = COLOR_INCREMENT / 2; - while(size <= fraction && fraction >= sizeof(void*)) { - simp->real_size = fraction; - fraction >>= 1; - } - simp->first_ctor = first_ctor; - simp->again_ctor = again_ctor; - simp->dtor = dtor; - - real_size += sizeof(void*); - simp->max_elems = (CHUNK_SIZE - HEADER_SIZE) / real_size; - simp->max_color = (CHUNK_SIZE - HEADER_SIZE) % real_size; - for(cpu = 0; cpu < NR_PROCESSORS; cpu++) { - struct per_processor * private = &simp->private[cpu]; - private->buffer_pos = private->postbuffer; - } - return simp; -} - -/* Do *not* inline this, it clobbers too many registers... */ -static void alloc_header(struct simp * simp) -{ - struct header * hdr; - char * ptr; - void ** index; - long count; - - spin_unlock(&simp->lock); - for(;;) { - hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER); - if(hdr) - break; - if(!simp_garbage()) - return; - } -#ifdef DEBUG - if(CHUNK_BASE(hdr) != hdr) - panic("simp: bad kernel page alignment"); -#endif - - memset(hdr, 0, HEADER_SIZE); -#ifdef DEBUG - memcpy(hdr->magic, global_magic, sizeof(global_magic)); -#endif - hdr->father = simp; - hdr->again_ctor = simp->again_ctor; - hdr->first_ctor = simp->first_ctor; - - /* note: races on simp->color don't produce any error :-) */ - ptr = ((char*)hdr) + HEADER_SIZE + simp->color; - index = CHUNK_END(hdr); - for(count = 0; count < simp->max_elems; count++) { - *--index = ptr; - ptr += simp->real_size; - /* note: constructors are not called here in bunch but - * instead at each single simp_alloc(), in order - * to maximize chances that the cache will be - * polluted after a simp_alloc() anyway, - * and not here. */ - } - hdr->index = hdr->fresh = hdr->emptypos = index; - - spin_lock(&simp->lock); - simp->color += COLOR_INCREMENT; - if(simp->color >= simp->max_color) - simp->color = 0; - hdr->next = simp->usable_list; - simp->usable_list = hdr; -} - -/* current x86 memcpy() is horribly moving around registers for nothing, - * is doing unnecessary work if the size is dividable by a power-of-two, - * and it clobbers way too many registers. - * This results in nearly any other register being transfered to stack. - * Fixing this would be a major win for the whole kernel! - */ -static void ** bunch_alloc(struct simp * simp, void ** buffer) -{ - struct header * hdr; - void ** index; - void ** to; - void ** end; - structor todo; - long length; - - spin_lock(&simp->lock); - hdr = simp->usable_list; - if(!hdr) { - alloc_header(simp); - hdr = simp->usable_list; - if(!hdr) { - spin_unlock(&simp->lock); - *buffer = NULL; - return buffer+1; - } - } - - index = hdr->index; - end = hdr->fresh; - todo = hdr->again_ctor; - if(index == end) { - end = CHUNK_END(hdr); - todo = hdr->first_ctor; - } - to = index + POSTBUFFER_SIZE/2; - if(to >= end) { - to = end; - if(to == CHUNK_END(hdr)) { - simp->usable_list = hdr->next; - hdr->next = NULL; - } - } - if(to > hdr->fresh) - hdr->fresh = to; - hdr->index = to; - length = ((unsigned long)to) - (unsigned long)index; - to = buffer + (length/sizeof(void**)); - - memcpy(buffer, index, length); - - spin_unlock(&simp->lock); - - if(todo) { - do { - todo(*buffer++); - } while(buffer < to); - } - return to; -} - -void * simp_alloc(struct simp * simp) -{ -#ifdef __SMP__ - const long cpu = smp_processor_id(); - struct per_processor * priv = &simp->private[cpu]; -#else -#define priv (&simp->private[0]) /*fool gcc to use no extra register*/ -#endif - void ** buffer_pos = priv->buffer_pos; - void * res; - - if(buffer_pos == priv->postbuffer) { - buffer_pos = bunch_alloc(simp, buffer_pos); - } - buffer_pos--; - res = *buffer_pos; - priv->buffer_pos = buffer_pos; - return res; -} - -#ifdef DEBUG -long check_header(struct header * hdr, void * ptr) -{ - void ** test; - - if(!hdr) { - printk("SIMP: simp_free() with NULL pointer\n"); - return 1; - } - if(strncmp(hdr->magic, global_magic, 32)) { - printk("SIMP: simpe_free() with bad ptr %p, or header corruption\n", ptr); - return 1; - } - /* This is brute force, but I don't want to pay for any - * overhead if debugging is not enabled, in particular - * no space overhead for keeping hashtables etc. */ - test = hdr->index; - while(test < CHUNK_END(hdr)) { - if(*test++ == ptr) { - printk("SIMP: trying to simp_free(%p) again\n", ptr); - return 1; - } - } - return 0; -} -#endif - -static void ** bunch_free(struct simp * simp, void ** buffer) -{ - void ** stop; - - stop = buffer - POSTBUFFER_SIZE/3; - - spin_lock(&simp->lock); - while(buffer > stop) { - void * elem = buffer[-1]; - struct header * hdr = CHUNK_BASE(elem); - void ** index = hdr->index; - index--; - hdr->index = index; - *index = elem; - if(!hdr->next) { - hdr->next = simp->usable_list; - simp->usable_list = hdr; - } - - buffer -= 2; - elem = *buffer; - hdr = CHUNK_BASE(elem); - index = hdr->index; - index--; - hdr->index = index; - *index = elem; - if(!hdr->next) { - hdr->next = simp->usable_list; - simp->usable_list = hdr; - } - } - spin_unlock(&simp->lock); - global->changed_flag = 1; - return buffer; -} - -void simp_free(void * objp) -{ - struct header * hdr; - void ** buffer_pos; - struct per_processor * private; -#ifdef __SMP__ - const long cpu = smp_processor_id(); -#else - const long cpu = 0; -#endif - - hdr = CHUNK_BASE(objp); -#ifdef DEBUG - if(check_header(hdr, objp)) - return; -#endif - - private = &hdr->father->private[cpu]; - buffer_pos = private->buffer_pos; - if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) { - buffer_pos = bunch_free(hdr->father, buffer_pos); - } - - *buffer_pos++ = objp; - private->buffer_pos = buffer_pos; - -#ifdef DEAD_BEEF - { - unsigned int * ptr = (unsigned int*)objp; - int count = (hdr->father->real_size - ELEM_SIZE) / sizeof(unsigned int); - while(count--) - *ptr++ = 0xdeadbeef; - } -#endif -} - -long simp_garbage(void) -{ - int i; - int res; - - if(!global->changed_flag) - return 0; /* shortcut */ - /* Note: costs do not matter here. Any heavy thrashing of - * simp chunks that could be caused by pools stealing each - * other's memory has to be considered a BUG :-) - * Simply avoid memory shortages by conservative allocating - * policies. - */ - global->changed_flag = 0; - res = 0; - for(i = 0; i < global->nr_simps; i++) { - struct simp * simp = &global->simps[i]; - struct header ** base = &simp->usable_list; - struct header * del; - - spin_lock(&simp->lock); - del = *base; - while(del) { - if(del->index == del->emptypos) { - if(simp->dtor) { - void ** ptr = del->index; - while(ptr < CHUNK_END(del)) { - simp->dtor(*ptr++); - } - } - *base = del->next; -#ifdef DEBUG - memset(del, 0, CHUNK_SIZE); -#endif - free_pages((unsigned long)del, ORDER); - res++; - } else - base = &del->next; - del = *base; - } - spin_unlock(&simp->lock); - } - return res; -} - diff -u --recursive --new-file v2.1.111/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.111/linux/mm/swapfile.c Wed Jun 24 22:54:14 1998 +++ linux/mm/swapfile.c Sun Jul 26 11:46:46 1998 @@ -532,6 +532,7 @@ error = blkdev_open(swap_dentry->d_inode, &filp); if (error) goto bad_swap_2; + set_blocksize(p->swap_device, PAGE_SIZE); error = -ENODEV; if (!p->swap_device || (blk_size[MAJOR(p->swap_device)] && diff -u --recursive --new-file v2.1.111/linux/net/Makefile linux/net/Makefile --- v2.1.111/linux/net/Makefile Sun Nov 30 14:00:39 1997 +++ linux/net/Makefile Sun Jul 26 23:35:57 1998 @@ -9,7 +9,8 @@ MOD_SUB_DIRS := ipv4 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ - netrom rose lapb x25 wanrouter netlink sched packet sunrpc #decnet + netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ + econet #decnet SUB_DIRS := core ethernet sched MOD_LIST_NAME := NET_MISC_MODULES @@ -137,6 +138,14 @@ else ifeq ($(CONFIG_DECNET),m) MOD_SUB_DIRS += decnet + endif +endif + +ifeq ($(CONFIG_ECONET),y) +SUB_DIRS += econet +else + ifeq ($(CONFIG_ECONET),m) + MOD_SUB_DIRS += econet endif endif diff -u --recursive --new-file v2.1.111/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.111/linux/net/ax25/af_ax25.c Sun Jul 26 11:57:20 1998 +++ linux/net/ax25/af_ax25.c Sun Jul 26 23:35:57 1998 @@ -91,7 +91,7 @@ * Jonathan(G4KLX) Support for packet forwarding. * AX.25 036 Jonathan(G4KLX) Major restructuring. * Joerg(DL1BKE) Fixed DAMA Slave. - * Jonathan(G4KLX) Fix widlcard listen parameter setting. + * Jonathan(G4KLX) Fix wildcard listen parameter setting. * AX.25 037 Jonathan(G4KLX) New timer architecture. * AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel * independent of AX25_MAX_DIGIS used by applications. diff -u --recursive --new-file v2.1.111/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.111/linux/net/core/skbuff.c Thu May 14 19:47:44 1998 +++ linux/net/core/skbuff.c Sun Jul 26 23:35:57 1998 @@ -77,11 +77,22 @@ static kmem_cache_t *skbuff_head_cache; /* - * Strings we don't want inline's duplicating + * Keep out-of-line to prevent kernel bloat. + * __builtin_return_address is not used because it is not always + * reliable. */ - -const char skb_push_errstr[]="skpush:under: %p:%d"; -const char skb_put_errstr[] ="skput:over: %p:%d"; + +void skb_over_panic(struct sk_buff *skb, int sz, void *here) +{ + panic("skput:over: %p:%d put:%d dev:%s", + here, skb->len, sz, skb->dev ? skb->dev->name : ""); +} + +void skb_under_panic(struct sk_buff *skb, int sz, void *here) +{ + panic("skput:over: %p:%d put:%d dev:%s", + here, skb->len, sz, skb->dev ? skb->dev->name : ""); +} void show_net_buffers(void) { diff -u --recursive --new-file v2.1.111/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.111/linux/net/core/sock.c Tue Jun 23 10:01:30 1998 +++ linux/net/core/sock.c Sun Jul 26 23:35:57 1998 @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -212,7 +213,7 @@ are treated in BSD as hints */ if (val > sysctl_wmem_max) - return 0; + val = sysctl_wmem_max; sk->sndbuf = max(val*2,2048); @@ -230,7 +231,7 @@ are treated in BSD as hints */ if (val > sysctl_rmem_max) - return 0; + val = sysctl_rmem_max; /* FIXME: is this lower bound the right one? */ sk->rcvbuf = max(val*2,256); @@ -495,10 +496,11 @@ kmem_cache_free(sk_cachep, sk); } -void sk_init(void) +__initfunc(void sk_init(void)) { sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0, SLAB_HWCACHE_ALIGN, 0, 0); + } /* diff -u --recursive --new-file v2.1.111/linux/net/econet/econet.c linux/net/econet/econet.c --- v2.1.111/linux/net/econet/econet.c Fri May 8 23:14:57 1998 +++ linux/net/econet/econet.c Sun Jul 26 23:35:57 1998 @@ -738,8 +738,8 @@ econet_release, econet_bind, sock_no_connect, - NULL, - NULL, + sock_no_socketpair, + sock_no_accept, econet_getname, datagram_poll, econet_ioctl, diff -u --recursive --new-file v2.1.111/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.111/linux/net/ipv4/arp.c Thu May 14 19:47:44 1998 +++ linux/net/ipv4/arp.c Sun Jul 26 23:35:57 1998 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $ + * Version: $Id: arp.c,v 1.67 1998/06/19 13:22:31 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. * * Fixes: - * Alan Cox : Removed the ethernet assumptions in + * Alan Cox : Removed the Ethernet assumptions in * Florian's code * Alan Cox : Fixed some small errors in the ARP * logic @@ -230,7 +230,7 @@ neigh->ops = &arp_direct_ops; neigh->output = neigh->ops->queue_xmit; } else { - /* Good devices (checked by reading texts, but only ethernet is + /* Good devices (checked by reading texts, but only Ethernet is tested) ARPHRD_ETHER: (ethernet, apfddi) @@ -240,7 +240,7 @@ ARPHRD_ARCNET: etc. etc. etc. - ARPHRD_IPDDP will also work, if author repaires it. + ARPHRD_IPDDP will also work, if author repairs it. I did not it, because this driver does not work even in old paradigm. */ @@ -1099,7 +1099,7 @@ #ifdef CONFIG_AX25_MODULE /* - * ax25 -> ascii conversion + * ax25 -> ASCII conversion */ char *ax2asc(ax25_address *a) { diff -u --recursive --new-file v2.1.111/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c --- v2.1.111/linux/net/ipv4/fib_hash.c Tue Mar 17 22:18:16 1998 +++ linux/net/ipv4/fib_hash.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * IPv4 FIB: lookup engine and maintenance routines. * - * Version: $Id: fib_hash.c,v 1.3 1998/03/08 05:56:16 davem Exp $ + * Version: $Id: fib_hash.c,v 1.4 1998/07/15 05:05:08 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -274,7 +274,7 @@ #endif ) { if (matched) - return 1; + break; continue; } matched = 1; diff -u --recursive --new-file v2.1.111/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.1.111/linux/net/ipv4/icmp.c Tue Jun 23 10:01:30 1998 +++ linux/net/ipv4/icmp.c Sun Jul 26 23:35:57 1998 @@ -3,7 +3,7 @@ * * Alan Cox, * - * Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $ + * Version: $Id: icmp.c,v 1.44 1998/06/16 04:38:27 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.1.111/linux/net/ipv4/ip_fragment.c Tue Jun 23 10:01:30 1998 +++ linux/net/ipv4/ip_fragment.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $ + * Version: $Id: ip_fragment.c,v 1.38 1998/06/16 04:38:29 davem Exp $ * * Authors: Fred N. van Kempen * Alan Cox diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.1.111/linux/net/ipv4/ip_output.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv4/ip_output.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $ + * Version: $Id: ip_output.c,v 1.59 1998/07/15 05:05:15 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -814,7 +814,7 @@ * will inherit fixed options. */ if (offset == 0) - ip_options_fragment(skb2); + ip_options_fragment(skb); /* * Added AC : If we are fragmenting a fragment that's not the diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.1.111/linux/net/ipv4/ip_sockglue.c Thu May 14 19:47:44 1998 +++ linux/net/ipv4/ip_sockglue.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.36 1998/07/15 05:05:06 davem Exp $ * * Authors: see ip.c * @@ -70,17 +70,11 @@ static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb) { - if (IPCB(skb)->opt.optlen == 0) - return; - put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl); } static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb) { - if (IPCB(skb)->opt.optlen == 0) - return; - put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos); } diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.1.111/linux/net/ipv4/ipconfig.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv4/ipconfig.c Sun Jul 26 23:35:57 1998 @@ -1,5 +1,5 @@ /* - * $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $ + * $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $ * * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied * information to configure own IP address and routes. @@ -323,7 +323,7 @@ if (rarp->ar_op != htons(ARPOP_RREPLY)) goto drop; - /* If it's not ethernet, delete it. */ + /* If it's not Ethernet, delete it. */ if (rarp->ar_pro != htons(ETH_P_IP)) goto drop; diff -u --recursive --new-file v2.1.111/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v2.1.111/linux/net/ipv4/rarp.c Tue Mar 17 22:18:16 1998 +++ linux/net/ipv4/rarp.c Sun Jul 26 23:35:57 1998 @@ -3,11 +3,11 @@ * Copyright (C) 1994 by Ross Martin * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche * - * $Id: rarp.c,v 1.24 1998/03/08 05:56:30 davem Exp $ + * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $ * * This module implements the Reverse Address Resolution Protocol * (RARP, RFC 903), which is used to convert low level addresses such - * as ethernet addresses into high level addresses such as IP addresses. + * as Ethernet addresses into high level addresses such as IP addresses. * The most common use of RARP is as a means for a diskless workstation * to discover its IP address during a network boot. * @@ -19,7 +19,7 @@ *** unless you have all the rest to boot the box from it. ** * - * Currently, only ethernet address -> IP address is likely to work. + * Currently, only Ethernet address -> IP address is likely to work. * (Is RARP ever used for anything else?) * * This code is free software; you can redistribute it and/or diff -u --recursive --new-file v2.1.111/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.1.111/linux/net/ipv4/route.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv4/route.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $ + * Version: $Id: route.c,v 1.54 1998/07/15 05:05:22 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1166,7 +1166,7 @@ } /* Multicast recognition logic is moved from route cache to here. - The problem was that too many ethernet cards have broken/missing + The problem was that too many Ethernet cards have broken/missing hardware multicast filters :-( As result the host on multicasting network acquires a lot of useless route cache entries, sort of SDR messages from all the world. Now we try to get rid of them. @@ -1496,7 +1496,7 @@ nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0; r->rtm_family = AF_INET; r->rtm_dst_len = 32; - r->rtm_src_len = 32; + r->rtm_src_len = 0; r->rtm_tos = rt->key.tos; r->rtm_table = RT_TABLE_MAIN; r->rtm_type = rt->rt_type; @@ -1509,9 +1509,16 @@ o = skb->tail; #endif RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); - RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src); + if (rt->key.src) { + r->rtm_src_len = 32; + RTA_PUT(skb, RTA_SRC, 4, &rt->key.src); + } if (rt->u.dst.dev) RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); + if (rt->key.iif) + RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); + else if (rt->rt_src != rt->key.src) + RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); if (rt->rt_dst != rt->rt_gateway) RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); #ifdef CONFIG_RTNL_OLD_IFINFO @@ -1533,7 +1540,6 @@ if (mx->rta_len == RTA_LENGTH(0)) skb_trim(skb, (u8*)mx - skb->data); #endif - RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); ci.rta_lastuse = jiffies - rt->u.dst.lastuse; ci.rta_used = atomic_read(&rt->u.dst.refcnt); ci.rta_clntref = atomic_read(&rt->u.dst.use); diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.111/linux/net/ipv4/tcp.c Tue Jul 21 00:15:33 1998 +++ linux/net/ipv4/tcp.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $ + * Version: $Id: tcp.c,v 1.116 1998/07/26 03:06:54 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.111/linux/net/ipv4/tcp_input.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv4/tcp_input.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $ + * Version: $Id: tcp_input.c,v 1.121 1998/07/15 04:39:12 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -156,8 +156,8 @@ } } -/* Calculate rto without backoff. This is the second half of Van Jacobsons - * routine refered to above. +/* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. */ static __inline__ void tcp_set_rto(struct tcp_opt *tp) @@ -186,13 +186,21 @@ } /* WARNING: this must not be called if tp->saw_timestamp was false. */ -extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq) +extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp, + __u32 start_seq, __u32 end_seq) { /* From draft-ietf-tcplw-high-performance: the correct * test is last_ack_sent <= end_seq. * (RFC1323 stated last_ack_sent < end_seq.) + * + * HOWEVER: The current check contradicts the draft statements. + * It has been done for good reasons. + * The implemented check improves security and eliminates + * unnecessary RTT overestimation. + * 1998/06/27 Andrey V. Savochkin */ - if (!before(end_seq, tp->last_ack_sent)) { + if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) && + !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) { /* PAWS bug workaround wrt. ACK frames, the PAWS discard * extra check below makes sure this can only happen * for pure ACK frames. -DaveM @@ -1657,7 +1665,9 @@ goto discard; } } - tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq); + tcp_replace_ts_recent(sk, tp, + TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(skb)->end_seq); } } @@ -2031,7 +2041,9 @@ goto discard; } } - tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq); + tcp_replace_ts_recent(sk, tp, + TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(skb)->end_seq); } } diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.111/linux/net/ipv4/tcp_ipv4.c Thu May 14 19:47:45 1998 +++ linux/net/ipv4/tcp_ipv4.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $ + * Version: $Id: tcp_ipv4.c,v 1.148 1998/07/23 12:28:25 freitag Exp $ * * IPv4 specific functions * @@ -1033,7 +1033,14 @@ return dopt; } -int sysctl_max_syn_backlog = 1024; +/* + * Maximum number of SYN_RECV sockets in queue per LISTEN socket. + * One SYN_RECV socket costs about 80bytes on a 32bit machine. + * It would be better to replace it with a global counter for all sockets + * but then some measure against one socket starving all other sockets + * would be needed. + */ +int sysctl_max_syn_backlog = 128; struct or_calltable or_ipv4 = { tcp_v4_send_synack, diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.111/linux/net/ipv4/tcp_output.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv4/tcp_output.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $ + * Version: $Id: tcp_output.c,v 1.92 1998/06/19 13:22:44 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -166,10 +166,10 @@ } } -/* Function to create two new tcp segments. Shrinks the given segment +/* Function to create two new TCP segments. Shrinks the given segment * to the specified size and appends a new segment with the rest of the - * packet to the list. This won't be called frenquently, I hope... - * Remember, these are still header-less SKB's at this point. + * packet to the list. This won't be called frequently, I hope. + * Remember, these are still headerless SKBs at this point. */ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len) { @@ -256,7 +256,7 @@ * * a) following SWS avoidance [and Nagle algorithm] * b) not exceeding our congestion window. - * c) not retransmiting [Nagle] + * c) not retransmitting [Nagle] */ while((skb = tp->send_head) && tcp_snd_test(sk, skb)) { if (skb->len > mss_now) { @@ -288,14 +288,14 @@ * 2. We limit memory per socket * * RFC 1122: - * "the suggested [SWS] avoidance algoritm for the receiver is to keep + * "the suggested [SWS] avoidance algorithm for the receiver is to keep * RECV.NEXT + RCV.WIN fixed until: * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" * * i.e. don't raise the right edge of the window until you can raise * it at least MSS bytes. * - * Unfortunately, the recomended algorithm breaks header prediction, + * Unfortunately, the recommended algorithm breaks header prediction, * since header prediction assumes th->window stays fixed. * * Strictly speaking, keeping th->window fixed violates the receiver @@ -474,7 +474,7 @@ /* This retransmits one SKB. Policy decisions and retransmit queue * state updates are done by the caller. Returns non-zero if an - * error occured which prevented the send. + * error occurred which prevented the send. */ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) { @@ -505,7 +505,7 @@ tp->retrans_out++; /* Make a copy, if the first transmission SKB clone we made - * is still in somebodies hands, else make a clone. + * is still in somebody's hands, else make a clone. */ TCP_SKB_CB(skb)->when = jiffies; if(skb_cloned(skb)) @@ -827,7 +827,7 @@ mss = min(mss, sk->user_mss); if (mss < 1) { - printk(KERN_DEBUG "intial sk->mss below 1\n"); + printk(KERN_DEBUG "initial sk->mss below 1\n"); mss = 1; /* Sanity limit */ } diff -u --recursive --new-file v2.1.111/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.111/linux/net/ipv6/addrconf.c Thu May 14 19:47:45 1998 +++ linux/net/ipv6/addrconf.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $ + * $Id: addrconf.c,v 1.43 1998/07/15 05:05:32 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1034,7 +1034,7 @@ struct inet6_dev * idev; if (dev->type != ARPHRD_ETHER) { - /* Alas, we support only ethernet autoconfiguration. */ + /* Alas, we support only Ethernet autoconfiguration. */ return; } @@ -1609,7 +1609,7 @@ { inet6_rtm_newroute, NULL, }, { inet6_rtm_delroute, NULL, }, - { NULL, inet6_dump_fib, }, + { inet6_rtm_getroute, inet6_dump_fib, }, { NULL, NULL, }, }; #endif diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c --- v2.1.111/linux/net/ipv6/ip6_input.c Thu May 7 22:51:56 1998 +++ linux/net/ipv6/ip6_input.c Sun Jul 26 23:35:57 1998 @@ -6,7 +6,7 @@ * Pedro Roque * Ian P. Morris * - * $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $ + * $Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -65,11 +65,6 @@ /* New header structures */ -struct ipv6_tlvtype { - u8 type; - u8 len; -}; - struct tlvtype_proc { u8 type; int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr, @@ -82,7 +77,7 @@ {255, NULL} }; -static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) +int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) { struct in6_addr *daddr; int pos; @@ -91,7 +86,7 @@ * unkown destination option type */ - pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw; + pos = (__u8 *) hdr - (__u8 *) skb->nh.raw; /* I think this is correct please check - IPM */ diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c --- v2.1.111/linux/net/ipv6/ip6_output.c Sat May 2 14:19:55 1998 +++ linux/net/ipv6/ip6_output.c Sun Jul 26 23:35:57 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_output.c,v 1.12 1998/04/11 22:11:06 davem Exp $ + * $Id: ip6_output.c,v 1.13 1998/07/15 05:05:38 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -32,6 +32,7 @@ #include #include #include +#include static u32 ipv6_fragmentation_id = 1; @@ -519,25 +520,104 @@ return err; } +int ip6_call_ra_chain(struct sk_buff *skb, int sel) +{ + struct ip6_ra_chain *ra; + struct sock *last = NULL; + + for (ra = ip6_ra_chain; ra; ra = ra->next) { + struct sock *sk = ra->sk; + if (sk && ra->sel == sel) { + if (last) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->sk = last; + rawv6_rcv(skb2, skb2->dev, &skb2->nh.ipv6h->saddr, + &skb2->nh.ipv6h->daddr, NULL, skb2->len); + } + } + last = sk; + } + } + + if (last) { + skb->sk = last; + rawv6_rcv(skb, skb->dev, &skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, NULL, skb->len); + return 1; + } + return 0; +} + int ip6_forward(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = skb->nh.ipv6h; int size; - if (ipv6_devconf.forwarding == 0) { - kfree_skb(skb); - return -EINVAL; - } + if (ipv6_devconf.forwarding == 0) + goto drop; /* * check hop-by-hop options present */ -#if 0 - if (hdr->nexthdr == NEXTHDR_HOP) - { + /* + * Note, that NEXTHDR_HOP header must be checked + * always at the most beginning of ipv6_rcv. + * The result should be saved somewhere, but + * we do not it for now. Alas. Let's do it here. --ANK + * + * Second note: we DO NOT make any processing on + * RA packets, pushing them to user level AS IS + * without ane WARRANTY that application will able + * to interpret them. The reson is that we + * cannot make anything clever here. + * + * We are not end-node, so that if packet contains + * AH/ESP, we cannot make anything. + * Defragmentation also would be mistake, RA packets + * cannot be fragmented, because there is no warranty + * that different fragments will go along one path. --ANK + */ + if (hdr->nexthdr == NEXTHDR_HOP) { + int ra_value = -1; + u8 *ptr = (u8*)(skb->nh.ipv6h+1); + int len = (ptr[1]+1)<<3; + + if (len + sizeof(struct ipv6hdr) > skb->len) + goto drop; + + ptr += 2; + len -= 2; + while (len > 0) { + u8 *opt; + int optlen; + + if (ptr[0] == 0) { + len--; + ptr++; + continue; + } + opt = ptr; + optlen = ptr[1]+1; + + len -= optlen; + ptr += optlen; + if (len < 0) + goto drop; + + if (opt[0] == 20) { + /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */ + if (optlen < 4) + goto drop; + ra_value = opt[2] + (opt[3]<<8); + } else if (!ip6_dstopt_unknown(skb, (struct ipv6_tlvtype*)opt)) + goto drop; + } + if (ra_value>=0 && ip6_call_ra_chain(skb, ra_value)) + return 0; } -#endif + /* * check and decrement ttl */ @@ -589,4 +669,8 @@ dst->output(skb); return 0; + +drop: + kfree_skb(skb); + return -EINVAL; } diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.1.111/linux/net/ipv6/ipv6_sockglue.c Thu May 14 19:47:45 1998 +++ linux/net/ipv6/ipv6_sockglue.c Sun Jul 26 23:35:57 1998 @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43:13 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.22 1998/07/15 05:05:39 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -67,6 +67,45 @@ 0 }; +struct ip6_ra_chain *ip6_ra_chain; + +int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) +{ + struct ip6_ra_chain *ra, *new_ra, **rap; + + /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ + if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW) + return -EINVAL; + + new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; + + for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { + if (ra->sk == sk) { + if (sel>=0) { + if (new_ra) + kfree(new_ra); + return -EADDRINUSE; + } + *rap = ra->next; + if (ra->destructor) + ra->destructor(sk); + kfree(ra); + return 0; + } + } + if (new_ra == NULL) + return -ENOBUFS; + new_ra->sk = sk; + new_ra->sel = sel; + new_ra->destructor = destructor; + start_bh_atomic(); + new_ra->next = ra; + *rap = new_ra; + end_bh_atomic(); + return 0; +} + + int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { @@ -74,6 +113,9 @@ int val, err; int retv = -ENOPROTOOPT; + if(level==SOL_IP && sk->type != SOCK_RAW) + return udp_prot.setsockopt(sk, level, optname, optval, optlen); + if(level!=SOL_IPV6) goto out; @@ -197,7 +239,11 @@ retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); else retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); + break; } + case IPV6_ROUTER_ALERT: + retv = ip6_ra_control(sk, val, NULL); + break; }; out: @@ -207,7 +253,11 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { - return 0; + if(level==SOL_IP && sk->type != SOCK_RAW) + return udp_prot.getsockopt(sk, level, optname, optval, optlen); + if(level!=SOL_IPV6) + return -ENOPROTOOPT; + return -EINVAL; } #if defined(MODULE) && defined(CONFIG_SYSCTL) diff -u --recursive --new-file v2.1.111/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.1.111/linux/net/ipv6/raw.c Thu Mar 26 15:57:13 1998 +++ linux/net/ipv6/raw.c Sun Jul 26 23:35:58 1998 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.19 1998/03/20 09:12:20 davem Exp $ + * $Id: raw.c,v 1.20 1998/07/15 05:05:41 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -596,6 +596,8 @@ { sk->state = TCP_CLOSE; ipv6_sock_mc_close(sk); + if (sk->num == IPPROTO_RAW) + ip6_ra_control(sk, -1, NULL); sk->dead = 1; destroy_sock(sk); } diff -u --recursive --new-file v2.1.111/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.1.111/linux/net/ipv6/route.c Thu May 14 19:47:45 1998 +++ linux/net/ipv6/route.c Sun Jul 26 23:35:58 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $ + * $Id: route.c,v 1.32 1998/07/25 23:28:52 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1722,7 +1722,6 @@ return err; } - struct rt6_rtnl_dump_arg { struct sk_buff *skb; @@ -1733,6 +1732,9 @@ }; static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, + struct in6_addr *dst, + struct in6_addr *src, + int iif, int type, pid_t pid, u32 seq) { struct rtmsg *rtm; @@ -1777,10 +1779,23 @@ #ifdef CONFIG_RTNL_OLD_IFINFO o = skb->tail; #endif - if (rtm->rtm_dst_len) + if (dst) { + RTA_PUT(skb, RTA_DST, 16, dst); + rtm->rtm_dst_len = 128; + } else if (rtm->rtm_dst_len) RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); - if (rtm->rtm_src_len) + if (src) { + RTA_PUT(skb, RTA_SRC, 16, src); + rtm->rtm_src_len = 128; + } else if (rtm->rtm_src_len) RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); + if (iif) + RTA_PUT(skb, RTA_IIF, 4, &iif); + else if (dst) { + struct inet6_ifaddr *ifp = ipv6_get_saddr(&rt->u.dst, dst); + if (ifp) + RTA_PUT(skb, RTA_PREFSRC, 16, &ifp->addr); + } #ifdef CONFIG_RTNL_OLD_IFINFO if (rt->u.dst.pmtu) RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu); @@ -1842,7 +1857,7 @@ arg->count++; continue; } - if (rt6_fill_node(arg->skb, rt, RTM_NEWROUTE, + if (rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq) <= 0) { arg->stop = 1; break; @@ -1870,6 +1885,68 @@ return skb->len; } +int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) +{ + struct rtattr **rta = arg; + int iif = 0; + int err; + struct sk_buff *skb; + struct flowi fl; + struct rt6_info *rt; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (skb == NULL) + return -ENOBUFS; + + /* Reserve room for dummy headers, this skb can pass + through good chunk of routing engine. + */ + skb->mac.raw = skb->data; + skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); + + fl.proto = 0; + fl.nl_u.ip6_u.daddr = NULL; + fl.nl_u.ip6_u.saddr = NULL; + fl.uli_u.icmpt.type = 0; + fl.uli_u.icmpt.code = 0; + if (rta[RTA_SRC-1]) + fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]); + if (rta[RTA_DST-1]) + fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]); + + if (rta[RTA_IIF-1]) + memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); + + if (iif) { + struct device *dev; + dev = dev_get_by_index(iif); + if (!dev) + return -ENODEV; + } + + fl.oif = 0; + if (rta[RTA_OIF-1]) + memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); + + rt = (struct rt6_info*)ip6_route_output(NULL, &fl); + + skb->dst = &rt->u.dst; + + NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; + err = rt6_fill_node(skb, rt, + fl.nl_u.ip6_u.daddr, + fl.nl_u.ip6_u.saddr, + iif, + RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq); + if (err < 0) + return -EMSGSIZE; + + err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); + if (err < 0) + return err; + return 0; +} + void inet6_rt_notify(int event, struct rt6_info *rt) { struct sk_buff *skb; @@ -1880,7 +1957,7 @@ netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; } - if (rt6_fill_node(skb, rt, event, 0, 0) < 0) { + if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; diff -u --recursive --new-file v2.1.111/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.1.111/linux/net/ipv6/udp.c Tue Jun 23 10:01:31 1998 +++ linux/net/ipv6/udp.c Sun Jul 26 23:35:58 1998 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $ + * $Id: udp.c,v 1.31 1998/07/15 05:05:45 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -185,12 +185,18 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; + struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct in6_addr *daddr; struct dst_entry *dst; - struct ipv6_pinfo *np; struct inet6_ifaddr *ifa; struct flowi fl; int addr_type; + int err; + + if (usin->sin6_family == AF_INET) { + err = udp_connect(sk, uaddr, addr_len); + goto ipv4_connected; + } if (addr_len < sizeof(*usin)) return(-EINVAL); @@ -199,7 +205,6 @@ return(-EAFNOSUPPORT); addr_type = ipv6_addr_type(&usin->sin6_addr); - np = &sk->net_pinfo.af_inet6; if (addr_type == IPV6_ADDR_ANY) { /* @@ -212,18 +217,21 @@ if (addr_type == IPV6_ADDR_MAPPED) { struct sockaddr_in sin; - int err; sin.sin_family = AF_INET; sin.sin_addr.s_addr = daddr->s6_addr32[3]; + sin.sin_port = usin->sin6_port; err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin)); - + +ipv4_connected: if (err < 0) return err; - ipv6_addr_copy(&np->daddr, daddr); - + ipv6_addr_set(&np->daddr, 0, 0, + __constant_htonl(0x0000ffff), + sk->daddr); + if(ipv6_addr_any(&np->saddr)) { ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000ffff), @@ -236,7 +244,7 @@ __constant_htonl(0x0000ffff), sk->rcv_saddr); } - + return 0; } ipv6_addr_copy(&np->daddr, daddr); @@ -347,6 +355,8 @@ if (skb->protocol == __constant_htons(ETH_P_IP)) { ipv6_addr_set(&sin6->sin6_addr, 0, 0, __constant_htonl(0xffff), skb->nh.iph->saddr); + if (sk->ip_cmsg_flags) + ip_cmsg_recv(msg, skb); } else { memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, sizeof(struct in6_addr)); @@ -668,6 +678,9 @@ return(-EINVAL); if (sin6) { + if (sin6->sin6_family == AF_INET) + return udp_sendmsg(sk, msg, ulen); + if (addr_len < sizeof(*sin6)) return(-EINVAL); @@ -702,8 +715,10 @@ sin.sin_family = AF_INET; sin.sin_addr.s_addr = daddr->s6_addr32[3]; + sin.sin_port = udh.uh.dest; + msg->msg_name = (struct sockaddr *)(&sin); - return udp_sendmsg(sk, msg, len); + return udp_sendmsg(sk, msg, ulen); } udh.daddr = NULL; diff -u --recursive --new-file v2.1.111/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.1.111/linux/net/netlink/af_netlink.c Thu May 14 19:47:45 1998 +++ linux/net/netlink/af_netlink.c Sun Jul 26 23:35:58 1998 @@ -986,15 +986,15 @@ netlink_release, netlink_bind, netlink_connect, - NULL, - NULL, + sock_no_socketpair, + sock_no_accept, netlink_getname, datagram_poll, sock_no_ioctl, sock_no_listen, sock_no_shutdown, - NULL, - NULL, + sock_no_setsockopt, + sock_no_getsockopt, sock_no_fcntl, netlink_sendmsg, netlink_recvmsg diff -u --recursive --new-file v2.1.111/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.111/linux/net/netsyms.c Thu Jul 16 18:09:32 1998 +++ linux/net/netsyms.c Sun Jul 26 23:35:58 1998 @@ -60,8 +60,7 @@ defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ - defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ - defined(CONFIG_LNE390) + defined(CONFIG_ES3210) #include "../drivers/net/8390.h" #endif @@ -85,8 +84,8 @@ EXPORT_SYMBOL(dev_lockct); /* Skbuff symbols. */ -EXPORT_SYMBOL(skb_push_errstr); -EXPORT_SYMBOL(skb_put_errstr); +EXPORT_SYMBOL(skb_over_panic); +EXPORT_SYMBOL(skb_under_panic); /* Socket layer registration */ EXPORT_SYMBOL(sock_register); @@ -222,6 +221,7 @@ EXPORT_SYMBOL(ip_mc_dec_group); EXPORT_SYMBOL(__ip_finish_output); EXPORT_SYMBOL(inet_dgram_ops); +EXPORT_SYMBOL(ip_cmsg_recv); EXPORT_SYMBOL(__release_sock); /* needed for ip_gre -cw */ @@ -358,8 +358,7 @@ defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ - defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ - defined(CONFIG_LNE390) + defined(CONFIG_ES3210) /* If 8390 NIC support is built in, we will need these. */ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); diff -u --recursive --new-file v2.1.111/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.1.111/linux/net/packet/af_packet.c Fri May 8 23:14:57 1998 +++ linux/net/packet/af_packet.c Sun Jul 26 23:35:58 1998 @@ -1182,8 +1182,8 @@ packet_release, packet_bind_spkt, sock_no_connect, - NULL, - NULL, + sock_no_socketpair, + sock_no_accept, packet_getname_spkt, datagram_poll, packet_ioctl, diff -u --recursive --new-file v2.1.111/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.111/linux/net/x25/af_x25.c Thu May 7 22:51:56 1998 +++ linux/net/x25/af_x25.c Sun Jul 26 23:35:58 1998 @@ -174,7 +174,8 @@ struct sock *s; for (s = x25_list; s != NULL; s = s->next) - if (s->protinfo.x25->neighbour->dev == dev) + if (s->protinfo.x25->neighbour && + s->protinfo.x25->neighbour->dev == dev) x25_disconnect(s, ENETUNREACH, 0, 0); } @@ -621,6 +622,9 @@ if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL) return -ENETUNREACH; + x25_limit_facilities(&sk->protinfo.x25->facilities, + sk->protinfo.x25->neighbour); + if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0) return -ENETUNREACH; @@ -787,6 +791,13 @@ } /* + * current neighbour/link might impose additional limits + * on certain facilties + */ + + x25_limit_facilities(&facilities,neigh); + + /* * Try to create a new socket. */ if ((make = x25_make_new(sk)) == NULL) { @@ -1124,18 +1135,8 @@ return -EINVAL; if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096) return -EINVAL; - if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended) - { - if (facilities.winsize_in < 1 || facilities.winsize_in > 127) - return -EINVAL; - if (facilities.winsize_out < 1 || facilities.winsize_out > 127) - return -EINVAL; - } else { - if (facilities.winsize_in < 1 || facilities.winsize_in > 7) - return -EINVAL; - if (facilities.winsize_out < 1 || facilities.winsize_out > 7) - return -EINVAL; - } + if (facilities.winsize_in < 1 || facilities.winsize_in > 127) + return -EINVAL; if (facilities.throughput < 0x03 || facilities.throughput > 0x2C) return -EINVAL; if (facilities.reverse != 0 && facilities.reverse != 1) @@ -1275,6 +1276,16 @@ x25_device_event, 0 }; + +void x25_kill_by_neigh(struct x25_neigh *neigh) +{ + struct sock *s; + + for( s=x25_list; s != NULL; s=s->next){ + if( s->protinfo.x25->neighbour == neigh ) + x25_disconnect(s, ENETUNREACH, 0, 0); + } +} #ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_net_x25 = { diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c --- v2.1.111/linux/net/x25/x25_dev.c Thu Feb 12 20:56:15 1998 +++ linux/net/x25/x25_dev.c Sun Jul 26 23:35:58 1998 @@ -98,6 +98,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) { struct x25_neigh *neigh; + int queued; skb->sk = NULL; @@ -113,7 +114,13 @@ switch (skb->data[0]) { case 0x00: skb_pull(skb, 1); - return x25_receive_data(skb, neigh); + queued = x25_receive_data(skb, neigh); + if( ! queued ) + /* We need to free the skb ourselves because + * net_bh() won't care about our return code. + */ + kfree_skb(skb); + return 0; case 0x01: x25_link_established(neigh); @@ -215,6 +222,8 @@ { unsigned char *dptr; + skb->nh.raw = skb->data; + switch (neigh->dev->type) { case ARPHRD_X25: dptr = skb_push(skb, 1); @@ -238,3 +247,6 @@ } #endif + + + diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_facilities.c linux/net/x25/x25_facilities.c --- v2.1.111/linux/net/x25/x25_facilities.c Mon Jul 7 08:20:00 1997 +++ linux/net/x25/x25_facilities.c Sun Jul 26 23:35:58 1998 @@ -200,4 +200,26 @@ return len; } +/* + * Limit values of certain facilities according to the capability of the + * currently attached x25 link. + */ +void x25_limit_facilities(struct x25_facilities *facilities, + struct x25_neigh *neighbour) +{ + + if( ! neighbour->extended ){ + if( facilities->winsize_in > 7 ){ + printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); + facilities->winsize_in = 7; + } + if( facilities->winsize_out > 7 ){ + facilities->winsize_out = 7; + printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); + } + } +} + #endif + + diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_in.c linux/net/x25/x25_in.c --- v2.1.111/linux/net/x25/x25_in.c Tue Apr 14 14:29:27 1998 +++ linux/net/x25/x25_in.c Sun Jul 26 23:35:58 1998 @@ -49,17 +49,20 @@ if (more) { sk->protinfo.x25->fraglen += skb->len; skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb); + skb_set_owner_r(skb, sk); return 0; } if (!more && sk->protinfo.x25->fraglen > 0) { /* End of fragment */ - sk->protinfo.x25->fraglen += skb->len; - skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb); + int len = sk->protinfo.x25->fraglen + skb->len; - if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL) + if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){ + kfree_skb(skb); return 1; + } + + skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb); - skb_set_owner_r(skbn, sk); skbn->h.raw = skbn->data; skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue); @@ -75,7 +78,12 @@ sk->protinfo.x25->fraglen = 0; } - return sock_queue_rcv_skb(sk, skbn); + skb_set_owner_r(skbn, sk); + skb_queue_tail(&sk->receive_queue, skbn); + if (!sk->dead) + sk->data_ready(sk,skbn->len); + + return 0; } /* diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_link.c linux/net/x25/x25_link.c --- v2.1.111/linux/net/x25/x25_link.c Thu Feb 12 20:56:15 1998 +++ linux/net/x25/x25_link.c Sun Jul 26 23:35:58 1998 @@ -264,11 +264,14 @@ /* * Called when the link layer has terminated, or an establishment - * request has failed. XXX should tell sockets. + * request has failed. */ + void x25_link_terminated(struct x25_neigh *neigh) { neigh->state = X25_LINK_STATE_0; + /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */ + x25_kill_by_neigh(neigh); } /*