From e19d773493f497ac3575a053ba29186f75f04451 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:16:05 -0500 Subject: [PATCH] Import 2.1.112pre2 --- Documentation/Configure.help | 179 -- MAINTAINERS | 13 + Makefile | 3 +- arch/i386/kernel/io_apic.c | 23 +- arch/i386/mm/ioremap.c | 23 +- drivers/char/console.c | 132 +- drivers/char/consolemap.c | 481 ++++-- drivers/char/fbmem.c | 5 +- drivers/char/selection.c | 2 +- drivers/char/vc_screen.c | 51 +- drivers/char/vt.c | 37 +- drivers/misc/parport_procfs.c | 4 +- drivers/net/3c509.c | 3 + drivers/net/Config.in | 10 +- drivers/net/Makefile | 12 + drivers/net/Space.c | 4 + drivers/net/bmac.c | 1450 +++++++++++++++++ drivers/net/bmac.h | 164 ++ drivers/net/daynaport.c | 603 +++++++ drivers/net/eepro.c | 3 + drivers/net/ibmtr.c | 12 +- drivers/net/ibmtr.h | 2 + drivers/net/lance.c | 3 +- drivers/net/mace.c | 10 +- drivers/net/myri_sbus.c | 18 +- drivers/net/plip.c | 2 + drivers/net/seeq8005.c | 3 + drivers/net/sk_g16.c | 3 + drivers/net/sonic.c | 2 + drivers/net/sunhme.c | 56 +- drivers/net/sunlance.c | 38 +- drivers/net/sunqe.c | 28 +- drivers/net/wavelan.c | 140 +- drivers/net/wavelan.h | 136 +- drivers/net/wavelan.p.h | 521 +++--- drivers/scsi/eata.c | 83 +- drivers/scsi/eata.h | 7 +- drivers/scsi/u14-34f.c | 37 +- drivers/scsi/u14-34f.h | 3 +- drivers/video/Config.in | 63 +- drivers/video/Makefile | 71 +- drivers/video/atafb.c | 1 + drivers/video/atyfb.c | 2789 ++++++++++++++++++-------------- drivers/video/bwtwofb.c | 222 +++ drivers/video/cgsixfb.c | 86 +- drivers/video/cgthreefb.c | 247 +++ drivers/video/clgenfb.c | 2122 ++++++++++++++++++++++++ drivers/video/clgenfb.h | 175 ++ drivers/video/controlfb.c | 997 ++++++++++++ drivers/video/controlfb.h | 262 +++ drivers/video/creatorfb.c | 74 +- drivers/video/cyberfb.c | 1 + drivers/video/dnfb.c | 1 + drivers/video/dummycon.c | 7 +- drivers/video/fbcon-afb.c | 14 +- drivers/video/fbcon-afb.h | 2 - drivers/video/fbcon-cfb16.c | 227 ++- drivers/video/fbcon-cfb16.h | 3 +- drivers/video/fbcon-cfb2.c | 7 +- drivers/video/fbcon-cfb2.h | 2 - drivers/video/fbcon-cfb24.c | 239 ++- drivers/video/fbcon-cfb24.h | 3 +- drivers/video/fbcon-cfb32.c | 201 ++- drivers/video/fbcon-cfb32.h | 3 +- drivers/video/fbcon-cfb4.c | 7 +- drivers/video/fbcon-cfb4.h | 2 - drivers/video/fbcon-cfb8.c | 26 +- drivers/video/fbcon-cfb8.h | 2 - drivers/video/fbcon-ilbm.c | 14 +- drivers/video/fbcon-ilbm.h | 2 - drivers/video/fbcon-iplan2p2.c | 7 +- drivers/video/fbcon-iplan2p2.h | 2 - drivers/video/fbcon-iplan2p4.c | 7 +- drivers/video/fbcon-iplan2p4.h | 2 - drivers/video/fbcon-iplan2p8.c | 7 +- drivers/video/fbcon-iplan2p8.h | 2 - drivers/video/fbcon-mac.c | 2 +- drivers/video/fbcon-mac.h | 2 - drivers/video/fbcon-mfb.c | 7 +- drivers/video/fbcon-mfb.h | 2 - drivers/video/fbcon-vga.h | 2 - drivers/video/fbcon.c | 201 ++- drivers/video/fbcon.h | 17 +- drivers/video/fbgen.c | 58 +- drivers/video/font_acorn_8x8.c | 1 - drivers/video/fonts.c | 4 +- drivers/video/macfb.c | 3 +- drivers/video/macmodes.c | 1 + drivers/video/macmodes.h | 8 + drivers/video/offb.c | 20 + drivers/video/platinumfb.c | 1052 ++++++++++++ drivers/video/platinumfb.h | 399 +++++ drivers/video/prom.uni | 11 + drivers/video/promcon.c | 96 +- drivers/video/retz3fb.c | 1 + drivers/video/sbusfb.c | 14 +- drivers/video/sbusfb.h | 26 +- drivers/video/skeletonfb.c | 1 + drivers/video/tcxfb.c | 290 ++++ drivers/video/tgafb.c | 1 + drivers/video/vesafb.c | 1 + drivers/video/vfb.c | 1 + drivers/video/vgacon.c | 42 +- drivers/video/virgefb.c | 1 + fs/ufs/truncate.c | 3 +- include/linux/console_struct.h | 6 +- include/linux/consolemap.h | 7 +- include/linux/fb.h | 34 + include/linux/in6.h | 1 + include/linux/kd.h | 3 + include/linux/proc_fs.h | 1 + include/linux/selection.h | 3 + include/linux/simp.h | 39 - include/linux/skbuff.h | 16 +- include/linux/socket.h | 1 + include/linux/vt_kern.h | 13 +- include/net/ip6_route.h | 1 + include/net/ipv6.h | 27 +- include/net/sock.h | 3 + include/net/x25.h | 2 + mm/memory.c | 48 +- mm/mmap.c | 5 + mm/simp.c | 435 ----- net/Makefile | 11 +- net/ax25/af_ax25.c | 2 +- net/core/skbuff.c | 19 +- net/core/sock.c | 8 +- net/econet/econet.c | 4 +- net/ipv4/arp.c | 10 +- net/ipv4/fib_hash.c | 4 +- net/ipv4/icmp.c | 2 +- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_output.c | 4 +- net/ipv4/ip_sockglue.c | 8 +- net/ipv4/ipconfig.c | 4 +- net/ipv4/rarp.c | 6 +- net/ipv4/route.c | 16 +- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_input.c | 26 +- net/ipv4/tcp_ipv4.c | 11 +- net/ipv4/tcp_output.c | 20 +- net/ipv6/addrconf.c | 6 +- net/ipv6/ip6_input.c | 11 +- net/ipv6/ip6_output.c | 102 +- net/ipv6/ipv6_sockglue.c | 54 +- net/ipv6/raw.c | 4 +- net/ipv6/route.c | 89 +- net/ipv6/udp.c | 33 +- net/netlink/af_netlink.c | 8 +- net/netsyms.c | 11 +- net/packet/af_packet.c | 4 +- net/x25/af_x25.c | 37 +- net/x25/x25_dev.c | 14 +- net/x25/x25_facilities.c | 22 + net/x25/x25_in.c | 18 +- net/x25/x25_link.c | 5 +- 156 files changed, 12451 insertions(+), 3243 deletions(-) create mode 100644 drivers/net/bmac.c create mode 100644 drivers/net/bmac.h create mode 100644 drivers/net/daynaport.c create mode 100644 drivers/video/bwtwofb.c create mode 100644 drivers/video/cgthreefb.c create mode 100644 drivers/video/clgenfb.c create mode 100644 drivers/video/clgenfb.h create mode 100644 drivers/video/controlfb.c create mode 100644 drivers/video/controlfb.h create mode 100644 drivers/video/platinumfb.c create mode 100644 drivers/video/platinumfb.h create mode 100644 drivers/video/prom.uni create mode 100644 drivers/video/tcxfb.c delete mode 100644 include/linux/simp.h delete mode 100644 mm/simp.c diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 615a866e6a45..0435f52d2ae8 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -5983,18 +5983,6 @@ CONFIG_ISP16_CDI 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 @@ -6005,173 +5993,6 @@ CONFIG_QUOTA 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 Minix is a simple operating system used in many classes about diff --git a/MAINTAINERS b/MAINTAINERS index c29f8a85c84b..05e1137b0be4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -310,6 +310,12 @@ M: Paul.Russell@rustcorp.com.au 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 @@ S: Maintained 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 @@ -563,6 +570,12 @@ M: Jay.Schulist@spacs.k12.wi.us L: linux-net@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 + STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS P: Greg Ungerer M: support@stallion.oz.au diff --git a/Makefile b/Makefile index 31b3c0e6773a..101cd1d37794 100644 --- a/Makefile +++ b/Makefile @@ -340,7 +340,8 @@ clean: archclean 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 --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index b8a05d049a59..7e160f17e38f 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -966,21 +966,6 @@ static void disable_level_ioapic_irq(unsigned int irq) 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 @@ static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) if (!action) return; - enter_ioapic_irq(cpu); + irq_enter(cpu, irq); /* * Edge triggered interrupts need to remember @@ -1035,7 +1020,7 @@ static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) 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 @@ static void do_level_ioapic_IRQ (unsigned int irq, int cpu, if (!action) return; - enter_ioapic_irq(cpu); + irq_enter(cpu, irq); handle_IRQ_event(irq, regs); @@ -1084,7 +1069,7 @@ static void do_level_ioapic_IRQ (unsigned int irq, int cpu, unmask_IO_APIC_irq(irq); spin_unlock(&irq_controller_lock); - exit_ioapic_irq(cpu); + irq_exit(cpu, irq); } /* diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index b3fd2bdc574c..740f4551fbbb 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -90,13 +90,34 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag 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 --git a/drivers/char/console.c b/drivers/char/console.c index ee61b3a00527..e4b861d1db31 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -188,7 +188,7 @@ static inline unsigned short *screenpos(int currcons, int offset, int viewed) return p; } -static inline void scrolldelta(int lines) +static void scrolldelta(int lines) { int currcons = fg_console; @@ -314,6 +314,8 @@ static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _unde a ^= 0x80; if (_intensity == 2) a ^= 0x08; + if (hi_font_mask == 0x100) + a <<= 1; return a; } #else @@ -339,17 +341,23 @@ void invert_screen(int currcons, int offset, int count, int viewed) 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 @@ static void add_softcursor(int currcons) int i = scr_readw((u16 *) pos); u32 type = cursor_type; + if (! (type & 0x10)) return; if (softcursor_original != -1) return; softcursor_original = i; - 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 add_softcursor(int currcons) 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 @@ void set_cursor(int currcons) if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) return; if (deccm) { + if (currcons == sel_cons) + clear_selection(); add_softcursor(currcons); if ((cursor_type & 0x0f) != 1) sw->con_cursor(vc_cons[currcons].d,CM_DRAW); @@ -510,8 +522,6 @@ void update_screen(int new_console) } 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 @@ void visual_init(int currcons) 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 @@ int vc_allocate(unsigned int currcons, int init) /* return 0 on success */ 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 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) /* 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, 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 int do_con_write(struct tty_struct * tty, int from_user, 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 @@ void do_blank_screen(int nopowersave) /* 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 @@ void do_unblank_screen(void) 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 @@ void reset_palette (int currcons) * /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 @@ int con_font_op(int currcons, struct console_font_op *op) 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; } /* @@ -2666,6 +2692,22 @@ void putconsxy(int currcons, char *p) 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); + } +} + /* * Visible symbols for modules diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 5a9300bf8c10..e63386d7c061 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -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 @@ static unsigned short translations[][256] = { #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 @@ static void set_inverse_transl(int i) 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 @@ unsigned short *set_translate(int m) * 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 @@ int con_set_trans_old(unsigned char * arg) p[i] = UNI_DIRECT_BASE | uc; } - set_inverse_transl(USER_MAP); + update_user_maps(); return 0; } @@ -255,7 +284,7 @@ int con_get_trans_old(unsigned char * arg) 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; + } +} -static u16 **uni_pagedir[32] = +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; - - 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) */ - } - - p2[unicode & 0x3f] = fontpos; - - return 0; + int i, n; + u16 **p1, *p2; + + 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; + } + + 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; - - 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++; - } - - for ( i = 0 ; i <= 3 ; i++ ) - set_inverse_transl(i); /* Update all inverse translations */ + int err = 0, err1, i; + struct uni_pagedir *p, *q; + struct vc_data *conp = vc_cons[con].d; + + p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + 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(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 @@ con_set_unimap(ushort ct, struct unipair *list) 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 @@ conv_uni_to_pc(long ucs) __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 --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c index 7179022aae08..eaa2c504070d 100644 --- a/drivers/char/fbmem.c +++ b/drivers/char/fbmem.c @@ -420,6 +420,9 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) #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 @@ register_framebuffer(struct fb_info *fb_info) 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 --git a/drivers/char/selection.c b/drivers/char/selection.c index b253bbad8fd7..3910d0e30cd5 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -60,7 +60,7 @@ highlight_pointer(const int where) { 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 --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 7e61082a98a5..2c266dfe8bdf 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -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 @@ static long long vcs_lseek(struct file *file, long long offset, int orig) 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 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) 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 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) 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 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) 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 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 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 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 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 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 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 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 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 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 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 --git a/drivers/char/vt.c b/drivers/char/vt.c index 992fa55ad34f..8b8ba87ec095 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -113,21 +113,18 @@ kd_size_changed(int row, int col) } /* - * 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 @@ _kd_mksound(unsigned int hz, unsigned int ticks) 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 @@ do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) 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 @@ do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm) 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 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, #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 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, 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 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, 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 @@ void complete_change_console(unsigned int new_console) { 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 --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c index 7e097c8a41b6..151920e335d2 100644 --- a/drivers/misc/parport_procfs.c +++ b/drivers/misc/parport_procfs.c @@ -182,6 +182,8 @@ static int autoprobe_read_proc (char *page, char **start, off_t off, 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 @@ static int autoprobe_read_proc (char *page, char **start, off_t off, *start = 0; *eof = 1; - return strlen (page); + return len; } static inline void destroy_proc_entry(struct proc_dir_entry *root, diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 1bc7ed8afc11..bbeab290c9f9 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -451,6 +451,8 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev) 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 @@ el3_rx(struct device *dev) 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 --git a/drivers/net/Config.in b/drivers/net/Config.in index 829811dfb75f..0f3a9d44074b 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -31,8 +31,14 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then 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 --git a/drivers/net/Makefile b/drivers/net/Makefile index 74888461b8df..1b8bf79ba522 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -151,6 +151,14 @@ else 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 @@ -853,6 +861,10 @@ ifeq ($(CONFIG_MACE),y) L_OBJS += mace.o endif +ifeq ($(CONFIG_BMAC),y) +L_OBJS += bmac.o +endif + ifeq ($(CONFIG_VENDOR_SANGOMA),y) LX_OBJS += sdladrv.o L_OBJS += sdlamain.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index ee12ef9113cd..99084afc9e38 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -95,6 +95,7 @@ extern int bionet_probe(struct device *); 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 m68k_probes[] __initdata = { struct devprobe ppc_probes[] __initdata = { #ifdef CONFIG_MACE {mace_probe, 0}, +#endif +#ifdef CONFIG_BMAC + {bmac_probe, 0}, #endif {NULL, 0}, }; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c new file mode 100644 index 000000000000..237f0c956a94 --- /dev/null +++ b/drivers/net/bmac.c @@ -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 --git a/drivers/net/bmac.h b/drivers/net/bmac.h new file mode 100644 index 000000000000..df3b93d1ac24 --- /dev/null +++ b/drivers/net/bmac.h @@ -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 --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c new file mode 100644 index 000000000000..e15ade7608da --- /dev/null +++ b/drivers/net/daynaport.c @@ -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 --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 54a7ac5ef447..b26a1bfc0116 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1106,6 +1106,8 @@ hardware_send_packet(struct device *dev, void *buf, short length) 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 @@ eepro_rx(struct device *dev) 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 --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index 648ac8c7ab29..527cd044336e 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -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 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs) 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 --git a/drivers/net/ibmtr.h b/drivers/net/ibmtr.h index 6768a351fdf9..07990773151b 100644 --- a/drivers/net/ibmtr.h +++ b/drivers/net/ibmtr.h @@ -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 tok_info { struct timer_list tr_timer; unsigned char ring_speed; __u32 func_addr; + unsigned int retry_count; }; /* token ring adapter commands */ diff --git a/drivers/net/lance.c b/drivers/net/lance.c index bc5f6895bd75..5a7d1fee51b1 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -326,8 +326,7 @@ __initfunc(int lance_init(void)) 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 --git a/drivers/net/mace.c b/drivers/net/mace.c index ea836aaa0f43..1c7f3b9bca78 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -573,6 +573,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) 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 --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 52d3a5089b30..bdc46d635e36 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1044,27 +1044,11 @@ static inline int myri_ether_init(struct device *dev, struct linux_sbus_device * 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 --git a/drivers/net/plip.c b/drivers/net/plip.c index 4341a3449618..bcadd467fd5b 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -574,6 +574,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl, /* 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 @@ plip_send_packet(struct device *dev, struct net_local *nl, &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 --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 6dbaec6d2ee3..b571dc28c1f6 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -372,6 +372,7 @@ static int 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 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev) hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; + lp->stats.tx_bytes += length; } dev_kfree_skb (skb); @@ -547,6 +549,7 @@ seeq8005_rx(struct device *dev) 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 --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index d05f113f27ee..ac6736cabfb4 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -1250,6 +1250,8 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev) */ dev->tbusy = 0; } + + p->stats.tx_bytes += skb->len; } dev_kfree_skb(skb); return 0; @@ -1585,6 +1587,7 @@ static void SK_rxintr(struct device *dev) writeb(RX_OWN, rmdp->u.s.status); p->stats.rx_packets++; + p->stats.rx_bytes += len; p->rmdnum++; diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 8edb8706cb0c..243ba6872172 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -430,6 +430,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev) 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 @@ sonic_rx(struct device *dev) 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 --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index c9273d538ee1..53bafee5548f 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2098,6 +2098,7 @@ static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs } #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 @@ static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *re dev->interrupt = 0; HMD(("done\n")); } +#endif static int happy_meal_open(struct device *dev) { @@ -2148,6 +2150,7 @@ static int happy_meal_open(struct device *dev) 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 @@ static int happy_meal_open(struct device *dev) 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 @@ static inline int happy_meal_ether_init(struct device *dev, struct linux_sbus_de 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 --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index c51bc4b19f75..b0bfeb81399a 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -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 @@ static int lance_open (struct device *dev) 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 @@ no_link_test: 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 @@ __initfunc(int sparc_lance_probe (struct device *dev)) 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 --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 2dd681439950..83b95a72ad48 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1103,7 +1103,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s 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 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s * 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 @@ cleanup_module(void) 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 --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index 214fb7a993e3..0c46649d353e 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -264,7 +264,7 @@ psa_read(u_long ioaddr, 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 @@ mmc_read(u_long ioaddr, * 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 @@ mmc_encr(u_long ioaddr) /* i/o port of the card */ * 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 @@ fee_wait(u_long ioaddr, /* i/o port of the card */ * 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 @@ fee_read(u_long ioaddr, /* i/o port of the card */ * 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_write(u_long ioaddr, /* i/o port of the card */ 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 @@ fee_write(u_long ioaddr, /* i/o port of the card */ 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 @@ wv_complete(device * dev, /* 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 @@ if (lp->tx_n_in_use > 0) lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; } - /* Hack for reconfiguration... */ + /* Hack for reconfiguration */ if(tx_status == 0xFFFF) continue; @@ -921,7 +921,7 @@ wv_82586_reconfig(device * dev) 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 @@ wv_scb_show(u_long ioaddr) 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 @@ wv_ru_show(device * dev) 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 @@ wv_init_info(device * dev) #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 @@ wv_init_info(device * dev) { 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 @@ wavelan_set_mac_address(device * dev, 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ /* 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ 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 @@ wv_set_frequency(u_long ioaddr, /* i/o port of the card */ /*------------------------------------------------------------------*/ /* - * 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 @@ wl_his_gather(device * dev, /*------------------------------------------------------------------*/ /* - * 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ /* --------------- 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ { 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ { 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ 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 @@ wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ #ifdef HISTOGRAM case SIOCSIPHISTO: - /* Verif if the user is root */ + /* Verify that the user is root. */ if(!suser()) return -EPERM; @@ -2416,10 +2407,11 @@ wv_packet_read(device * dev, 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 @@ wv_receive(device * dev) * 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 @@ if (lp->tx_n_in_use > 0) /*------------------------------------------------------------------*/ /* * 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 @@ wv_mmc_init(device * dev) /* 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 @@ wv_mmc_init(device * dev) 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 @@ wv_mmc_init(device * dev) 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 --git a/drivers/net/wavelan.h b/drivers/net/wavelan.h index 2e92c798eaa8..ca67dbf6659a 100644 --- a/drivers/net/wavelan.h +++ b/drivers/net/wavelan.h @@ -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 @@ union hacs_u unsigned short hu_command; /* Command register */ #define HACR_RESET 0x0001 /* Reset board */ #define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ -#define HACR_16BITS 0x0004 /* 16 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 @@ struct ha_t /************************** 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 @@ struct psa_t 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 @@ struct psa_t #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 @@ typedef struct mmw_t mmw_t; struct mmw_t { unsigned char mmw_encr_key[8]; /* encryption key */ - unsigned char mmw_encr_enable; /* enable/disable encryption */ -#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ -#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_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 @@ struct mmw_t 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 @@ struct mmw_t /* 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 @@ struct mmr_t #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 @@ struct mmr_t 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 --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index 18320dcc4434..251f2b98e6fa 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -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... + * 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 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...). + * 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 know how to use this driver, read the NET3 HOWTO. - * If you want to exploit the many other fonctionalities, look comments - * in the code... + * 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 - * - * Changes made in second pre-release : - * ---------------------------------- - * - Cleanup init code (probe & module init) - * - Better multi device support (module) - * - name assignement (module) + * - many other minor details and cleanups * - * 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.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.17: + * ----------------------------------- + * - update to wireless extensions changes + * - silly bug in card initial configuration (psa_conf_status) + * + * Changes made for release in 2.1.27 & 2.0.30: + * -------------------------------------------- + * - small bug in debug code (probably not the last one...) + * - remove extern keyword for wavelan_probe() + * - level threshold is now a standard wireless extension (version 4 !) * - modules parameters types (new module interface) * - * Changes made for release in 2.1.36 : - * ---------------------------------- + * 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 @@ static const char *version = "wavelan.c : v16 (wireless extensions) 17/4/97\n"; #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 @@ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ /* * Static specific data for the interface. * - * For each network interface, Linux keep data in two structure. "device" - * keep the generic data (same format for everybody) and "net_local" keep - * the additional specific data. + * 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 @@ struct net_local 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 @@ static void 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 @@ static u_char irqvals[] = }; /* - * 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 @@ static unsigned short iobase[] = * 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 --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index a3d3ea51647f..8d7ba08311cb 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -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(link_statistics, "i"); 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 @@ struct proc_dir_entry proc_scsi_eata2x = { #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 do_trace = FALSE; 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 @@ __initfunc (static inline int port_detect \ 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 @@ __initfunc (void eata2x_setup(char *str, int *ints)) { 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 @@ __initfunc (static void add_pci_ports(void)) { 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 @@ __initfunc (static void add_pci_ports(void)) { 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; } @@ -1846,6 +1890,23 @@ int eata2x_reset(Scsi_Cmnd *SCarg) { #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) { unsigned int i, j, k, y; diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h index c45169f65af7..f1641f42d469 100644 --- a/drivers/scsi/eata.h +++ b/drivers/scsi/eata.h @@ -14,8 +14,9 @@ int eata2x_abort(Scsi_Cmnd *); 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 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int); 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 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int); 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 --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 0ebd93957610..cad88bc29a73 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -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(have_old_firmware, "i"); 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 @@ struct proc_dir_entry proc_scsi_u14_34f = { #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 void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); 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 @@ __initfunc (static inline int port_detect \ 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 @@ __initfunc (void u14_34f_setup(char *str, int *ints)) { 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 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { 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 --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h index f21aa63faf4d..943b8cbb3cc8 100644 --- a/drivers/scsi/u14-34f.h +++ b/drivers/scsi/u14-34f.h @@ -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_reset(Scsi_Cmnd *); 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 --git a/drivers/video/Config.in b/drivers/video/Config.in index 1a04a9c585b1..82d77bd121a8 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -23,6 +23,7 @@ if [ "$CONFIG_FB" = "y" ]; then 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_FB" = "y" ]; then 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 [ "$CONFIG_FB" = "y" ]; then 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" = "y" ]; then 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" = "y" ]; then 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 @@ if [ "$CONFIG_FB" = "y" ]; then 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 @@ if [ "$CONFIG_FB" = "y" ]; then 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 --git a/drivers/video/Makefile b/drivers/video/Makefile index 39138be35ac7..2461fddc47e5 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -30,13 +30,13 @@ ifeq ($(CONFIG_DUMMY_CONSOLE),y) 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 @@ ifeq ($(CONFIG_FB_ATY),y) 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 @@ else 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 @@ L_OBJS += sbusfb.o 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 @@ else 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 @@ include $(TOPDIR)/Rules.make 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 --git a/drivers/video/atafb.c b/drivers/video/atafb.c index a64eaf1fa19f..2b3de8ba50e7 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -47,6 +47,7 @@ #define ATAFB_EXT #define ATAFB_FALCON +#include #include #include #include diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 38570715e168..7d271bc290de 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -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 @@ struct aty_cmap_regs { 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 @@ struct pci_mmap_map { #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 @@ struct fb_info_aty { 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 @@ static int atyfb_mmap(struct fb_info *info, struct file *file, * 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,13 +304,73 @@ static int store_video_par(char *videopar, unsigned char m64_num); 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, atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl, @@ -493,64 +381,110 @@ static struct fb_ops atyfb_ops = { #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 @@ static inline void aty_st_8(volatile unsigned int regindex, u8 val, * (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 @@ static void reset_engine(struct fb_info_aty *info) 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 @@ static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) /* 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 @@ static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) /* 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 @@ static void aty_st_514(int offset, u8 val, struct fb_info_aty *info) 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 @@ static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info) 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) -static int read_aty_sense(struct fb_info_aty *info) + /* + * Apple monitor sense + */ + +static int read_aty_sense(const struct fb_info_aty *info) { int sense, i; @@ -800,50 +703,13 @@ static int read_aty_sense(struct fb_info_aty *info) 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 @@ aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel, 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 @@ aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel, 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 @@ aty_set_cursor_shape(struct fb_info_aty *fb) 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 @@ aty_set_cursor(struct fb_info_aty *fb) 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_set_cursor(struct fb_info_aty *fb) aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE, fb); } - wait_for_idle(fb); } static void @@ -986,6 +865,11 @@ atyfb_cursor(struct display *d, int mode, int x, int y) 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,249 +945,766 @@ atyfb_set_font(struct display *d, int width, int height) } -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); - } + /* + * CRTC programming + */ - 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); - } +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); +} - 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; +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"); + + if (vxres*vyres*bpp/8 > info->total_vram) + FAIL("not enough video RAM"); + + if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + FAIL("invalid vmode"); + + /* 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_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); + return 0; +} - aty_st_8(CLOCK_CNTL, 0, info); - aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info); - - aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); +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; - set_off_pitch(par, info); + 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 */ +} - 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; +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); + + 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: + FAIL("Invalid pixel width"); + } - 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 */ + /* 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; - 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; + return 0; +} + +/* ------------------------------------------------------------------------- */ + + /* + * PLL programming (Mach64 GX family) + * + * FIXME: use function pointer tables instead of switch statements + */ + +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; + } +} - case CLASS_GT: - aty_st_le32(BUS_CNTL, 0x7b23a040, info); +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) +{ + /* + * 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; + + 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; +} - /* 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); + /* FIXME: ATI18818?? */ - 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); +static int aty_pll_gx_to_var(const struct pll_gx *pll, + struct fb_var_screeninfo *var) +{ + u8 df, vco_div_count, ref_div_count; - /* 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); + df = pll->m >> 6; + vco_div_count = pll->m & 0x3f; + ref_div_count = pll->n; + + var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df); + + return 0; +} - /* if (info->total_vram > 0x400000) - i |= 0x538; this not been verified on > 4Megs!! */ - j = 0x86010102; + /* + * PLL programming (Mach64 CT family) + */ + +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; + } + } + /* 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; + + x = x; /* x is a workaround for sparc64-linux-gcc */ + + pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ + + 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 + 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 + vclk_post_div = 1; + vclk_fb_div = q*vclk_post_div/8; + + 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 ((((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 + pll_gen_cntl = 0x84; + + 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 */ - /* 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); + if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)) + pll_ext_cntl = 0; + else + pll_ext_cntl = mpostdiv; /* xclk == mclk */ - 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: - default: - i = CRTC_PIX_WIDTH_8BPP; break; + 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; +} + +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 (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]; + 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); } - /* Gentlemen, start your crtc engine */ - aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info); + aty_st_8(DAC_MASK, 0xff, info); /* Initialize the graphics engine */ - if (par->accel & FB_ACCELF_TEXT) + if (par->accel_flags & FB_ACCELF_TEXT) init_engine(par, info); #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; + 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; - 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; @@ -1311,6 +1712,79 @@ static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info) #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)) + return -EINVAL; +#endif + + return 0; +} + +static int atyfb_encode_var(struct fb_var_screeninfo *var, + const struct atyfb_par *par, + const struct fb_info_aty *info) +{ + int err; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + 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->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 @@ -1319,350 +1793,129 @@ static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info) static int atyfb_open(struct fb_info *info, int user) { - /* - * Nothing, only a usage count for the moment - */ - +#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++; + } +#endif MOD_INC_USE_COUNT; 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 int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, struct fb_info_aty *info) + const struct atyfb_par *par, + const struct fb_info_aty *info) { - struct aty_regvals *init; - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); 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 + * 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-PAGE_SIZE) - fix->smem_len = 0x800000-PAGE_SIZE; + 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 - */ - 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; - } - 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; - - return 0; -} - - -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; - - xres = vmode_attrs[par->hw.gx.vmode-1].hres; - yres = vmode_attrs[par->hw.gx.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; - - 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; - else - return -EINVAL; - - if (var->accel_flags & FB_ACCELF_TEXT) - par->accel = FB_ACCELF_TEXT; - else - par->accel = 0; - - if (aty_vram_reqd(par) > info->total_vram) - return -EINVAL; - - /* 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)) - return -EINVAL; - -#if 0 - if (!fbmon_valid_timings(pixclock, htotal, vtotal, info)) - return -EINVAL; -#endif + */ + 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; } -static int encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - 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; - - 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; - var->height = -1; - var->width = -1; - var->vmode = FB_VMODE_NONINTERLACED; - var->accel_flags = par->accel; - - 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; - } - var->pixclock = vclk; +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 +}; - return 0; -} +#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 +}; -static void init_par(struct atyfb_par *par, int vmode, int cmode) -{ - 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; -} +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 /* @@ -1670,16 +1923,16 @@ static void init_par(struct atyfb_par *par, int vmode, int cmode) */ 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_fix(struct fb_fix_screeninfo *fix, int con, */ 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_get_var(struct fb_var_screeninfo *var, int con, */ 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 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, 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 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, 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 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, 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 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, 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_set_var(struct fb_var_screeninfo *var, int con, */ 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 @@ static int atyfb_mmap(struct fb_info *info, struct file *file, 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 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) { 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 (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 (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); - } + 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; - 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; - } 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 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) 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 @@ __initfunc(void atyfb_init(void)) 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 @@ __initfunc(void atyfb_init(void)) /* 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 @@ __initfunc(void atyfb_init(void)) /* * 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 @@ __initfunc(void atyfb_init(void)) 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 @@ __initfunc(void atyfb_init(void)) #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 @@ __initfunc(void atyfb_init(void)) if (!aty_init(info, "PCI")) { if (info->mmap_map) kfree(info->mmap_map); - kfree(info); + kfree(info); } } } @@ -2500,39 +2800,51 @@ __initfunc(void atyfb_of_init(struct device_node *dp)) __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 @@ __initfunc(static char *strtoke(char *s, const char *ct)) } #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 @@ static int atyfbcon_updatevar(int con, struct fb_info *info) * 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 @@ static void atyfbcon_blank(int blank, struct fb_info *info) } 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 void atyfbcon_blank(int blank, struct fb_info *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) { - 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_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, */ 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 @@ static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, 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 @@ static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height, 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 inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height, 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_bmove(struct display *p, int sy, int sx, int dy, int dx, 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_aty_clear(struct vc_data *conp, struct display *p, int sy, 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 void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, 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 struct display_switch fbcon_aty8 = { 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 struct display_switch fbcon_aty16 = { 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 --git a/drivers/video/bwtwofb.c b/drivers/video/bwtwofb.c new file mode 100644 index 000000000000..a907fc2d178c --- /dev/null +++ b/drivers/video/bwtwofb.c @@ -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 --git a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c index f1e7ece86ddd..0ef9e4dcb16c 100644 --- a/drivers/video/cgsixfb.c +++ b/drivers/video/cgsixfb.c @@ -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 @@ static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx, } 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 @@ static void cg6_fill(struct fb_info_sbusfb *fb, int s, 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 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int 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 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int 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 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh fd1 += 2; } } +#endif } } @@ -466,7 +489,6 @@ static void cg6_loadcmap (struct fb_info_sbusfb *fb, int index, int count) 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 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) 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 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) 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 --git a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c new file mode 100644 index 000000000000..2cab0fc254f2 --- /dev/null +++ b/drivers/video/cgthreefb.c @@ -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 --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c new file mode 100644 index 000000000000..8bf6cf93fd1b --- /dev/null +++ b/drivers/video/clgenfb.c @@ -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 --git a/drivers/video/clgenfb.h b/drivers/video/clgenfb.h new file mode 100644 index 000000000000..3f66ec2946c3 --- /dev/null +++ b/drivers/video/clgenfb.h @@ -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 --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c new file mode 100644 index 000000000000..466bf52ee969 --- /dev/null +++ b/drivers/video/controlfb.c @@ -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 --git a/drivers/video/controlfb.h b/drivers/video/controlfb.h new file mode 100644 index 000000000000..2e138b7c70d3 --- /dev/null +++ b/drivers/video/controlfb.h @@ -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 --git a/drivers/video/creatorfb.c b/drivers/video/creatorfb.c index 63e65bc8b9f9..1dda1ef0e459 100644 --- a/drivers/video/creatorfb.c +++ b/drivers/video/creatorfb.c @@ -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 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int 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 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int 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 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh } xy += 2 * p->fontwidth; } +#endif } while (count) { count--; @@ -347,13 +366,16 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh fd1 += 2; } } +#endif xy += p->fontwidth; } } @@ -471,11 +494,8 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb)) 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 --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c index 510814478bea..34d023311cf4 100644 --- a/drivers/video/cyberfb.c +++ b/drivers/video/cyberfb.c @@ -21,6 +21,7 @@ */ +#include #include #include #include diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 9065546417a5..d8b993eedd86 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/video/dummycon.c b/drivers/video/dummycon.c index f97560214779..6a577d259500 100644 --- a/drivers/video/dummycon.c +++ b/drivers/video/dummycon.c @@ -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 --git a/drivers/video/fbcon-afb.c b/drivers/video/fbcon-afb.c index 146063b0560d..a8c01d6a0fd7 100644 --- a/drivers/video/fbcon-afb.c +++ b/drivers/video/fbcon-afb.c @@ -251,7 +251,7 @@ void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, 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 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, while (count--) if (xx&3 || count < 3) { /* Slow version */ - c1 = *s++; + c1 = *s++ & p->charmask; dest1 = dest0++; xx++; @@ -322,10 +322,10 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, 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 --git a/drivers/video/fbcon-afb.h b/drivers/video/fbcon-afb.h index c82d98c410ba..6eb0310e96d0 100644 --- a/drivers/video/fbcon-afb.h +++ b/drivers/video/fbcon-afb.h @@ -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 --git a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c index 49a54643a930..24da1127767b 100644 --- a/drivers/video/fbcon-cfb16.c +++ b/drivers/video/fbcon-cfb16.c @@ -47,23 +47,34 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx, 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 @@ void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy, 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;; } - dest0 += 16; +#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; + } + break; } +#endif } void fbcon_cfb16_revc(struct display *p, int xx, int yy) @@ -163,12 +241,60 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy) 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 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy) 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 --git a/drivers/video/fbcon-cfb16.h b/drivers/video/fbcon-cfb16.h index 7419f81b7e85..716f1f949e4c 100644 --- a/drivers/video/fbcon-cfb16.h +++ b/drivers/video/fbcon-cfb16.h @@ -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_putc(struct vc_data *conp, struct display *p, int c, 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 --git a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c index 707ccff846f0..60bed6275fb6 100644 --- a/drivers/video/fbcon-cfb2.c +++ b/drivers/video/fbcon-cfb2.c @@ -129,7 +129,7 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy, 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_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh 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 --git a/drivers/video/fbcon-cfb2.h b/drivers/video/fbcon-cfb2.h index 1cb29c5a98cb..c66745e1b3b4 100644 --- a/drivers/video/fbcon-cfb2.h +++ b/drivers/video/fbcon-cfb2.h @@ -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 --git a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c index bfad93291081..875ad850cfe2 100644 --- a/drivers/video/fbcon-cfb24.c +++ b/drivers/video/fbcon-cfb24.c @@ -37,29 +37,56 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx, 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 @@ void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy) 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 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy) 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 --git a/drivers/video/fbcon-cfb24.h b/drivers/video/fbcon-cfb24.h index 738c9e62fadd..c764ad029d08 100644 --- a/drivers/video/fbcon-cfb24.h +++ b/drivers/video/fbcon-cfb24.h @@ -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_putc(struct vc_data *conp, struct display *p, int c, 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 --git a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c index a0120c5a17d1..8a064e9cd3df 100644 --- a/drivers/video/fbcon-cfb32.c +++ b/drivers/video/fbcon-cfb32.c @@ -37,23 +37,34 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx, 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 @@ void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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_clear(struct vc_data *conp, struct display *p, int sy, int sx, 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 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy) 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 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy) 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 --git a/drivers/video/fbcon-cfb32.h b/drivers/video/fbcon-cfb32.h index ee22abb1464d..3d3eda626d6a 100644 --- a/drivers/video/fbcon-cfb32.h +++ b/drivers/video/fbcon-cfb32.h @@ -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_putc(struct vc_data *conp, struct display *p, int c, 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 --git a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c index 4b7b54f0da52..4d3f196bf359 100644 --- a/drivers/video/fbcon-cfb4.c +++ b/drivers/video/fbcon-cfb4.c @@ -131,7 +131,7 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy, 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_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, 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 --git a/drivers/video/fbcon-cfb4.h b/drivers/video/fbcon-cfb4.h index df08288cde24..cc565efb3065 100644 --- a/drivers/video/fbcon-cfb4.h +++ b/drivers/video/fbcon-cfb4.h @@ -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 --git a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c index cebf6bd23f3c..8ee2a83c82d2 100644 --- a/drivers/video/fbcon-cfb8.c +++ b/drivers/video/fbcon-cfb8.c @@ -110,9 +110,9 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, } 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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, 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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, } 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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, } 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 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, } break; } +#endif } void fbcon_cfb8_revc(struct display *p, int xx, int yy) @@ -212,6 +221,10 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy) 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 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy) case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f; /* FALL THROUGH */ default: break; } +#endif } } diff --git a/drivers/video/fbcon-cfb8.h b/drivers/video/fbcon-cfb8.h index e1d8170ed585..419de250d0df 100644 --- a/drivers/video/fbcon-cfb8.h +++ b/drivers/video/fbcon-cfb8.h @@ -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 --git a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c index 3bd98cde556c..b87a1d10caaa 100644 --- a/drivers/video/fbcon-ilbm.c +++ b/drivers/video/fbcon-ilbm.c @@ -103,7 +103,7 @@ void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, { 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 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, while (count--) if (xx&3 || count < 3) { /* Slow version */ - c1 = *s++; + c1 = *s++ & p->charmask; dest = dest0++; xx++; @@ -185,10 +185,10 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, } } } 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 --git a/drivers/video/fbcon-ilbm.h b/drivers/video/fbcon-ilbm.h index 13292f28799f..bd066f49b7a7 100644 --- a/drivers/video/fbcon-ilbm.h +++ b/drivers/video/fbcon-ilbm.h @@ -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 --git a/drivers/video/fbcon-iplan2p2.c b/drivers/video/fbcon-iplan2p2.c index 3e1e67607d17..3cd8ab81ea21 100644 --- a/drivers/video/fbcon-iplan2p2.c +++ b/drivers/video/fbcon-iplan2p2.c @@ -307,7 +307,7 @@ void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c, 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 @@ void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p, 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 @@ void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p, 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 --git a/drivers/video/fbcon-iplan2p2.h b/drivers/video/fbcon-iplan2p2.h index 07b5a0d31e5f..4e8502c05e9d 100644 --- a/drivers/video/fbcon-iplan2p2.h +++ b/drivers/video/fbcon-iplan2p2.h @@ -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 --git a/drivers/video/fbcon-iplan2p4.c b/drivers/video/fbcon-iplan2p4.c index 844398127b15..4bd21c366545 100644 --- a/drivers/video/fbcon-iplan2p4.c +++ b/drivers/video/fbcon-iplan2p4.c @@ -317,7 +317,7 @@ void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c, 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 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p, 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 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p, * cache :-( */ - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight); for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff --git a/drivers/video/fbcon-iplan2p4.h b/drivers/video/fbcon-iplan2p4.h index 6d501a58e737..7dd3eded2630 100644 --- a/drivers/video/fbcon-iplan2p4.h +++ b/drivers/video/fbcon-iplan2p4.h @@ -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 --git a/drivers/video/fbcon-iplan2p8.c b/drivers/video/fbcon-iplan2p8.c index 2db180dd7c4d..aa2f4d2f131b 100644 --- a/drivers/video/fbcon-iplan2p8.c +++ b/drivers/video/fbcon-iplan2p8.c @@ -349,7 +349,7 @@ void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c, 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 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p, 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 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p, * cache :-( */ - c = *s++; + c = *s++ & p->charmask; cdat = p->fontdata + (c * p->fontheight); for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { diff --git a/drivers/video/fbcon-iplan2p8.h b/drivers/video/fbcon-iplan2p8.h index ba298f84c4d7..9e0f11f8df10 100644 --- a/drivers/video/fbcon-iplan2p8.h +++ b/drivers/video/fbcon-iplan2p8.h @@ -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 --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c index a1ba4ce9e5fc..a4bac8fae806 100644 --- a/drivers/video/fbcon-mac.c +++ b/drivers/video/fbcon-mac.c @@ -272,7 +272,7 @@ void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 --git a/drivers/video/fbcon-mac.h b/drivers/video/fbcon-mac.h index 62d2ae6d3505..b19464d53b50 100644 --- a/drivers/video/fbcon-mac.h +++ b/drivers/video/fbcon-mac.h @@ -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 --git a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c index dafa4ad5b53e..b8f575859997 100644 --- a/drivers/video/fbcon-mfb.c +++ b/drivers/video/fbcon-mfb.c @@ -90,7 +90,7 @@ void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy, 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 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, { 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 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, 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 --git a/drivers/video/fbcon-mfb.h b/drivers/video/fbcon-mfb.h index 77f312e31dbf..a300d8cc6796 100644 --- a/drivers/video/fbcon-mfb.h +++ b/drivers/video/fbcon-mfb.h @@ -2,8 +2,6 @@ * Monochrome (mfb) */ -#include - #ifdef MODULE #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE) #define FBCON_HAS_MFB diff --git a/drivers/video/fbcon-vga.h b/drivers/video/fbcon-vga.h index 7d62e213c4da..259780247b51 100644 --- a/drivers/video/fbcon-vga.h +++ b/drivers/video/fbcon-vga.h @@ -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 --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c index 1962f1b0aad2..cdec5a29d932 100644 --- a/drivers/video/fbcon.c +++ b/drivers/video/fbcon.c @@ -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 @@ static void fbcon_setup(int con, int init, int logo) 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 @@ static void fbcon_setup(int con, int init, int logo) } 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 @@ static void fbcon_setup(int con, int init, int logo) 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 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, { int unit = conp->vc_num; struct display *p = &fb_display[unit]; - + if (!p->can_soft_blank && console_blanked) return; @@ -1033,9 +1040,9 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, 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 @@ static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, 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 @@ static int fbcon_switch(struct vc_data *conp) 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 int fbcon_blank(struct vc_data *conp, int blank) 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 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int int resize; int w = op->width; int h = op->height; + int cnt; char *old_data = NULL; if (!fontwidthvalid(p,w)) { @@ -1188,11 +1241,28 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int 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 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int 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 @@ static inline int fbcon_copy_font(int unit, struct console_font_op *op) 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 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op) { 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 @@ static inline int fbcon_set_def_font(int unit, struct console_font_op *op) } op->width = f->width; op->height = f->height; - op->charcount = 256; return fbcon_do_set_font(unit, op, f->data, 0); } @@ -1372,7 +1516,6 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines) return 0; } - __initfunc(static int fbcon_show_logo( void )) { struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ diff --git a/drivers/video/fbcon.h b/drivers/video/fbcon.h index 39a8b22434c2..98091ba0c592 100644 --- a/drivers/video/fbcon.h +++ b/drivers/video/fbcon.h @@ -11,6 +11,7 @@ #ifndef __VIDEO_FBCON_H #define __VIDEO_FBCON_H +#include #include @@ -35,11 +36,21 @@ struct display_switch { 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 @@ struct display_switch { /* 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 --git a/drivers/video/fbgen.c b/drivers/video/fbgen.c index 730438d166a2..3ff6479803c7 100644 --- a/drivers/video/fbgen.c +++ b/drivers/video/fbgen.c @@ -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 @@ int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, 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 @@ void fbgen_install_cmap(int con, struct fb_info_gen *info) 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 --git a/drivers/video/font_acorn_8x8.c b/drivers/video/font_acorn_8x8.c index ace9a2c4b704..007afe4af9c0 100644 --- a/drivers/video/font_acorn_8x8.c +++ b/drivers/video/font_acorn_8x8.c @@ -1,6 +1,5 @@ /* Acorn-like font definition, with PC graphics characters */ -#include #include "font.h" static unsigned char acorndata_8x8[] = { diff --git a/drivers/video/fonts.c b/drivers/video/fonts.c index aa09773bc95b..72f29410a46b 100644 --- a/drivers/video/fonts.c +++ b/drivers/video/fonts.c @@ -30,7 +30,7 @@ static struct fbcon_font_desc *fbcon_fonts[] = { &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 @@ static struct fbcon_font_desc *fbcon_fonts[] = { &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 --git a/drivers/video/macfb.c b/drivers/video/macfb.c index f1a8150b1980..694f2df4d8b2 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -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 @@ static struct fb_var_screeninfo macfb_defined={ {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 --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index da41fabdf401..2498162e7728 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c @@ -9,6 +9,7 @@ */ +#include #include #include #include diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h index 29fb2593a9bb..e0e90c738422 100644 --- a/drivers/video/macmodes.h +++ b/drivers/video/macmodes.h @@ -50,3 +50,11 @@ extern int mac_vmode_to_var(int vmode, int cmode, 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 --git a/drivers/video/offb.c b/drivers/video/offb.c index 01edad5cc791..0e6e57f5665e 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -282,6 +282,13 @@ extern void s3triofb_init_of(struct device_node *dp); #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 @@ __initfunc(void offb_init(void)) 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 --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c new file mode 100644 index 000000000000..f2a3e9410499 --- /dev/null +++ b/drivers/video/platinumfb.c @@ -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 --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h new file mode 100644 index 000000000000..a9b4b1c8f592 --- /dev/null +++ b/drivers/video/platinumfb.h @@ -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 --git a/drivers/video/prom.uni b/drivers/video/prom.uni new file mode 100644 index 000000000000..58f9c04ed9d3 --- /dev/null +++ b/drivers/video/prom.uni @@ -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 --git a/drivers/video/promcon.c b/drivers/video/promcon.c index d714b7f4b19c..e728b16abb63 100644 --- a/drivers/video/promcon.c +++ b/drivers/video/promcon.c @@ -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 @@ __initfunc(const char *promcon_startup(void)) 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 @@ promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) 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 @@ static int promcon_dummy(void) 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 @@ struct consw prom_con = { 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 --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c index 9673cb9ae105..94b5797bbcda 100644 --- a/drivers/video/retz3fb.c +++ b/drivers/video/retz3fb.c @@ -21,6 +21,7 @@ */ +#include #include #include #include diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c index 009e1f5a4e80..a771c37bd1fb 100644 --- a/drivers/video/sbusfb.c +++ b/drivers/video/sbusfb.c @@ -277,7 +277,7 @@ static void sbusfb_clear_margin(struct display *p, int s) 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 @@ static void sbusfb_clear_margin(struct display *p, int s) 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 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype, 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 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype, 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 @@ __initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype, kfree(fb); return; } + + if (p == SBUSFBINIT_SIZECHANGE) + goto sizechange; disp->dispsw = &fb->dispsw; if (fb->setcursor) diff --git a/drivers/video/sbusfb.h b/drivers/video/sbusfb.h index b17a1cf9cfe1..f65ca1d716b7 100644 --- a/drivers/video/sbusfb.h +++ b/drivers/video/sbusfb.h @@ -24,6 +24,18 @@ struct fb_info_cgsix { 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 @@ struct fb_info_sbusfb { 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 @@ struct fb_info_sbusfb { 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 *leofb_init(struct fb_info_sbusfb *); 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 --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 1831e6b33de2..e0aebeb42658 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include diff --git a/drivers/video/tcxfb.c b/drivers/video/tcxfb.c new file mode 100644 index 000000000000..181b6c53edd7 --- /dev/null +++ b/drivers/video/tcxfb.c @@ -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 --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index ef3f9b135966..f2a357e7e223 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -22,6 +22,7 @@ * KNOWN PROBLEMS/TO DO ==================================================== */ +#include #include #include #include diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index cf1534a9ae04..97d65ef8c261 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index f2bc39cd091c..bb1102d93685 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -8,6 +8,7 @@ * more details. */ +#include #include #include #include diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c index 5ed8b668abd4..5a4b21859551 100644 --- a/drivers/video/vgacon.c +++ b/drivers/video/vgacon.c @@ -33,7 +33,7 @@ * more details. */ -#include + #include #include #include @@ -94,6 +94,7 @@ static void vgacon_save_screen(struct vc_data *c); 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 @@ __initfunc(static const char *vgacon_startup(void)) 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 inline void vga_set_mem_top(struct vc_data *c) 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 u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, 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 @@ static int vgacon_font_op(struct vc_data *c, struct console_font_op *op) 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 --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c index 927fbb46d3be..09884fb515f8 100644 --- a/drivers/video/virgefb.c +++ b/drivers/video/virgefb.c @@ -16,6 +16,7 @@ #undef VIRGEFBDEBUG +#include #include #include #include diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 7b1676836c4a..c6dca7358c25 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -267,7 +267,7 @@ next: for (i = 0; i < uspi->s_apb; i++) if (SWAB32(*ubh_get_addr32(ind_ubh,i))) break; - if (i >= uspi->s_apb) + if (i >= uspi->s_apb) { if (ubh_max_bcount(ind_ubh) != 1) { retry = 1; } @@ -280,6 +280,7 @@ next: 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); diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index f669b764286e..b1807bf3a9bf 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -15,6 +15,8 @@ */ #define CUR_DEFAULT CUR_UNDERLINE +#include + #define NPAR 16 struct vc_data { @@ -33,7 +35,7 @@ struct vc_data { 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 @@ struct vc_data { 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 --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 9aba19db33b9..fd0bcd43fdba 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -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 --git a/include/linux/fb.h b/include/linux/fb.h index 2c7fc1de1c51..7c631b44ae6a 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -272,6 +272,8 @@ struct display { 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 */ }; @@ -334,6 +336,38 @@ struct fb_info_gen { /* 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 { const char *name; diff --git a/include/linux/in6.h b/include/linux/in6.h index 0ebec6ba37d9..37f0e066d6f6 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -126,5 +126,6 @@ struct ipv6_mreq { #define IPV6_MULTICAST_LOOP 19 #define IPV6_ADD_MEMBERSHIP 20 #define IPV6_DROP_MEMBERSHIP 21 +#define IPV6_ROUTER_ALERT 22 #endif diff --git a/include/linux/kd.h b/include/linux/kd.h index c4a3febfedaf..5a4c620dc0e3 100644 --- a/include/linux/kd.h +++ b/include/linux/kd.h @@ -149,6 +149,9 @@ struct console_font_op { #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 --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index e1e108a65503..6f1901b42455 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -109,6 +109,7 @@ enum net_directory_inos { 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 --git a/include/linux/selection.h b/include/linux/selection.h index 640fd41678ff..45a14a4b3db0 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -40,4 +40,7 @@ extern void invert_screen(int currcons, int offset, int count, int shift); 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 --git a/include/linux/simp.h b/include/linux/simp.h deleted file mode 100644 index bf838f8153d9..000000000000 --- a/include/linux/simp.h +++ /dev/null @@ -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 --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 561d74d8097c..ee6c79970cad 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -151,6 +151,8 @@ extern int skb_headroom(struct sk_buff *skb); 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 @@ extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list) return result; } - -extern const char skb_put_errstr[]; -extern const char skb_push_errstr[]; - /* * Add data to an sk_buff */ @@ -452,9 +450,9 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) 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 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len) if(skb->datahead) { __label__ here; - panic(skb_push_errstr, &&here,len); -here: ; + skb_under_panic(skb, len, &&here); +here: ; } return skb->data; } diff --git a/include/linux/socket.h b/include/linux/socket.h index 87b175b994d4..a6e306381517 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -183,6 +183,7 @@ struct ucred { #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 --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index bdc9f8763a5e..e4f48e908d30 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -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_set_trans_old(unsigned char * table); 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 --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 8fb0fbed7616..8ca62a7edcc7 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -100,6 +100,7 @@ struct netlink_callback; 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 --git a/include/net/ipv6.h b/include/net/ipv6.h index 47705c923cd5..acf37b3579ca 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -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 @@ -118,6 +118,31 @@ struct frag_queue { __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, __u8 *nhptr, diff --git a/include/net/sock.h b/include/net/sock.h index 4b6d2d5ee895..ed05e12bea37 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -468,6 +468,9 @@ struct sock { #endif #ifdef CONFIG_NETLINK struct netlink_opt af_netlink; +#endif +#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) + struct econet_opt *af_econet; #endif } protinfo; diff --git a/include/net/x25.h b/include/net/x25.h index a72bd04265dd..5ac507bd52f5 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -147,6 +147,7 @@ extern unsigned int x25_new_lci(struct x25_neigh *); 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 void x25_terminate_link(struct x25_neigh *); 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 --git a/mm/memory.c b/mm/memory.c index fc0de9b60064..c7c0e91af53c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -127,16 +127,23 @@ static inline void free_one_pgd(pgd_t * dir) */ 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 clear_page_tables(struct task_struct * tsk) */ 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 --git a/mm/mmap.c b/mm/mmap.c index 3ea31f2037b3..172bcd8f11e6 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -196,9 +196,14 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, 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 --git a/mm/simp.c b/mm/simp.c deleted file mode 100644 index 581cde3d70c3..000000000000 --- a/mm/simp.c +++ /dev/null @@ -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 --git a/net/Makefile b/net/Makefile index 0f32c8397a30..0bbf171fa661 100644 --- a/net/Makefile +++ b/net/Makefile @@ -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 @@ -140,6 +141,14 @@ else endif endif +ifeq ($(CONFIG_ECONET),y) +SUB_DIRS += econet +else + ifeq ($(CONFIG_ECONET),m) + MOD_SUB_DIRS += econet + endif +endif + # We must attach netsyms.o to socket.o, as otherwise there is nothing # to pull the object file from the archive. diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 44ad2189d39a..3edee0168d65 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -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 --git a/net/core/skbuff.c b/net/core/skbuff.c index c49fbeb20068..a366acfbad30 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -77,11 +77,22 @@ extern atomic_t ip_frag_mem; 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 --git a/net/core/sock.c b/net/core/sock.c index e1d1379aa30b..54d1c0a54628 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -212,7 +213,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, 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 @@ int sock_setsockopt(struct socket *sock, int level, int optname, 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 @@ void sk_free(struct sock *sk) 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 --git a/net/econet/econet.c b/net/econet/econet.c index 5d83716a82a1..5b5a543357f0 100644 --- a/net/econet/econet.c +++ b/net/econet/econet.c @@ -738,8 +738,8 @@ static struct proto_ops econet_ops = { econet_release, econet_bind, sock_no_connect, - NULL, - NULL, + sock_no_socketpair, + sock_no_accept, econet_getname, datagram_poll, econet_ioctl, diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 4fcdc2622ef7..39ed076ed511 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -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 @@ static int arp_constructor(struct neighbour *neigh) 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 @@ static int arp_constructor(struct neighbour *neigh) 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 @@ __initfunc(void arp_init (void)) #ifdef CONFIG_AX25_MODULE /* - * ax25 -> ascii conversion + * ax25 -> ASCII conversion */ char *ax2asc(ax25_address *a) { diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 4b89ab6767bc..3e13671a287f 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -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 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result #endif ) { if (matched) - return 1; + break; continue; } matched = 1; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 2ec5fcc3de6e..4e947337ad47 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -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 --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index dad449980c3b..838498c21b4d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -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 --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 41c66f2c3f6f..0527c1b0bc87 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -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 @@ void ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) * 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 --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 318e3624ff59..8f712c801c7a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -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_pktinfo(struct msghdr *msg, struct sk_buff *skb) 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 --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 155b4162d40c..76372b4ab4e4 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -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 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)) 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 --git a/net/ipv4/rarp.c b/net/ipv4/rarp.c index 9fd174b68a29..7f7c7e3f2674 100644 --- a/net/ipv4/rarp.c +++ b/net/ipv4/rarp.c @@ -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 --git a/net/ipv4/route.c b/net/ipv4/route.c index 902c3983b8f8..e10f65c68f72 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -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 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, } /* 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 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int 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 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int 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 @@ static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int 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 --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d161344da7a6..3d6f188e7eff 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -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 --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6b62622e6f41..a4ad2dc3cae6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -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 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) } } -/* 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 @@ static __inline__ void tcp_bound_rto(struct tcp_opt *tp) } /* 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 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, 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 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, 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 --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 26a623a1fb21..ad08655b6c15 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -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 @@ tcp_v4_save_options(struct sock *sk, struct sk_buff *skb, 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 --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 4a925bd0f8e3..84535341fb03 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -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 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue) } } -/* 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 @@ void tcp_write_xmit(struct sock *sk) * * 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 @@ void tcp_write_xmit(struct sock *sk) * 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 @@ static __inline__ void update_retrans_head(struct sock *sk) /* 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 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) 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 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss) 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 --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4dd0155fb979..329807093335 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -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 @@ static void addrconf_dev_config(struct device *dev) 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 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { inet6_rtm_newroute, NULL, }, { inet6_rtm_delroute, NULL, }, - { NULL, inet6_dump_fib, }, + { inet6_rtm_getroute, inet6_dump_fib, }, { NULL, NULL, }, }; #endif diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 5f024dddbd70..6ab4d2c08395 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -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 @@ struct hdrtype_proc { /* 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 @@ struct tlvtype_proc { {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 @@ static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) * 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 --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index eb3984f5574b..aa13c20747da 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -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 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, 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 @@ int ip6_forward(struct sk_buff *skb) dst->output(skb); return 0; + +drop: + kfree_skb(skb); + return -EINVAL; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f409cbb15682..b31c07c00bce 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -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 @@ static struct notifier_block ipv6_dev_notf = { 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 ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 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 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 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 @@ out: 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 --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7429a9210e67..659ec59ccf1b 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -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 @@ static void rawv6_close(struct sock *sk, unsigned long timeout) { 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 --git a/net/ipv6/route.c b/net/ipv6/route.c index c3eac9395691..9d159fe36ece 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -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 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) return err; } - struct rt6_rtnl_dump_arg { struct sk_buff *skb; @@ -1733,6 +1732,9 @@ struct rt6_rtnl_dump_arg }; 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 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, #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 @@ static void rt6_dump_node(struct fib6_node *fn, void *p_arg) 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 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) 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 @@ void inet6_rt_notify(int event, struct rt6_info *rt) 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 --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 90a59266c61d..2dac0570f654 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, 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 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 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 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 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 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) __constant_htonl(0x0000ffff), sk->rcv_saddr); } - + return 0; } ipv6_addr_copy(&np->daddr, daddr); @@ -347,6 +355,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len, 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 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) 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 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) 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 --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 407e5eaa125a..c57d793c07cd 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -986,15 +986,15 @@ struct proto_ops netlink_ops = { 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 --git a/net/netsyms.c b/net/netsyms.c index 7cd274478e29..d9767a09ec93 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -60,8 +60,7 @@ extern int tcp_tw_death_row_slot; 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 @@ extern int sysctl_max_syn_backlog; 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_inc_group); 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 @@ EXPORT_SYMBOL(sock_rmalloc); 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 --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e8ebbcb7a084..5f760d394fb6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1182,8 +1182,8 @@ struct proto_ops packet_ops_spkt = { packet_release, packet_bind_spkt, sock_no_connect, - NULL, - NULL, + sock_no_socketpair, + sock_no_accept, packet_getname_spkt, datagram_poll, packet_ioctl, diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 514f64e1b52f..60a3581e5942 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -174,7 +174,8 @@ static void x25_kill_by_device(struct device *dev) 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 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len 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; @@ -786,6 +790,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i return 0; } + /* + * current neighbour/link might impose additional limits + * on certain facilties + */ + + x25_limit_facilities(&facilities,neigh); + /* * Try to create a new socket. */ @@ -1124,18 +1135,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 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) @@ -1276,6 +1277,16 @@ struct notifier_block x25_dev_notifier = { 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 = { PROC_NET_X25, 3, "x25", diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 16fc3677d3cc..bcbf31b0dfca 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -98,6 +98,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) 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 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packe 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 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh) { unsigned char *dptr; + skb->nh.raw = skb->data; + switch (neigh->dev->type) { case ARPHRD_X25: dptr = skb_push(skb, 1); @@ -238,3 +247,6 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh) } #endif + + + diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index af072ce22dbe..18de2da1a9c0 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -200,4 +200,26 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa 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 --git a/net/x25/x25_in.c b/net/x25/x25_in.c index ae98e95ec34e..ad7adb7ea558 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c @@ -49,17 +49,20 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) 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 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) 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 --git a/net/x25/x25_link.c b/net/x25/x25_link.c index f27fa4f4aeaa..961682702448 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -264,11 +264,14 @@ void x25_link_established(struct x25_neigh *neigh) /* * 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); } /* -- 2.39.5