which includes a server that supports the frame buffer device
directly (XF68_FBDev).
+Matrox unified accelerated driver
+CONFIG_FB_MATROX
+ Say Y here if you have Matrox Millenium, Matrox Millenium II, Matrox
+ Mystique, Matrox Mystique 220 or Matrox Productiva G100 in your box.
+ At this time, G100 support is untested and G200 support does not
+ exist at all. If you want, you can select M, in this case module
+ matroxfb.o will be created.
+ You can pass parameters into driver if it is compiled into kernel by
+ specifying "video=matrox:XXX", where meaning of XXX you can found at
+ the end of main source file (drivers/video/matroxfb.c) at boottime.
+ Same parameters can be passed into insmod if driver is used as
+ module.
+
+Matrox Millenium support
+CONFIG_FB_MATROX_MILLENIUM
+ Say Y here if you have Matrox Millenium or Matrox Millenium II in the
+ box. If you select "Advanced lowlevel driver options", you should
+ check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp packed pixel, 24
+ bpp packed pixel and 32 bpp packed pixel. You can also use font
+ widths different from 8.
+
+Matrox Mystique support
+CONFIG_FB_MATROX_MYSTIQUE
+ Say Y here if you have Matrox Mystique or Matrox Mystique 220 in the
+ box. If you select "Advanced lowlevel driver options", you should
+ check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel
+ and 32 bpp packed pixel. You can also use font widths different
+ from 8.
+
+Matrox G100 support
+CONFIG_FB_MATROX_G100
+ Say Y here if you have Matrox Productiva G100 in the box. But THIS
+ DRIVER IS NOT TESTED BECAUSE OF I HAVE NO G100 board and G100
+ technical sheets are top secret at this time. But driver should not
+ cause any damage to your computer.
+ If you select "Advanced lowlevel driver options", you should check
+ 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and
+ 32 bpp packed pixel. You can also use font widths different from 8.
+
+Matrox unified driver multihead support
+CONFIG_FB_MATROX_MULTIHEAD
+ Say Y here if you have more than one (supported) Matrox device in
+ computer and you want to use all of them. If you have only one
+ device, you should say N because of driver compiled with Y is larger
+ and a bit slower, especially on ia32 (ix86).
+ If you compiled driver as module, you are VERY interested in speed
+ and you can use 40KB of memory per each Matrox device, you can
+ compile driver without multihead support and instead of it insmod
+ more module instances. In this case, you MUST specify parameter dev=N
+ to insmod, where N is sequential number of Matrox device (0 = first,
+ 1 = second and so on).
+
MDA text console (dual-headed)
CONFIG_MDA_CONSOLE
Say Y here if you have an old MDA or monochrome Hercules graphics
The module will be called fdomain.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+Future Domain MCS-600/700 SCSI support
+CONFIG_SCSI_FD_MCS
+ This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some
+ PS/2s are also equipped with IBM Fast SCSI Adapter/A which is an OEM
+ of the MCS 700. This driver also supports Reply SB16/SCSI card (the
+ SCSI part). It supports multiple adapters in the same system.
+
Generic NCR5380/53c400 SCSI support
CONFIG_SCSI_GENERIC_NCR5380
This is the generic NCR family of SCSI controllers, not to be
Comtrol Hostess SV-11 support
CONFIG_HOSTESS_SV11
- This is a network card for high speed synchronous serial links. It
- is commonly used to connect to Cisco equipment over HSSI links. At
- this point, the driver can only be compiled as a module.
+ This is a network card for low speed synchronous serial links, at
+ up to 256Kbits. It supports both PPP and Cisco HDLC
+ At this point, the driver can only be compiled as a module.
WAN Drivers
CONFIG_WAN_DRIVERS
is for you, read the Ethernet-HOWTO, available via FTP (user:
anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
-AT1700 support
+AT1700/1720 support
CONFIG_AT1700
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available via FTP (user: anonymous) in
driver applies only to the one with the 65c02 processor chip on it.
To include it in the kernel, select the CONFIG_LTPC switch in the
-configuration dialog; at this time (kernel 2.1.23) compiling it as
-a module will not work.
+configuration dialog. You can also compile it as a module.
+
+While the driver will attempt to autoprobe the I/O port address, IRQ
+line, and DMA channel of the card, this does not always work. For
+this reason, you should be prepared to supply these parameters
+yourself. (see "Card Configuration" below for how to determine or
+change the settings on your card)
+
+When the driver is compiled into the kernel, you can add a line such
+as the following to your /etc/lilo.conf:
+
+ append="ltpc=0x240,9,1"
+
+where the parameters (in order) are the port address, IRQ, and DMA
+channel. The second and third values can be omitted, in which case
+the driver will try to determine them itself.
+
+If you load the driver as a module, you can pass the parameters "io=",
+"irq=", and "dma=" on the command line with insmod or modprobe, or add
+them as options in /etc/conf.modules:
+
+ alias lt0 ltpc # autoload the module when the interface is configured
+ options ltpc io=0x240 irq=9 dma=1
Before starting up the netatalk demons (perhaps in rc.local), you
need to add a line such as:
-/sbin/ifconfig ltalk0 127.0.0.42
+ /sbin/ifconfig lt0 127.0.0.42
-
-The driver will autoprobe, and you should see a message like:
-"LocalTalk card found at 240, IR9, DMA1."
-at bootup.
+The address is unimportant - however, the card needs to be configured
+with ifconfig so that Netatalk can find it.
The appropriate netatalk configuration depends on whether you are
attached to a network that includes AppleTalk routers or not. If,
printers, you need to set up netatalk to "seed". The way I do this
is to have the lines
-dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
-ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
+ dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033"
+ lt0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033"
in my atalkd.conf. What is going on here is that I need to fool
netatalk into thinking that there are two AppleTalk interfaces
-present -- otherwise it refuses to seed. This is a hack, and a
-more permanent solution would be to alter the netatalk code.
-Note that the dummy driver needs to accept multicasts also -- earlier
-versions of dummy.c may need to be patched.
-
+present; otherwise, it refuses to seed. This is a hack, and a more
+permanent solution would be to alter the netatalk code. Also, make
+sure you have the correct name for the dummy interface - If it's
+compiled as a module, you will need to refer to it as "dummy0" or some
+such.
If you are attached to an extended AppleTalk network, with routers on
it, then you don't need to fool around with this -- the appropriate
line in atalkd.conf is
-ltalk0 -phase 1
+ lt0 -phase 1
--------------------------------------
--------------------------------------
IP:
- Many people are interested in this driver in order to use IP
-when LocalTalk, but no Ethernet, is available. While the code to do
-this is not strictly speaking part of this driver, an experimental
-version is available which seems to work under kernel 2.0.xx. It is
-not yet functional in the 2.1.xx kernels.
+
+Yes, it is possible to do IP over LocalTalk. However, you can't just
+treat the LocalTalk device like an ordinary Ethernet device, even if
+that's what it looks like to Netatalk.
+
+Instead, you follow the same procedure as for doing IP in EtherTalk.
+See Documentation/networking/ipddp.txt for more information about the
+kernel driver and userspace tools needed.
--------------------------------------
BUGS:
-2.0.xx:
+IRQ autoprobing often doesn't work on a cold boot. To get around
+this, either compile the driver as a module, or pass the parameters
+for the card to the kernel as described above.
+
+Also, as usual, autoprobing is not recommended when you use the driver
+as a module. (though it usually works at boot time, at least)
+
+Polled mode is *really* slow sometimes, but this seems to depend on
+the configuration of the network.
-2.1.xx: The module support doesn't work yet.
+It may theoretically be possible to use two LTPC cards in the same
+machine, but this is unsupported, so if you really want to do this,
+you'll probably have to hack the initialization code a bit.
______________________________________
-- Bradford Johnson <bradford@math.umn.edu>
+-- Updated 11/09/1998 by David Huggins-Daines <dhd@debian.org>
-Documentation for /proc/sys/*/* version 0.1
+Documentation for /proc/sys/ kernel version 2.1.128
(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
'Why', I hear you ask, 'would anyone even _want_ documentation
Furthermore, the programmers who built sysctl have built it to
be actually used, not just for the fun of programming it :-)
+If you prefer HTML, feel free to visit the Linux-MM homepage
+<http://www.phys.uu.nl/~riel/mm-patch/>...
+
==============================================================
Legal blurb:
debug/ <empty>
dev/ device specific information (eg dev/cdrom/info)
fs/ specific filesystems
+ filehandle, inode, dentry and quota tuning
binfmt_misc <linux/Documentation/binfmt_misc.txt>
kernel/ global kernel info / tuning
- open file / inode tuning
miscellaneous stuff
net/ networking stuff, for documentation look in:
<linux/Documentation/networking/>
--- /dev/null
+Documentation for /proc/sys/fs/* kernel version 2.1.128
+ (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
+
+For general info and legal blurb, please look in README.
+
+==============================================================
+
+This file contains documentation for the sysctl files in
+/proc/sys/fs/ and is valid for Linux kernel version 2.1.
+
+The files in this directory can be used to tune and monitor
+miscellaneous and general things in the operation of the Linux
+kernel. Since some of the files _can_ be used to screw up your
+system, it is advisable to read both documentation and source
+before actually making adjustments.
+
+Currently, these files are in /proc/sys/fs:
+- dentry-state
+- dquot-max
+- dquot-nr
+- file-max
+- file-nr
+- inode-max
+- inode-nr
+- inode-state
+
+Documentation for the files in /proc/sys/fs/binfmt_misc is
+in Documentation/binfmt_misc.txt.
+
+==============================================================
+
+dentry-state:
+
+From linux/fs/dentry.c:
+--------------------------------------------------------------
+struct {
+ int nr_dentry;
+ int nr_unused;
+ int age_limit; /* age in seconds */
+ int want_pages; /* pages requested by system */
+ int dummy[2];
+} dentry_stat = {0, 0, 45, 0,};
+--------------------------------------------------------------
+
+Dentries are dynamically allocated and deallocated, and
+nr_dentry seems to be 0 all the time. Hence it's safe to
+assume that only nr_unused, age_limit and want_pages are
+used. Nr_unused seems to be exactly what its name says.
+Age_limit is the age in seconds after which dcache entries
+can be reclaimed when memory is short and want_pages is
+nonzero when shrink_dcache_pages() has been called and the
+dcache isn't pruned yet.
+
+==============================================================
+
+dquot-max & dquot-nr:
+
+The file dquot-max shows the maximum number of cached disk
+quota entries.
+
+The file dquot-nr shows the number of allocated disk quota
+entries and the number of free disk quota entries.
+
+If the number of free cached disk quotas is very low and
+you have some awesome number of simultaneous system users,
+you might want to raise the limit.
+
+==============================================================
+
+file-max & file-nr:
+
+The kernel allocates file handles dynamically, but as yet it
+doesn't free them again.
+
+The value in file-max denotes the maximum number of file-
+handles that the Linux kernel will allocate. When you get lots
+of error messages about running out of file handles, you might
+want to increase this limit.
+
+The three values in file-nr denote the number of allocated
+file handles, the number of used file handles and the maximum
+number of file handles. When the allocated file handles come
+close to the maximum, but the number of actually used ones is
+far behind, you've encountered a peak in your usage of file
+handles and you don't need to increase the maximum.
+
+==============================================================
+
+inode-max, inode-nr & inode-state:
+
+As with file handles, the kernel allocates the inode structures
+dynamically, but can't free them yet.
+
+The value in inode-max denotes the maximum number of inode
+handlers. This value should be 3-4 times larger than the value
+in file-max, since stdin, stdout and network sockets also
+need an inode struct to handle them. When you regularly run
+out of inodes, you need to increase this value.
+
+The file inode-nr contains the first two items from
+inode-state, so we'll skip to that file...
+
+Inode-state contains three actual numbers and four dummies.
+The actual numbers are, in order of appearance, nr_inodes,
+nr_free_inodes and preshrink.
+
+Nr_inodes stands for the number of inodes the system has
+allocated, this can be slightly more than inode-max because
+Linux allocates them one pageful at a time.
+
+Nr_free_inodes represents the number of free inodes (?) and
+preshrink is nonzero when the nr_inodes > inode-max and the
+system needs to prune the inode list instead of allocating
+more.
+
+
-Documentation for /proc/sys/kernel/* version 0.1
+Documentation for /proc/sys/kernel/* kernel version 2.1.128
(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
For general info and legal blurb, please look in README.
system, it is advisable to read both documentation and source
before actually making adjustments.
-Currently, these files are in /proc/sys/kernel:
+Currently, these files might (depending on your configuration)
+show up in /proc/sys/kernel:
- acct
- ctrl-alt-del
- dentry-state
- domainname
-- file-max
-- file-nr
- hostname
-- inode-max
-- inode-nr
-- inode-state
+- htab-reclaim [ PPC only ]
+- java-appletviewer [ binfmt_java, obsolete ]
+- java-interpreter [ binfmt_java, obsolete ]
- modprobe ==> Documentation/kmod.txt
- osrelease
- ostype
- panic
+- powersave-nap [ PPC only ]
- printk
- real-root-dev ==> Documentation/initrd.txt
-- reboot-cmd ==> SPARC specific
-- securelevel
+- reboot-cmd [ SPARC only ]
+- sg-big-buff [ generic SCSI device (sg) ]
- version
+- zero-paged [ PPC only ]
==============================================================
==============================================================
-dentry-state:
-
-From linux/fs/dentry.c:
---------------------------------------------------------------
-struct {
- int nr_dentry;
- int nr_unused;
- int age_limit; /* age in seconds */
- int want_pages; /* pages requested by system */
- int dummy[2];
-} dentry_stat = {0, 0, 45, 0,};
---------------------------------------------------------------
-
-Dentries are dynamically allocated and deallocated, and
-nr_dentry seems to be 0 all the time. Hence it's safe to
-assume that only nr_unused, age_limit and want_pages are
-used. Nr_unused seems to be exactly what its name says.
-Age_limit is the age in seconds after which dcache entries
-can be reclaimed when memory is short and want_pages is
-nonzero when shrink_dcache_pages() has been called and the
-dcache isn't pruned yet.
-
-==============================================================
-
domainname & hostname:
These files can be controlled to set the domainname and
==============================================================
-file-max & file-nr:
-
-The kernel allocates file handles dynamically, but as yet it
-doesn't free them again.
-
-The value in file-max denotes the maximum number of file-
-handles that the Linux kernel will allocate. When you get lots
-of error messages about running out of file handles, you might
-want to increase this limit.
-
-The three values in file-nr denote the number of allocated
-file handles, the number of used file handles and the maximum
-number of file handles. When the allocated file handles come
-close to the maximum, but the number of actually used ones is
-far behind, you've encountered a peak in your usage of file
-handles and you don't need to increase the maximum.
-
-==============================================================
-
-inode-max, inode-nr & inode-state:
-
-As with file handles, the kernel allocates the inode structures
-dynamically, but can't free them yet.
-
-The value in inode-max denotes the maximum number of inode
-handlers. This value should be 3-4 times larger than the value
-in file-max, since stdin, stdout and network sockets also
-need an inode struct to handle them. When you regularly run
-out of inodes, you need to increase this value.
-
-The file inode-nr contains the first two items from
-inode-state, so we'll skip to that file...
-
-Inode-state contains three actual numbers and four dummies.
-The actual numbers are, in order of appearance, nr_inodes,
-nr_free_inodes and preshrink.
-
-Nr_inodes stands for the number of inodes the system has
-allocated, this can be slightly more than inode-max because
-Linux allocates them one pageful at a time.
-
-Nr_free_inodes represents the number of free inodes (?) and
-preshrink is nonzero when the nr_inodes > inode-max and the
-system needs to prune the inode list instead of allocating
-more.
+htab-reclaim: (PPC only)
+Setting this to a non-zero value, the PowerPC htab
+(see Documentation/powerpc/ppc_htab.txt) is pruned
+each time the system hits the idle loop.
+
==============================================================
osrelease, ostype & version:
==============================================================
+powersave-nap: (PPC only)
+
+If set, Linux-PPC will use the 'nap' mode of powersaving,
+otherwise the 'doze' mode will be used.
+
+==============================================================
+
printk:
The four values in printk denote: console_loglevel,
==============================================================
-securelevel:
+reboot-cmd: (Sparc only)
-When the value in this file is nonzero, root is prohibited
-from:
-- changing the immutable and append-only flags on files
-- changing sysctl things (limited ???)
+??? This seems to be a way to give an argument to the Sparc
+ROM/Flash boot loader. Maybe to tell it what to do after
+rebooting. ???
==============================================================
-real-root-dev: (CONFIG_INITRD only)
+sg-big-buff:
-This file is used to configure the real root device when using
-an initial ramdisk to configure the system before switching to
-the 'real' root device. See linux/Documentation/initrd.txt for
-more info.
+This file shows the size of the generic SCSI (sg) buffer.
+You can't tune it just yet, but you could change it on
+compile time by editing include/scsi/sg.h and changing
+the value of SG_BIG_BUFF.
-==============================================================
+There shouldn't be any reason to change this value. If
+you can come up with one, you probably know what you
+are doing anyway :)
-reboot-cmd: (Sparc only)
+==============================================================
-??? This seems to be a way to give an argument to the Sparc
-ROM/Flash boot loader. Maybe to tell it what to do after
-rebooting. ???
+zero-paged: (PPC only)
+When enabled (non-zero), Linux-PPC will pre-zero pages in
+the idle loop, possibly speeding up get_free_pages. Since
+this only affects what the idle loop is doing, you should
+enable this and see if anything changes.
-Documentation for /proc/sys/vm/* version 0.1
+Documentation for /proc/sys/vm/* kernel version 2.1.128
(c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
For general info and legal blurb, please look in README.
- kswapd
- overcommit_memory
- pagecache
+- pagetable_cache
- swapctl
-- swapout_interval
==============================================================
} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
--------------------------------------------------------------
-The first parameter governs the maximum number of of dirty
+The first parameter governs the maximum number of dirty
buffers in the buffer cache. Dirty means that the contents
of the buffer still have to be written to disk (as opposed
to a clean buffer, which can just be forgotten about).
min_percent -- this is the minimum percentage of memory
that should be spent on buffer memory
borrow_percent -- when Linux is short on memory, and the
- buffer cache uses more memory, free pages
- are stolen from it
+ buffer cache uses more memory than this,
+ the MM subsystem will prune the buffercache
+ more heavily than other memory
max_percent -- this is the maximum amount of memory that
can be used for buffer memory
This file contains the values in the struct freepages. That
struct contains three members: min, low and high.
-Although the goal of the Linux memory management subsystem
-is to avoid fragmentation and make large chunks of free
-memory (so that we can hand out DMA buffers and such), there
-still are some page-based limits in the system, mainly to
-make sure we don't waste too much memory trying to get large
-free area's.
-
The meaning of the numbers is:
freepages.min When the number of free pages in the system
reaches this number, only the kernel can
allocate more memory.
-freepages.low If memory is too fragmented, the swapout
- daemon is started, except when the number
- of free pages is larger than freepages.low.
-freepages.high The swapping daemon exits when memory is
- sufficiently defragmented, when the number
- of free pages reaches freepages.high or when
- it has tried the maximum number of times.
+freepages.low If the number of free pages gets below this
+ point, the kernel starts swapping agressively.
+freepages.high The kernel tries to keep up to this amount of
+ memory free; if memory comes below this point,
+ the kernel gently starts swapping in the hopes
+ that it never has to do real agressive swapping.
==============================================================
This file does exactly the same as buffermem, only this
file controls the struct page_cache, and thus controls
-the amount of memory allowed for memory mapping of files.
+the amount of memory allowed for memory mapping and generic
+caching of files.
You don't want the minimum level to be too low, otherwise
your system might thrash when memory is tight or fragmentation
==============================================================
+pagetable_cache:
+
+The kernel keeps a number of page tables in a per-processor
+cache (this helps a lot on SMP systems). The cache size for
+each processor will be between the low and the high value.
+
+On a low-memory, single CPU system you can safely set these
+values to 0 so you don't waste the memory. On SMP systems it
+is used so that the system can do fast pagetable allocations
+without having to aquire the kernel memory lock.
+
+For large systems, the settings are probably OK. For normal
+systems they won't hurt a bit. For small systems (<16MB ram)
+it might be advantageous to set both values to 0.
+
+==============================================================
+
swapctl:
This file contains no less than 8 variables.
might want to either increase sc_bufferout_weight, or decrease
the value of sc_pageout_weight.
-==============================================================
-
-swapout_interval:
-
-The single value in this file controls the amount of time
-between successive wakeups of kswapd when nr_free_pages is
-between free_pages_low and free_pages_high. The default value
-of HZ/4 is usually right, but when kswapd can't keep up with
-the number of allocations in your system, you might want to
-decrease this number.
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 128
+SUBLEVEL = 129
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
EXPORT_SYMBOL(mca_set_adapter_procfn);
EXPORT_SYMBOL(mca_isenabled);
EXPORT_SYMBOL(mca_isadapter);
+EXPORT_SYMBOL(mca_mark_as_used);
+EXPORT_SYMBOL(mca_mark_as_unused);
+EXPORT_SYMBOL(mca_find_unused_adapter);
#endif
#ifdef CONFIG_VT
fi
fi
if [ "$CONFIG_MCA" = "y" ]; then
- bool 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+ tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
comment 'Additional Block Devices'
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+if [ "$CONFIG_NET" = "y" ]; then
+ tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+fi
bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
tristate ' Linear (append) mode' CONFIG_MD_LINEAR
ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */
- drive->present = 1;
printk("%s: %s, ", drive->name, id->model);
+ drive->present = 1;
+
+ /*
+ * Prevent long system lockup probing later for non-existant
+ * slave drive if the hwif is actually a Kodak CompactFlash card.
+ */
+ if (!strcmp(id->model, "KODAK ATA_FLASH")) {
+ ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+ mate->present = 0;
+ mate->noprobe = 1;
+ }
/*
* Check for an ATAPI device
/*
- * linux/drivers/block/via82C586.c Version 0.01 Aug 16, 1998
+ * linux/drivers/block/via82c586.c Version 0.01 Aug 16, 1998
*
* Copyright (C) 1998 Michel Aubry
* Copyright (C) 1998 Andre Hedrick
struct cdrom_device_ops * cdo);
static void sanitize_format(union cdrom_addr *addr,
u_char * curr, u_char requested);
+#ifdef CONFIG_SYSCTL
static void cdrom_sysctl_register(void);
+#endif /* CONFIG_SYSCTL */
static struct cdrom_device_info *topCdromPtr = NULL;
struct file_operations cdrom_fops =
switch (cmd) {
case RNDGETENTCNT:
- retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (retval)
- return(retval);
ent_count = random_state.entropy_count;
- put_user(ent_count, (int *) arg);
+ if (put_user(ent_count, (int *) arg))
+ return -EFAULT;
return 0;
case RNDADDTOENTCNT:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
- if (retval)
- return(retval);
- get_user(ent_count, (int *) arg);
+ if (get_user(ent_count, (int *) arg))
+ return -EFAULT;
/*
* Add i to entropy_count, limiting the result to be
* between 0 and POOLBITS.
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
p = (int *) arg;
- retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
- if (retval)
- return(retval);
ent_count = random_state.entropy_count;
- put_user(ent_count, p++);
- retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int));
- if (retval)
- return(retval);
- get_user(size, p);
- put_user(POOLWORDS, p++);
+ if (put_user(ent_count, p++))
+ return -EFAULT;
+
+ if (get_user(size, p))
+ return -EFAULT;
+ if (put_user(POOLWORDS, p++))
+ return -EFAULT;
if (size < 0)
return -EINVAL;
if (size > POOLWORDS)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
p = (int *) arg;
- retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int));
- if (retval)
- return(retval);
- get_user(ent_count, p++);
+ if (get_user(ent_count, p++))
+ return -EFAULT;
if (ent_count < 0)
return -EINVAL;
- get_user(size, p++);
- retval = verify_area(VERIFY_READ, (void *) p, size);
- if (retval)
- return retval;
+ if (get_user(size, p++))
+ return -EFAULT;
retval = random_write(file, (const char *) p,
size, &file->f_pos);
if (retval < 0)
printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
p->irq);
+#ifdef CONFIG_PROC_FS
parport_proc_register(p);
+#endif
p->flags |= PARPORT_FLAG_COMA;
if (parport_probe_hook)
printmode(ECPPS2);
}
printk("]\n");
+#ifdef CONFIG_PROC_FS
parport_proc_register(p);
+#endif
p->flags |= PARPORT_FLAG_COMA;
p->ops->write_control(p, 0x0c);
if (p->modes & PARPORT_MODE_PCSPP) {
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
+#ifdef CONFIG_PROC_FS
parport_proc_unregister(p);
+#endif
parport_unregister_port(p);
}
p = tmp;
#ifdef MODULE
int init_module(void)
{
+#ifdef CONFIG_PROC_FS
(void)parport_proc_init(); /* We can go on without it. */
+#endif
return 0;
}
void cleanup_module(void)
{
+#ifdef CONFIG_PROC_FS
parport_proc_cleanup();
+#endif
}
#else
__initfunc(int parport_init(void))
#ifdef CONFIG_PNP_PARPORT
parport_probe_hook = &parport_probe_one;
#endif
+#ifdef CONFIG_PROC_FS
parport_proc_init();
+#endif
#ifdef CONFIG_PARPORT_PC
parport_pc_init(io, irq, dma);
#endif
EXPORT_SYMBOL(parport_enumerate);
EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
EXPORT_SYMBOL(parport_wait_peripheral);
+#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(parport_proc_register);
EXPORT_SYMBOL(parport_proc_unregister);
+#endif
EXPORT_SYMBOL(parport_probe_hook);
EXPORT_SYMBOL(parport_parse_irqs);
}
#undef printmode
printk("]\n");
+#ifdef CONFIG_PROC_FS
if (probedirq != PARPORT_IRQ_NONE)
printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
parport_proc_register(p);
+#endif
p->flags |= PARPORT_FLAG_COMA;
/* Done probing. Now put the port into a sensible start-up state. */
if (p->modes & PARPORT_MODE_PCSPP) {
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
+#ifdef CONFIG_PROC_FS
parport_proc_unregister(p);
+#endif
parport_unregister_port(p);
}
p = tmp;
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/timer.h>
#include <asm/byteorder.h>
#if defined(CONFIG_LTPC)
extern int ltpc_probe(struct device *);
static struct device dev_ltpc = {
- "ltalk0\0 ",
+ "lt0\0 ",
0, 0, 0, 0,
0x0, 0,
0, 0, 0, NEXT_DEV, ltpc_probe };
static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
- int err;
unsigned int tmp;
/* First make sure we're connected. */
static int hostess_ioctl(struct device *d, struct ifreq *ifr, int cmd)
{
- struct sv11_device *sv11=d->priv;
- /* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
+ /* struct sv11_device *sv11=d->priv;
+ z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
return sppp_do_ioctl(d, ifr,cmd);
}
* Hacked about a bit to clean things up - Alan Cox
* Probably broken it from the origina 1.8
*
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+ and to probe for things in the standard order of i/o, irq, dma. This
+ removes the "reset the reset" hack, because I couldn't figure out an
+ easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+ line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+ other localtalk driver, and to clear up the inconsistency between the
+ module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+ codes and the register offsets, but I'm still not sure exactly what their
+ semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+ I'm responsible for that...
+
+ *
* Revision 1.7 1996/12/12 03:42:33 bradford
* DMA alloc cribbed from 3c505.c.
*
#define DEBUG_UPPER 2
#define DEBUG_LOWER 4
+static int io=0;
+static int irq=0;
+static int dma=0;
#ifdef MODULE
#include <linux/module.h>
return __get_dma_pages(GFP_KERNEL, order);
}
+/* DMA data buffer, DMA command buffer */
static unsigned char *ltdmabuf;
static unsigned char *ltdmacbuf;
+/* private struct, holds our appletalk address */
+
struct ltpc_private
{
struct net_device_stats stats;
struct at_addr my_addr;
};
+/* transmit queue element struct */
+
struct xmitQel {
struct xmitQel *next;
+ /* command buffer */
unsigned char *cbuf;
short cbuflen;
+ /* data buffer */
unsigned char *dbuf;
short dbuflen;
unsigned char QWrite; /* read or write data */
unsigned char mailbox;
};
+/* the transmit queue itself */
+
static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
static void enQ(struct xmitQel *qel)
return qel;
}
+/* and... the queue elements we'll be using */
static struct xmitQel qels[16];
+/* and their corresponding mailboxes */
static unsigned char mailbox[16];
static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
return 1; /* timed out */
}
+/* get the first free mailbox */
+
static int getmbox(void)
{
unsigned long flags;
return 0;
}
+/* read a command from the card */
static void handlefc(struct device *dev)
{
/* called *only* from idle, non-reentrant */
if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
}
+/* read data from the card */
static void handlefd(struct device *dev)
{
int dma = dev->dma;
if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
}
-static unsigned char rescbuf[2] = {0,0};
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
static unsigned char resdbuf[2];
static int QInIdle=0;
struct xmitQel *q=0;
int oops;
int i;
- int statusPort = dev->base_addr+6;
+ int base = dev->base_addr;
save_flags(flags);
cli();
restore_flags(flags);
-
- (void) inb_p(statusPort); /* this tri-states the IRQ line */
+ /* this tri-states the IRQ line */
+ (void) inb_p(base+6);
oops = 100;
goto done;
}
- state = inb_p(statusPort);
- if (state != inb_p(statusPort)) goto loop;
+ state = inb_p(base+6);
+ if (state != inb_p(base+6)) goto loop;
switch(state) {
- case 0xfc:
+ case 0xfc:
+ /* incoming command */
if (debug&DEBUG_LOWER) printk("idle: fc\n");
handlefc(dev);
break;
- case 0xfd:
+ case 0xfd:
+ /* incoming data */
if(debug&DEBUG_LOWER) printk("idle: fd\n");
handlefd(dev);
break;
- case 0xf9:
+ case 0xf9:
+ /* result ready */
if (debug&DEBUG_LOWER) printk("idle: f9\n");
if(!mboxinuse[0]) {
mboxinuse[0] = 1;
printk("timed out idle f9\n");
break;
case 0xf8:
+ /* ?? */
if (xmQhd) {
inb_p(dev->base_addr+1);
inb_p(dev->base_addr+0);
goto done;
}
break;
- case 0xfa:
+ case 0xfa:
+ /* waiting for command */
if(debug&DEBUG_LOWER) printk("idle: fa\n");
if (xmQhd) {
q=deQ();
printk("\n");
}
handlecommand(dev);
- if(0xfa==inb_p(statusPort)) {
+ if(0xfa==inb_p(base+6)) {
/* we timed out, so return */
goto done;
}
}
}
break;
- case 0xfb:
+ case 0Xfb:
+ /* data transfer ready */
if(debug&DEBUG_LOWER) printk("idle: fb\n");
if(q->QWrite) {
memcpy(ltdmabuf,q->dbuf,q->dbuflen);
handlewrite(dev);
} else {
handleread(dev);
+ /* non-zero mailbox numbers are for
+ commmands, 0 is for GETRESULT
+ requests */
if(q->mailbox) {
memcpy(q->dbuf,ltdmabuf,q->dbuflen);
} else {
QInIdle=0;
/* now set the interrupts back as appropriate */
- /* the first 7 takes it out of tri-state (but still high) */
+ /* the first read takes it out of tri-state (but still high) */
/* the second resets it */
- /* note that after this point, any read of 6 will trigger an interrupt */
+ /* note that after this point, any read of base+6 will
+ trigger an interrupt */
if (dev->irq) {
- inb_p(dev->base_addr+7);
- inb_p(dev->base_addr+7);
+ inb_p(base+7);
+ inb_p(base+7);
}
return;
}
return do_write(dev, &c, sizeof(c.setflags),&c,0);
}
+/* LLAP to DDP translation */
+
static int sendup_buffer (struct device *dev)
{
/* on entry, command is in ltdmacbuf, data in ltdmabuf */
if (!dev)
return; /* we've been downed */
- if (dev->irq)
- {
- /* we're set up for interrupts */
- if (0xf8 != inb_p(dev->base_addr+7)) {
- /* trigger an interrupt */
- (void) inb_p(dev->base_addr+6);
- }
- ltpc_timer.expires = jiffies+100;
- } else {
- /* we're strictly polling mode */
- idle(dev);
- ltpc_timer.expires = jiffies+5;
- }
-
+ idle(dev);
+ ltpc_timer.expires = jiffies+5;
+
add_timer(<pc_timer);
}
+/* DDP to LLAP translation */
+
static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
{
/* in kernel 1.3.xx, on entry skb->data points to ddp header,
return stats;
}
-static unsigned short irqhitmask;
-
-__initfunc(static void lt_probe_handler(int irq, void *dev_id, struct pt_regs *reg_ptr))
-{
- irqhitmask |= 1<<irq;
-}
-
-__initfunc(int ltpc_probe(struct device *dev))
+/* initialization stuff */
+
+__initfunc(int ltpc_probe_dma(int base))
{
- int err;
- unsigned char dma=0;
- short base=0;
- unsigned char irq=0;
- int x=0,y=0;
- int timeout;
- int probe3, probe4, probe9;
- unsigned short straymask;
- unsigned long flags;
- unsigned long f;
-
- err = ltpc_init(dev);
- if (err) return err;
-
- /* occasionally the card comes up with reset latched, so we need
- * to "reset the reset" first of all -- check the irq first also
- */
-
- save_flags(flags);
- cli();
-
- probe3 = request_irq( 3, <_probe_handler, 0, "ltpc_probe",dev);
- probe4 = request_irq( 4, <_probe_handler, 0, "ltpc_probe",dev);
- probe9 = request_irq( 9, <_probe_handler, 0, "ltpc_probe",dev);
-
- irqhitmask = 0;
-
- sti();
-
- timeout = jiffies+2;
- while(timeout>jiffies) ; /* wait for strays */
-
- straymask = irqhitmask; /* pick up any strays */
-
- /* if someone already owns this address, don't probe */
- if (!check_region(0x220,8)) {
- inb_p(0x227);
- inb_p(0x227);
- x=inb_p(0x226);
- timeout = jiffies+2;
- while(timeout>jiffies) ;
- if(straymask != irqhitmask) base = 0x220;
- }
- if (!check_region(0x240,8)) {
- inb_p(0x247);
- inb_p(0x247);
- y=inb_p(0x246);
- timeout = jiffies+2;
- while(timeout>jiffies) ;
- if(straymask != irqhitmask) base = 0x240;
- }
-
- /* at this point, either we have an irq and the base addr, or
- * there isn't any irq and we don't know the base address, but
- * in either event the card is no longer latched in reset and
- * the irq request line is tri-stated.
- */
-
- cli();
-
- if (!probe3) free_irq(3,dev);
- if (!probe4) free_irq(4,dev);
- if (!probe9) free_irq(9,dev);
-
- sti();
-
- irqhitmask &= ~straymask;
-
- irq = ffz(~irqhitmask);
- if (irqhitmask != 1<<irq)
- printk("ltpc card raised more than one interrupt!\n");
-
- if (!base) {
- if (!check_region(0x220,8)) {
- x = inb_p(0x220+6);
- if ( (x!=0xff) && (x>=0xf0) ) base = 0x220;
- }
-
- if (!check_region(0x240,8)) {
- y = inb_p(0x240+6);
- if ( (y!=0xff) && (y>=0xf0) ) base = 0x240;
- }
- }
-
- if(base) {
- request_region(base,8,"ltpc");
- } else {
- printk("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",x,y);
- restore_flags(flags);
- return -1;
- }
-
- ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
- if (ltdmabuf) ltdmacbuf = <dmabuf[800];
-
- if (!ltdmabuf) {
- printk("ltpc: mem alloc failed\n");
- restore_flags(flags);
- return(-1);
- }
-
- if(debug&DEBUG_VERBOSE) {
- printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
- }
-
- /* reset the card */
-
- inb_p(base+1);
- inb_p(base+3);
- timeout = jiffies+2;
- while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
- inb_p(base+0);
- inb_p(base+2);
- inb_p(base+7); /* clear reset */
- inb_p(base+4);
- inb_p(base+5);
- inb_p(base+5); /* enable dma */
- inb_p(base+6); /* tri-state interrupt line */
-
- timeout = jiffies+100;
-
- while(timeout>jiffies) {
- /* wait for the card to complete initialization */
- }
-
- /* now, figure out which dma channel we're using */
-
- /* set up both dma 1 and 3 for read call */
-
- if (!request_dma(1,"ltpc")) {
-
- f=claim_dma_lock();
- disable_dma(1);
- clear_dma_ff(1);
+ int dma = 0;
+ int timeout;
+ unsigned long f;
+
+ if (!request_dma(1,"ltpc")) {
+ f=claim_dma_lock();
+ disable_dma(1);
+ clear_dma_ff(1);
set_dma_mode(1,DMA_MODE_WRITE);
set_dma_addr(1,virt_to_bus(ltdmabuf));
set_dma_count(1,sizeof(struct lt_mem));
/* FIXME -- do timings better! */
- ltdmabuf[0] = 2; /* read request */
+ ltdmabuf[0] = LT_READMEM;
ltdmabuf[1] = 1; /* mailbox */
ltdmabuf[2] = 0; ltdmabuf[3] = 0; /* address */
ltdmabuf[4] = 0; ltdmabuf[5] = 1; /* read 0x0100 bytes */
ltdmabuf[6] = 0; /* dunno if this is necessary */
- inb_p(base+1);
- inb_p(base+0);
+ inb_p(io+1);
+ inb_p(io+0);
timeout = jiffies+100;
while(timeout>jiffies) {
- if ( 0xfa == inb_p(base+6) ) break;
+ if ( 0xfa == inb_p(io+6) ) break;
}
- inb_p(base+3);
- inb_p(base+2);
+ inb_p(io+3);
+ inb_p(io+2);
while(timeout>jiffies) {
- if ( 0xfb == inb_p(base+6) ) break;
+ if ( 0xfb == inb_p(io+6) ) break;
}
- /* release the other dma channel */
+ /* release the other dma channel (if we opened both of them) */
if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
dma&=1;
dma&=0x2;
free_dma(1);
}
-
- if (!dma) { /* no dma channel */
- printk("No DMA channel found on ltpc card.\n");
- restore_flags(flags);
- return -1;
- }
-
+
/* fix up dma number */
dma|=1;
- /* set up read */
+ return dma;
+}
+
+__initfunc(int ltpc_probe(struct device *dev))
+{
+ int err;
+ int x=0,y=0;
+ int timeout;
+ int autoirq;
+ unsigned long flags;
+ unsigned long f;
+
+ save_flags(flags);
+
+ /* probe for the I/O port address */
+ if (io != 0x240 && !check_region(0x220,8)) {
+ x = inb_p(0x220+6);
+ if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+ }
+
+ if (io != 0x220 && !check_region(0x240,8)) {
+ y = inb_p(0x240+6);
+ if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+ }
+
+ if(io) {
+ /* found it, now grab it */
+ request_region(io,8,"ltpc");
+ } else {
+ /* give up in despair */
+ printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+ x,y);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* probe for the IRQ line */
+ if (irq < 2) {
+ autoirq_setup(2);
+
+ /* reset the interrupt line */
+ inb_p(io+7);
+ inb_p(io+7);
+ /* trigger an interrupt (I hope) */
+ inb_p(io+6);
+
+ autoirq = autoirq_report(1);
+
+ if (autoirq == 0) {
+ printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+ io);
+ }
+ else {
+ irq = autoirq;
+ }
+ }
+
+ /* allocate a DMA buffer */
+ ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+ if (ltdmabuf) ltdmacbuf = <dmabuf[800];
+
+ if (!ltdmabuf) {
+ printk("ltpc: mem alloc failed\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ if(debug&DEBUG_VERBOSE) {
+ printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+ }
+
+ /* reset the card */
+
+ inb_p(io+1);
+ inb_p(io+3);
+ timeout = jiffies+2;
+ while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */
+ inb_p(io+0);
+ inb_p(io+2);
+ inb_p(io+7); /* clear reset */
+ inb_p(io+4);
+ inb_p(io+5);
+ inb_p(io+5); /* enable dma */
+ inb_p(io+6); /* tri-state interrupt line */
+
+ timeout = jiffies+100;
+
+ while(timeout>jiffies) {
+ /* wait for the card to complete initialization */
+ }
+
+ /* now, figure out which dma channel we're using, unless it's
+ already been specified */
+ /* well, 0 is a legal DMA channel, but the LTPC card doesn't
+ use it... */
+ if (dma == 0) {
+ dma = ltpc_probe_dma(io);
+ if (!dma) { /* no dma channel */
+ printk("No DMA channel found on ltpc card.\n");
+ restore_flags(flags);
+ return -1;
+ }
+ }
+
+ /* print out friendly message */
if(irq)
- printk("LocalTalk card found at %03x, IR%d, DMA%d.\n",base,irq,dma);
+ printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
else
- printk("LocalTalk card found at %03x, DMA%d. Using polled mode.\n",base,dma);
-
- dev->base_addr = base;
+ printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma);
+
+ /* seems more logical to do this *after* probing the card... */
+ err = ltpc_init(dev);
+ if (err) return err;
+
+ dev->base_addr = io;
dev->irq = irq;
dev->dma = dma;
- if(debug&DEBUG_VERBOSE) {
- printk("finishing up transfer\n");
- }
-
+ /* the card will want to send a result at this point */
+ /* (I think... leaving out this part makes the kernel crash,
+ so I put it back in...) */
+
f=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
enable_dma(dma);
release_dma_lock(f);
- (void) inb_p(base+3);
- (void) inb_p(base+2);
+ (void) inb_p(io+3);
+ (void) inb_p(io+2);
timeout = jiffies+100;
while(timeout>jiffies) {
- if( 0xf9 == inb_p(base+6)) break;
+ if( 0xf9 == inb_p(io+6)) break;
}
if(debug&DEBUG_VERBOSE) {
printk("setting up timer and irq\n");
}
- init_timer(<pc_timer);
- ltpc_timer.function=ltpc_poll;
- ltpc_timer.data = (unsigned long) dev;
-
if (irq) {
+ /* grab it and don't let go :-) */
(void) request_irq( irq, <pc_interrupt, 0, "ltpc", dev);
- (void) inb_p(base+7); /* enable interrupts from board */
- (void) inb_p(base+7); /* and reset irq line */
- ltpc_timer.expires = 100;
- /* poll it once per second just in case */
+ (void) inb_p(io+7); /* enable interrupts from board */
+ (void) inb_p(io+7); /* and reset irq line */
} else {
- ltpc_timer.expires = 5;
- /* polled mode -- 20 times per second */
- }
-
- ltpc_timer.expires += jiffies; /* 1.2 to 1.3 change... */
-
- add_timer(<pc_timer);
+ /* polled mode -- 20 times per second */
+ /* this is really, really slow... should it poll more often? */
+ init_timer(<pc_timer);
+ ltpc_timer.function=ltpc_poll;
+ ltpc_timer.data = (unsigned long) dev;
- restore_flags(flags);
+ ltpc_timer.expires = jiffies + 5;
+ add_timer(<pc_timer);
+ restore_flags(flags);
+ }
return 0;
}
+/* handles "ltpc=io,irq,dma" kernel command lines */
+__initfunc(void ltpc_setup(char *str, int *ints))
+{
+ if (ints[0] == 0) {
+ if (str && !strncmp(str, "auto", 4)) {
+ /* do nothing :-) */
+ }
+ else {
+ /* usage message */
+ printk (KERN_ERR
+ "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+ }
+ return;
+ } else {
+ io = ints[1];
+ if (ints[0] > 1) {
+ irq = ints[2];
+ return;
+ }
+ if (ints[0] > 2) {
+ dma = ints[3];
+ return;
+ }
+ /* ignore any other paramters */
+ }
+ return;
+}
+
#ifdef MODULE
static char dev_name[8];
0x0, 0,
0, 0, 0, NULL, ltpc_probe };
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
int init_module(void)
{
+ int err, result;
+
+ if(io == 0)
+ printk(KERN_NOTICE
+ "ltpc: Autoprobing is not recommended for modules\n");
+
/* Find a name for this unit */
- int err=dev_alloc_name(&dev_ltpc,"lt%d");
+ err=dev_alloc_name(&dev_ltpc,"lt%d");
if(err<0)
return err;
- if (register_netdev(&dev_ltpc) != 0) {
- if(debug&DEBUG_VERBOSE) printk("EIO from register_netdev\n");
- return -EIO;
+ if ((result = register_netdev(&dev_ltpc)) != 0) {
+ printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+ return result;
} else {
if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
return 0;
if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
}
#endif /* MODULE */
+
skb->shapelatency=0;
skb->shapeclock=shaper->recovery;
- if(skb->shapeclock<jiffies)
+ if(time_before(skb->shapeclock, jiffies))
skb->shapeclock=jiffies;
skb->priority=0; /* short term bug fix */
skb->shapestamp=jiffies;
if(sh_debug)
printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
- if(skb->shapeclock <= jiffies + SHAPER_BURST)
+ if(skb->shapeclock - jiffies <= SHAPER_BURST)
{
/*
* Pull the frame and get interrupts back on.
/*
* Can't open until attached.
+ * Also can't open until speed is set, or we'll get
+ * a division by zero.
*/
if(shaper->dev==NULL)
return -ENODEV;
+ if(shaper->bitspersec==0)
+ return -EINVAL;
MOD_INC_USE_COUNT;
return 0;
}
shdev->type=dev->type;
shdev->addr_len=dev->addr_len;
shdev->mtu=dev->mtu;
+ sh->bitspersec=0;
return 0;
}
case SHAPER_GET_DEV:
if(sh->dev==NULL)
return -ENODEV;
- memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+ strcpy(ss->ss_name, sh->dev->name);
return 0;
case SHAPER_SET_SPEED:
shaper_setspeed(sh,ss->ss_speed);
if(dev->flags&IFF_UP)
return -EBUSY;
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch(cmd)
{
case SPPPIOCCISCO:
case SPPPIOCDEBUG:
sp->pp_flags&=~PP_DEBUG;
if(ifr->ifr_flags)
- {
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
sp->pp_flags|=PP_DEBUG;
- }
break;
default:
return -EINVAL;
save_flags(flags);
cli();
for (; expires_first &&
- ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires <= jiffies; )
+ time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); )
{
instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;
((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
ICR_ASSERT_SEL);
- while (probe_irq == IRQ_NONE && jiffies < timeout)
+ while (probe_irq == IRQ_NONE && time_before(jiffies,timeout))
barrier();
NCR5380_write(SELECT_ENABLE_REG, 0);
printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
instance->host_no);
timeout = jiffies + 5 * HZ;
- while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
+ while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY));
break;
case 2:
printk("scsi%d: bus busy, attempting abort\n",
&& !hostdata->dmalen
#endif
#ifdef USLEEP
- && (!hostdata->time_expires || hostdata->time_expires <= jiffies)
+ && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
#endif
) {
restore_flags(flags);
spin_unlock_irq(&io_request_lock);
while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK
- && jiffies < timeout);
+ && time_before(jiffies, timeout));
spin_lock_irq(&io_request_lock);
- if (jiffies >= timeout)
+ if (time_after_eq(jiffies, timeout) )
printk("scsi%d: timeout at NCR5380.c:%d\n",
host->host_no, __LINE__);
}
spin_unlock_irq(&io_request_lock);
while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && jiffies < timeout);
+ && time_before(jiffies,timeout));
spin_lock_irq(&io_request_lock);
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies,timeout)) {
printk("scsi: arbitration timeout at %d\n", __LINE__);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
waiting period */
#else
spin_unlock_irq(&io_request_lock);
- while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) &
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
(SR_BSY | SR_IO)));
spin_lock_irq(&io_request_lock);
#endif
unsigned long timeout = jiffies + NCR_TIMEOUT;
spin_unlock_irq(&io_request_lock);
- while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout);
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout));
spin_lock_irq(&io_request_lock);
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return -1;
{
/* RvC: go to sleep if polling time expired
*/
- if (!cmd->device->disconnect && jiffies >= poll_time)
+ if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time))
{
hostdata->time_expires = jiffies + USLEEP_SLEEP;
#if (NDEBUG & NDEBUG_USLEEP)
{"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
{"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */
{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */
+{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */
{"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
* for aha152x controller, which causes
return(-EBADF);
}
+static void scsi_proc_fill_inode(struct inode *inode, int fill)
+{
+Scsi_Host_Template *shpnt;
+
+shpnt = scsi_hosts;
+while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
+ shpnt = shpnt->next;
+if (!shpnt || !shpnt->module)
+ return;
+if (fill)
+ __MOD_INC_USE_COUNT(shpnt->module);
+else
+ __MOD_DEC_USE_COUNT(shpnt->module);
+}
+
void build_proc_dir_entries(Scsi_Host_Template *tpnt)
{
struct Scsi_Host *hpnt;
-
struct scsi_dir *scsi_hba_dir;
proc_scsi_register(0, tpnt->proc_dir);
-
+ tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
+
hpnt = scsi_hostlist;
while (hpnt) {
if (tpnt == hpnt->hostt) {
if (!share_dma)
{
- if (irq > 0)
+ if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
free_irq(devc->irq, (void *)devc->dev_no);
sound_free_dma(audio_devs[dev]->dmap_out->dma);
return len;
}
+#ifdef CONFIG_PROC_FS
static struct proc_dir_entry proc_root_sound = {
PROC_SOUND, 5, "sound",
S_IFREG | S_IRUGO, 1, 0, 0,
0, NULL, sound_proc_get_info
};
+#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
audio_init_devices();
}
#endif
+#ifdef CONFIG_PROC_FS
if (proc_register(&proc_root, &proc_root_sound))
printk(KERN_ERR "sound: registering /proc/sound failed\n");
+#endif
}
static int sound[20] = {
tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
+ bool 'Amiga CyberVisionPPC support (experimental)' CONFIG_FB_CVPPC
tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
fi
bool 'VESA VGA graphics console' CONFIG_FB_VESA
define_bool CONFIG_VIDEO_SELECT y
fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ tristate 'Matrox acceleration' CONFIG_FB_MATROX
+ if [ "$CONFIG_FB_MATROX" != "n" ]; then
+ bool ' Millenium I/II support' CONFIG_FB_MATROX_MILLENIUM
+ bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE
+ bool ' G100/G200 support' CONFIG_FB_MATROX_G100
+ bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+ fi
+ fi
+ fi
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS
if [ "$CONFIG_FB_SBUS" != "n" ]; then
"$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
"$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
"$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
- "$CONFIG_FB_IGA" = "y" ]; then
+ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" ]; then
define_bool CONFIG_FBCON_CFB8 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
"$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
"$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
- "$CONFIG_FB_IGA" = "y" ]; then
+ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" ]; then
define_bool CONFIG_FBCON_CFB8 m
fi
fi
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
- "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_MATROX" = "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" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_MATROX" = "m" ]; then
define_bool CONFIG_FBCON_CFB16 m
fi
fi
if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
- "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" ]; then
+ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+ "$CONFIG_FB_MATROX" = "y" ]; then
define_bool CONFIG_FBCON_CFB24 y
else
if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
- "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" ]; then
+ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+ "$CONFIG_FB_MATROX" = "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" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
- "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_MATROX" = "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" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_MATROX" = "m" ]; then
define_bool CONFIG_FBCON_CFB32 m
fi
fi
endif
endif
+ifeq ($(CONFIG_FB_CVPPC),y)
+L_OBJS += cvppcfb.o
+CONFIG_FBGEN_BUILTIN = y
+endif
+
ifeq ($(CONFIG_FB_MAC),y)
L_OBJS += macfb.o
endif
endif
endif
+ifeq ($(CONFIG_FB_MATROX),y)
+L_OBJS += matroxfb.o
+else
+ ifeq ($(CONFIG_FB_MATROX),m)
+ M_OBJS += matroxfb.o
+ endif
+endif
+
# Generic Low Level Drivers
ifeq ($(CONFIG_FBCON_AFB),y)
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#include <asm/setup.h>
+#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-afb.h>
struct fb_fix_screeninfo fix;
ami_encode_fix(&fix, &par);
- display->screen_base = fix.smem_start;
+ display->screen_base =
+ phys_to_virt ((unsigned long) fix.smem_start);
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, amifb_name);
- fix->smem_start = (char *)videomemory;
+ fix->smem_start = (char*) virt_to_phys((void *)videomemory);
fix->smem_len = videomemorysize;
#ifdef FBCON_HAS_MFB
-/* $Id: atyfb.c,v 1.81 1998/10/14 16:45:38 ecd Exp $
+/* $Id: atyfb.c,v 1.89 1998/11/12 13:07:26 geert Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
static char fontname[40] __initdata = { 0 };
static char curblink __initdata = 1;
static char noaccel __initdata = 0;
+static u32 default_vram __initdata = 0;
+static int default_pll __initdata = 0;
+static int default_mclk __initdata = 0;
static const u32 ref_clk_per = 1000000000000ULL/14318180;
#if defined(CONFIG_PPC)
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
#endif
#ifdef CONFIG_ATARI
};
static const char *aty_gx_ram[8] __initdata = {
- "DRAM", "VRAM", "VRAM", "DRAM", "GDRAM", "EVRAM", "EVRAM", "RESV"
+ "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"
};
static const char *aty_ct_ram[8] __initdata = {
- "OFF", "DRAM", "EDO", "HPDRAM", "SDRAM", "SGRAM", "WRAM", "RESV"
+ "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"
};
aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
/* ensure engine is not locked up by clearing any FIFO or */
/* HOST errors */
- aty_st_le32(0xf4,0xa955,info);
aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
BUS_FIFO_ERR_ACK, info);
}
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 */
+ aty_st_514(0x21, pll->n, info); /* F1 / N0 */
break;
}
}
(vclk_fb_div*mclk_post_div*bpp);
if (xclks_per_row < (1<<11))
FAIL("Dotclock to high");
- fifo_size = 24;
+ if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == VT_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) {
+ fifo_size = 24;
+ dsp_loop_latency = 0;
+ } else {
+ fifo_size = 32;
+ dsp_loop_latency = 2;
+ }
dsp_precision = 0;
y = (xclks_per_row*fifo_size)>>11;
while (y) {
if (info->total_vram > 1*1024*1024) {
if (info->ram_type >= SDRAM) {
/* >1 MB SDRAM */
- dsp_loop_latency = 8;
+ dsp_loop_latency += 8;
page_size = 8;
} else {
/* >1 MB DRAM */
- dsp_loop_latency = 6;
+ dsp_loop_latency += 6;
page_size = 9;
}
} else {
if (info->ram_type >= SDRAM) {
/* <2 MB SDRAM */
- dsp_loop_latency = 9;
+ dsp_loop_latency += 9;
page_size = 10;
} else {
/* <2 MB DRAM */
- dsp_loop_latency = 8;
+ dsp_loop_latency += 8;
page_size = 10;
}
}
struct fb_var_screeninfo var;
struct display *disp;
const char *chipname = NULL, *ramname = NULL;
- int pll, mclk;
+ int pll, mclk, gtb_memsize;
#if defined(CONFIG_PPC)
int sense;
#endif
}
}
}
- 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 */
- info->pll_per = 1000000/pll;
- info->mclk_per = 1000000/mclk;
i = aty_ld_le32(MEM_CNTL, info);
- 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))
+ gtb_memsize = (((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));
+ if (gtb_memsize)
switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
case MEM_SIZE_512K:
info->total_vram = 0x80000;
info->total_vram += 0x400000;
}
+ if (default_vram) {
+ info->total_vram = default_vram*1024;
+ i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+ if (info->total_vram <= 0x80000)
+ i |= MEM_SIZE_512K;
+ else if (info->total_vram <= 0x100000)
+ i |= MEM_SIZE_1M;
+ else if (info->total_vram <= 0x200000)
+ i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+ else if (info->total_vram <= 0x400000)
+ i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+ else if (info->total_vram <= 0x600000)
+ i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+ else
+ i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+ aty_st_le32(MEM_CNTL, i, info);
+ }
+ if (default_pll)
+ pll = default_pll;
+ if (default_mclk)
+ mclk = default_mclk;
+
printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n",
info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
+ 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 */
+ info->pll_per = 1000000/pll;
+ info->mclk_per = 1000000/mclk;
+
#ifdef DEBUG
if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
int i;
if (node == pcp->prom_node) {
struct fb_var_screeninfo *var = &default_var;
+ unsigned int N, P, Q, M, T;
u32 v_total, h_total;
struct crtc crtc;
u8 pll_regs[16];
u8 clock_cntl;
- unsigned int N, P, Q, M, T;
crtc.vxres = prom_getintdefault(node, "width", 1024);
crtc.vyres = prom_getintdefault(node, "height", 768);
*/
clock_cntl = aty_ld_8(CLOCK_CNTL, info);
/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < 16; i++)
pll_regs[i] = aty_ld_pll(i, info);
- /* printk("atyfb: PLL %2d: %02x\n", i, pll_regs[i]); */
- }
+
/*
* PLL Reference Devider M:
*/
M = pll_regs[2];
- /* printk("atyfb: M: %02x\n", M); */
/*
* PLL Feedback Devider N (Dependant on CLOCK_CNTL):
*/
N = pll_regs[7 + (clock_cntl & 3)];
- /* printk("atyfb: N: %02x\n", N); */
/*
* PLL Post Devider P (Dependant on CLOCK_CNTL):
*/
P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
- /* printk("atyfb: P: %2d\n", P); */
/*
* PLL Devider Q:
*/
Q = N / P;
- /* printk("atyfb: Q: %d\n", Q); */
/*
* Target Frequency:
* where R is XTALIN (= 14318 kHz).
*/
T = 2 * Q * 14318 / M;
- /* printk("atyfb: T: %d\n", T); */
- default_var.pixclock =
- ((1000000000000ULL / v_total) * 1000) / (T * h_total);
- /* printk("atyfb: pixclock: %d\n", default_var.pixclock); */
+ default_var.pixclock = 1000000000 / T;
}
#else /* __sparc__ */
struct fb_info_aty *info;
int i;
- for (; dp; dp = dp->next) {
- switch (dp->n_addrs) {
- case 1:
- case 2:
- case 3:
- addr = dp->addrs[0].address;
- break;
- case 4:
- addr = dp->addrs[1].address;
- break;
- default:
- printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
- for (i = 0; i < dp->n_addrs; i++)
- printk(" %08x-%08x", dp->addrs[i].address,
- dp->addrs[i].address+dp->addrs[i].size-1);
- if (dp->n_addrs)
- printk("\n");
- continue;
- }
-
- info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
- if (!info) {
- printk("atyfb_of_init: can't alloc fb_info_aty\n");
+ switch (dp->n_addrs) {
+ case 1:
+ case 2:
+ case 3:
+ addr = dp->addrs[0].address;
+ break;
+ case 4:
+ addr = dp->addrs[1].address;
+ break;
+ default:
+ printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
+ for (i = 0; i < dp->n_addrs; i++)
+ printk(" %08x-%08x", dp->addrs[i].address,
+ dp->addrs[i].address+dp->addrs[i].size-1);
+ if (dp->n_addrs)
+ printk("\n");
return;
- }
- memset(info, 0, sizeof(struct fb_info_aty));
+ }
+
+ info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+ if (!info) {
+ printk("atyfb_of_init: can't alloc fb_info_aty\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_aty));
- 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,
+ info->ati_regbase_phys = 0x7ff000+addr;
+ info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
0x1000);
- info->ati_regbase_phys += 0xc00;
- info->ati_regbase += 0xc00;
-
- /* enable memory-space accesses using config-space command register */
- if (pci_device_loc(dp, &bus, &devfn) == 0) {
- pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
- if (cmd != 0xffff) {
- cmd |= PCI_COMMAND_MEMORY;
- pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
- }
+ info->ati_regbase_phys += 0xc00;
+ info->ati_regbase += 0xc00;
+
+ /* enable memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ if (cmd != 0xffff) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
}
+ }
#ifdef __BIG_ENDIAN
- /* Use the big-endian aperture */
- addr += 0x800000;
+ /* Use the big-endian aperture */
+ addr += 0x800000;
#endif
- /* Map in frame buffer */
- info->frame_buffer_phys = addr;
- info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+ /* Map in frame buffer */
+ info->frame_buffer_phys = addr;
+ info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
- if (!aty_init(info, dp->full_name)) {
- kfree(info);
- return;
- }
+ if (!aty_init(info, dp->full_name)) {
+ kfree(info);
+ return;
+ }
#ifdef CONFIG_FB_COMPAT_XPMAC
- if (!console_fb_info)
- console_fb_info = &info->fb_info;
+ if (!console_fb_info)
+ console_fb_info = &info->fb_info;
#endif /* CONFIG_FB_COMPAT_XPMAC */
- }
}
#endif /* CONFIG_FB_OF */
curblink = 0;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
- }
+ } else if (!strncmp(this_opt, "vram:", 5))
+ default_vram = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "pll:", 4))
+ default_pll = simple_strtoul(this_opt+4, NULL, 0);
+ else if (!strncmp(this_opt, "mclk:", 5))
+ default_mclk = simple_strtoul(this_opt+5, NULL, 0);
#if defined(CONFIG_PPC)
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
{ 0x0b, 0x11 },
{ 0x10, 0x0c },
{ 0x11, 0xe0 },
- { 0x12, 0x40 },
+ /* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */
{ 0x20, 0x63 },
{ 0x21, 0x68 },
{ 0x22, 0x19 },
int btype;
int smallboard;
unsigned char SFR; /* Shadow of special function register */
+
+ unsigned long fbmem_phys;
+ unsigned long fbregs_phys;
struct clgenfb_par currentmode;
union {
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, clgenfb_name);
- fix->smem_start = (char*)_info->fbmem;
+ fix->smem_start = (char*)_info->fbmem_phys;
/* monochrome: only 1 memory plane */
/* 8 bit and above: Use whole memory area */
fix->ypanstep = 1;
fix->ywrapstep = 0;
fix->line_length = _par->line_length;
- fix->mmio_start = (char *)_info->regs;
+ fix->mmio_start = (char *)_info->fbregs_phys;
fix->mmio_len = 0x10000;
fix->accel = FB_ACCEL_NONE;
/* use highest possible virtual resolution */
if (_par->var.xres_virtual == -1 &&
- _par->var.xres_virtual == -1)
+ _par->var.yres_virtual == -1)
{
printk("clgen: using maximum available virtual resolution\n");
for (i=0; modes[i].xres != -1; i++)
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->fbregs_phys = board_addr + 0x600000;
- fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216,
+ fb_info->fbmem_phys = board_addr + 16777216;
+ fb_info->fbmem = kernel_map(fb_info->fbmem_phys, 16777216,
KERNELMAP_NOCACHE_SER, NULL);
DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
}
cd2 = zorro_get_board(key2);
printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
+ fb_info->fbmem_phys = board_addr;
if (board_addr > 0x01000000)
fb_info->fbmem = kernel_map(board_addr, board_size,
KERNELMAP_NOCACHE_SER, NULL);
/* set address for REG area of board */
fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr);
+ fb_info->fbregs_phys = (unsigned long) 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);
static int currcon = 0;
static int switching = 0;
+static char fontname[40] __initdata = { 0 };
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
struct fb_par_control {
int vmode, cmode;
* Exported functions
*/
void control_init(void);
+#ifdef CONFIG_FB_OF
void control_of_init(struct device_node *dp);
+#endif
+void controlfb_setup(char *options, int *ints);
static int control_open(struct fb_info *info, int user);
static int control_release(struct fb_info *info, int user);
info->node = -1; /* ??? danj */
info->fbops = &controlfb_ops;
info->disp = &p->disp;
- info->fontname[0] = 0;
+ strcpy(info->fontname, fontname);
info->changevar = NULL;
info->switch_con = &controlfb_switch;
info->updatevar = &controlfb_updatevar;
}
}
-#if 0
+/* Parse user speficied options (`video=controlfb:') */
__initfunc(void controlfb_setup(char *options, int *ints))
{
- /* Parse user speficied options (`video=controlfb:') */
- FUNCID;
+ char *this_opt;
+
+ 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 (!strncmp(this_opt, "vmode:", 6)) {
+ 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)) {
+ int depth = simple_strtoul(this_opt+6, NULL, 0);
+ switch (depth) {
+ case 8:
+ default_cmode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_cmode = CMODE_32;
+ break;
+ }
+ }
+ }
}
+#if 0
static int controlfb_pan_display(struct fb_var_screeninfo *var,
struct controlfb_par *par,
const struct fb_info *fb_info)
return 0;
}
-
#endif
--- /dev/null
+/*
+ * CybervisionPPC (TVP4020) low level driver for the frame buffer device
+ * ^^^^^^^^^
+ * literally ;)
+ *
+ * Copyright (c) 1998 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) (v124)
+ * --------------------------------------------------------------------------
+ * based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven
+ * --------------------------------------------------------------------------
+ * TODO h/w parameters detect/modify, 8-bit CLUT, acceleration
+ * --------------------------------------------------------------------------
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+
+#define ISDIGIT(a) ((a)>='0' && (a)<='9')
+
+#undef CVPPCFB_MASTER_DEBUG
+#ifdef CVPPCFB_MASTER_DEBUG
+#define FBEGIN if (usr_startup.debug>1)\
+ printk(__FUNCTION__ " {\n")
+#define FEND if (usr_startup.debug>1)\
+ printk("} /* " __FUNCTION__ " */\n")
+#define DPRINTK(a,b...) if (usr_startup.debug)\
+ printk("%s: " a, __FUNCTION__ , ## b)
+#else
+#define FBEGIN
+#define FEND
+#define DPRINTK(a,b...)
+#endif
+
+static const char cvppcfb_name[16]="CybervisionPPC";
+
+struct cvppcfb_startup { /* startup options */
+ char font[40];
+ u32 xres;
+ u32 yres;
+ u32 bpp;
+ unsigned long debug;
+ unsigned long YANW; /* You Are Not Welcome */
+ struct fb_monspecs monitor;
+};
+static struct cvppcfb_startup usr_startup = {
+ "\0", 640, 480, 16, 0, 1, { 31, 32, 58, 62, 0 } };
+
+#define CVPPC_BASE 0xe0000000
+#define CVPPC_SIZE 0x00800000
+static char* video_base; /* virtual address of board video memory */
+static unsigned long video_phys;/* physical address of board video memory */
+static u32 video_size; /* size of board video memory */
+
+struct cvppcfb_par { /* board parameters (sort of) */
+ u32 xres;
+ u32 yres;
+ u32 vxres;
+ u32 vyres;
+ u32 vxoff;
+ u32 vyoff;
+ u32 bpp;
+ u32 clock;
+ u32 sflags;
+ u32 left;
+ u32 right;
+ u32 top;
+ u32 bottom;
+ u32 hsynclen;
+ u32 vsynclen;
+};
+
+struct cvppcfb_info {
+ struct fb_info_gen gen;
+ struct cvppcfb_par current_par;
+ int current_par_valid;
+ struct display disp;
+ struct {
+ u8 transp;
+ u8 red;
+ u8 green;
+ u8 blue;
+ } palette[256];
+ union {
+#ifdef FBCON_HAS_CFB16
+ u16 cmap16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cmap32[16];
+#endif
+ } cmap;
+};
+static struct cvppcfb_info fb_info;
+
+/*
+ * declaration of hw switch functions
+ */
+static void cvppcfb_detect(void);
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+ const void* par, struct fb_info_gen* info);
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+ void* par, struct fb_info_gen* info);
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+ const void* par, struct fb_info_gen* info);
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info);
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info);
+static int cvppcfb_getcolreg(unsigned regno,
+ unsigned* red, unsigned* green, unsigned* blue,
+ unsigned* transp, struct fb_info* info);
+static int cvppcfb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info* info);
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+ struct fb_info_gen* info);
+
+static struct fbgen_hwswitch cvppcfb_hwswitch={
+ cvppcfb_detect, cvppcfb_encode_fix, cvppcfb_decode_var,
+ cvppcfb_encode_var, cvppcfb_get_par, cvppcfb_set_par,
+ cvppcfb_getcolreg, cvppcfb_setcolreg, NULL /* pan_display() */,
+ NULL /* blank() */, cvppcfb_dispsw
+};
+
+/*
+ * declaration of ops switch functions
+ */
+static int cvppcfb_open(struct fb_info* info, int user);
+static int cvppcfb_release(struct fb_info* info, int user);
+
+static struct fb_ops cvppcfb_ops={
+ cvppcfb_open, cvppcfb_release, fbgen_get_fix, fbgen_get_var,
+ fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display,
+ fbgen_ioctl, NULL /* fb_mmap() */
+};
+
+/*
+ * the actual definition of the above mentioned functions follows
+ */
+
+/*
+ * private functions
+ */
+
+static void cvppcfb_set_modename(struct cvppcfb_info* info,
+ struct cvppcfb_startup* s) {
+
+ strcpy(info->gen.info.modename, cvppcfb_name);
+}
+
+static void cvppcfb_decode_opt(struct cvppcfb_startup* s, void* par,
+ struct cvppcfb_info* info) {
+ struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+
+ memset(p, 0, sizeof(struct cvppcfb_par));
+ p->xres=p->vxres=(s->xres+7)&~7;
+ p->yres=p->vyres=s->yres;
+ p->bpp=(s->bpp+7)&~7;
+ if (p->bpp==24)
+ p->bpp=32;
+ if (p->bpp<32)
+ p->clock=6666;
+ else
+ p->clock=10000;
+}
+
+static void cvppcfb_encode_mcap(char* options, struct fb_monspecs* mcap) {
+ char* next;
+ int i=0;
+
+ while (i<4 && options) {
+ if ((next=strchr(options, ';')))
+ *(next++)='\0';
+ switch (i++) {
+ case 0: /* vmin */
+ mcap->vfmin=(__u16 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ case 1: /* vmax */
+ mcap->vfmax=(__u16 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ case 2: /* hmin */
+ mcap->hfmin=(__u32 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ case 3: /* hmax */
+ mcap->hfmax=(__u32 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ }
+ options=next;
+ }
+}
+
+static void cvppcfb_encode_mode(char* options, struct cvppcfb_startup* s) {
+ char* next;
+ int i=0;
+
+ while (i<3 && options) {
+ if ((next=strchr(options, ';')))
+ *(next++)='\0';
+ switch (i++) {
+ case 0:
+ s->xres=(u32 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ case 1:
+ s->yres=(u32 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ case 2:
+ s->bpp=(u32 )
+ simple_strtoul(options, NULL, 0);
+ break;
+ }
+ options=next;
+ }
+}
+
+/*
+ * protected functions
+ */
+
+static void cvppcfb_detect(void) {
+
+ FBEGIN;
+ FEND;
+}
+
+static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix,
+ const void* par, struct fb_info_gen* info) {
+
+ FBEGIN;
+ strcpy(fix->id, cvppcfb_name);
+ fix->smem_start=(char* )video_phys;
+ fix->smem_len=(__u32 )video_size;
+ fix->type=FB_TYPE_PACKED_PIXELS;
+ if (((struct cvppcfb_par* )par)->bpp==8)
+ fix->visual=FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual=FB_VISUAL_TRUECOLOR;
+ fix->xpanstep=fix->ypanstep=fix->ywrapstep=0;
+ fix->line_length=0; /* computed by fbcon */
+ fix->mmio_start=NULL;
+ fix->mmio_len=0;
+ fix->accel=FB_ACCEL_NONE;
+ FEND;
+ return 0;
+}
+
+static int cvppcfb_decode_var(const struct fb_var_screeninfo* var,
+ void* par, struct fb_info_gen* info) {
+ struct cvppcfb_par p;
+
+ FBEGIN;
+ memset(&p, 0, sizeof(struct cvppcfb_par));
+ p.bpp=(var->bits_per_pixel+7)&~7;
+ if (p.bpp==24)
+ p.bpp=32;
+ if (p.bpp>32) {
+ DPRINTK("depth too big (%lu)\n", p.bpp);
+ return -EINVAL;
+ }
+ p.xres=(var->xres+7)&~7;
+ p.yres=var->yres;
+ if (p.xres<320 || p.yres<200 || p.xres>2048 || p.yres>2048) {
+ DPRINTK("bad resolution (%lux%lu)\n", p.xres, p.yres);
+ return -EINVAL;
+ }
+ p.vxres=(var->xres_virtual+7)&~7;
+ p.vxoff=(var->xoffset+7)&~7;
+ p.vyres=var->yres_virtual;
+ p.vyoff=var->yoffset;
+ if (p.vxres<p.xres+p.vxoff)
+ p.vxres=p.xres+p.vxoff;
+ if (p.vyres<p.yres+p.vyoff)
+ p.vyres=p.yres+p.vyoff;
+ if (p.vxres*p.vyres*p.bpp/8>video_size) {
+ DPRINTK("no memory for screen (%lux%lux%lu)\n",
+ p.vxres, p.vyres, p.bpp);
+ return -EINVAL;
+ }
+ p.sflags=var->sync&(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT);
+ p.clock=var->pixclock;
+ if (p.clock<6666) {
+ DPRINTK("pixclock too fast (%lu)\n", p.clock);
+ return -EINVAL;
+ }
+ p.left=var->left_margin;
+ p.top=var->upper_margin;
+ p.right=var->right_margin;
+ p.bottom=var->lower_margin;
+ p.hsynclen=var->hsync_len;
+ p.vsynclen=var->vsync_len;
+ *((struct cvppcfb_par* )par)=p;
+ FEND;
+ return 0;
+}
+
+static int cvppcfb_encode_var(struct fb_var_screeninfo* var,
+ const void* par, struct fb_info_gen* info) {
+ struct cvppcfb_par* p=(struct cvppcfb_par* )par;
+ struct fb_var_screeninfo v;
+
+ FBEGIN;
+ memset(&v, 0, sizeof(struct fb_var_screeninfo));
+ v.xres=p->xres;
+ v.yres=p->yres;
+ v.xres_virtual=p->vxres;
+ v.yres_virtual=p->vyres;
+ v.xoffset=p->vxoff;
+ v.yoffset=p->vyoff;
+ v.bits_per_pixel=p->bpp;
+ switch (p->bpp) {
+ case 16:
+ v.red.offset=11;
+ v.red.length=5;
+ v.green.offset=5;
+ v.green.length=6;
+ v.blue.length=5;
+ break;
+ case 32:
+ v.transp.offset=24;
+ v.red.offset=16;
+ v.green.offset=8;
+ v.transp.length=8;
+ /* fallback */
+ case 8:
+ v.red.length=v.green.length=v.blue.length=8;
+ break;
+ }
+ v.activate=FB_ACTIVATE_NOW;
+ v.height=v.width=-1;
+ v.pixclock=p->clock;
+ v.left_margin=p->left;
+ v.right_margin=p->right;
+ v.upper_margin=p->top;
+ v.lower_margin=p->bottom;
+ v.hsync_len=p->hsynclen;
+ v.vsync_len=p->vsynclen;
+ v.sync=p->sflags;
+ v.vmode=FB_VMODE_NONINTERLACED;
+ *var=v;
+ FEND;
+ return 0;
+}
+
+static void cvppcfb_get_par(void* par, struct fb_info_gen* info) {
+ struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+ FBEGIN;
+ if (i->current_par_valid)
+ *((struct cvppcfb_par* )par)=i->current_par;
+ else
+ cvppcfb_decode_opt(&usr_startup, par, i);
+ FEND;
+}
+
+static void cvppcfb_set_par(const void* par, struct fb_info_gen* info) {
+ struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+ FBEGIN;
+ i->current_par=*((struct cvppcfb_par* )par);
+ i->current_par_valid=1;
+ FEND;
+}
+
+static int cvppcfb_getcolreg(unsigned regno,
+ unsigned* red, unsigned* green, unsigned* blue,
+ unsigned* transp, struct fb_info* info) {
+ struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+ if (regno<256) {
+ *red=i->palette[regno].red<<8|i->palette[regno].red;
+ *green=i->palette[regno].green<<8|i->palette[regno].green;
+ *blue=i->palette[regno].blue<<8|i->palette[regno].blue;
+ *transp=i->palette[regno].transp<<8|i->palette[regno].transp;
+ }
+ return regno>255;
+}
+
+static int cvppcfb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info* info) {
+ struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+
+ if (regno<16) {
+ switch (i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ DPRINTK("8 bit depth not supported yet.\n");
+ return 1;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ i->cmap.cmap16[regno]=
+ ((u32 )red & 0xf800) |
+ (((u32 )green & 0xfc00)>>5) |
+ (((u32 )blue & 0xf800)>>11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ i->cmap.cmap32[regno]=
+ (((u32 )transp & 0xff00) << 16) |
+ (((u32 )red & 0xff00) << 8) |
+ (((u32 )green & 0xff00)) |
+ (((u32 )blue & 0xff00) >> 8);
+ break;
+#endif
+ }
+ }
+ if (regno<256) {
+ i->palette[regno].red=red >> 8;
+ i->palette[regno].green=green >> 8;
+ i->palette[regno].blue=blue >> 8;
+ i->palette[regno].transp=transp >> 8;
+ }
+ return regno>255;
+}
+
+static void cvppcfb_dispsw(const void* par, struct display* disp,
+ struct fb_info_gen* info) {
+ struct cvppcfb_info* i=(struct cvppcfb_info* )info;
+ unsigned long flags;
+
+ FBEGIN;
+ save_flags(flags);
+ cli();
+ switch (((struct cvppcfb_par* )par)->bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ disp->dispsw=&fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ disp->dispsw=&fbcon_cfb16;
+ disp->dispsw_data=i->cmap.cmap16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ disp->dispsw=&fbcon_cfb32;
+ disp->dispsw_data=i->cmap.cmap32;
+ break;
+#endif
+ default:
+ disp->dispsw=&fbcon_dummy;
+ break;
+ }
+ restore_flags(flags);
+ FEND;
+}
+
+static int cvppcfb_open(struct fb_info* info, int user) {
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int cvppcfb_release(struct fb_info* info, int user) {
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * public functions
+ */
+
+void cvppcfb_cleanup(struct fb_info* info) {
+
+ unregister_framebuffer(info);
+}
+
+__initfunc(void cvppcfb_init(void)) {
+
+ FBEGIN;
+#ifdef CVPPCFB_MASTER_DEBUG
+ printk("cvppcfb_init():\n");
+ printk(" resolution %ldx%ldx%ld\n", usr_startup.xres,
+ usr_startup.yres, usr_startup.bpp);
+ printk(" debug: %ld, YANW: %ld\n", usr_startup.debug,
+ usr_startup.YANW);
+ printk(" monitorcap: %ld,%ld,%ld,%ld\n",
+ usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+ usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+ if (usr_startup.YANW) /* cannot probe yet */
+ return;
+ memset(&fb_info, 0, sizeof(struct cvppcfb_info));
+ video_size=CVPPC_SIZE;
+ video_phys=CVPPC_BASE;
+#ifdef CONFIG_APUS
+ video_base=(char* )
+ kernel_map(video_phys, video_size, KERNELMAP_NOCACHE_SER, NULL);
+#else
+ video_base=ioremap(video_phys, video_size);
+#endif
+ DPRINTK("video_phys=%08lx, video_base=%08lx\n", video_phys, video_base);
+ DPRINTK("phys_to_virt(video_phys)=%08lx\n", phys_to_virt(video_phys));
+ DPRINTK("virt_to_phys(video_base)=%08lx\n", virt_to_phys(video_base));
+ fb_info.disp.scrollmode=SCROLL_YREDRAW;
+ fb_info.gen.parsize=sizeof(struct cvppcfb_par);
+ fb_info.gen.fbhw=&cvppcfb_hwswitch;
+ cvppcfb_set_modename(&fb_info, &usr_startup);
+ fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
+ fb_info.gen.info.fbops=&cvppcfb_ops;
+ fb_info.gen.info.monspecs=usr_startup.monitor;
+ fb_info.gen.info.disp=&fb_info.disp;
+ strcpy(fb_info.gen.info.fontname, usr_startup.font);
+ fb_info.gen.info.switch_con=&fbgen_switch;
+ fb_info.gen.info.updatevar=&fbgen_update_var;
+ fb_info.gen.info.blank=&fbgen_blank;
+ fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
+ if (fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen)<0) {
+ printk( "cvppcfb: bad startup configuration: "
+ "unable to register.\n");
+ return;
+ }
+ fbgen_set_disp(-1, &fb_info.gen);
+ fbgen_install_cmap(0, &fb_info.gen);
+ if (register_framebuffer(&fb_info.gen.info)<0) {
+ printk("cvppcfb: unable to register.\n");
+ return;
+ }
+ printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename,
+ (unsigned long )(video_size>>10));
+ MOD_INC_USE_COUNT;
+ FEND;
+}
+
+__initfunc(void cvppcfb_setup(char* options, int* ints)) {
+ char* next;
+
+ usr_startup.YANW=0;
+ DPRINTK("options: '%s'\n", options);
+ while (options) {
+ if ((next=strchr(options, ',')))
+ *(next++)='\0';
+ if (!strncmp(options, "monitorcap:", 11))
+ cvppcfb_encode_mcap(options+11, &usr_startup.monitor);
+ else if (!strncmp(options, "debug:", 6)) {
+ if (ISDIGIT(options[6]))
+ usr_startup.debug=options[6]-'0';
+ else
+ usr_startup.debug=1;
+ }
+ else if (!strncmp(options, "mode:", 5))
+ cvppcfb_encode_mode(options+5, &usr_startup);
+ else if (!strncmp(options, "font:", 5))
+ strcpy(usr_startup.font, options+5);
+ else
+ DPRINTK("unrecognized option '%s'\n", options);
+ options=next;
+ }
+#ifdef CVPPCFB_MASTER_DEBUG
+ printk("cvppcfb_setup():\n");
+ printk(" resolution %ldx%ldx%ld\n", usr_startup.xres,
+ usr_startup.yres, usr_startup.bpp);
+ printk(" debug: %ld, YANW: %ld\n", usr_startup.debug,
+ usr_startup.YANW);
+ printk(" monitorcap: %ld,%ld,%ld,%ld\n",
+ usr_startup.monitor.vfmin, usr_startup.monitor.vfmax,
+ usr_startup.monitor.hfmin, usr_startup.monitor.hfmax);
+#endif
+}
+
+/*
+ * modularization
+ */
+
+#ifdef MODULE
+int init_module(void) {
+
+ cvppcfb_init();
+}
+
+void cleanup_module(void) {
+
+ cvppcfb_cleanup();
+}
+#endif /* MODULE */
+
static unsigned long CyberMem;
static unsigned long CyberSize;
static volatile char *CyberRegs;
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
/*
0, 0, -1, -1, FB_ACCELF_TEXT, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
+ }, {
+ "1024x768-16", { /* Cybervision 16 bpp */
+ 1024, 768, 1024, 768, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
}
};
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, cyberfb_name);
- fix->smem_start = (char *)CyberMem;
+ fix->smem_start = (char*) CyberMem_phys;
fix->smem_len = CyberSize;
- fix->mmio_start = (char *)CyberRegs;
+ fix->mmio_start = (char*) CyberRegs_phys;
fix->mmio_len = 0x10000;
fix->type = FB_TYPE_PACKED_PIXELS;
cyberfb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
- display->screen_base = fix.smem_start;
+ display->screen_base = (char*) CyberMem;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
board_addr = (unsigned long)cd->cd_BoardAddr;
/* This includes the video memory as well as the S3 register set */
- CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
+ CyberMem_phys = board_addr + 0x01400000;
+ CyberRegs_phys = CyberMem_phys + 0x00c00000;
+ CyberMem = kernel_map (CyberMem_phys, 0x01000000,
KERNELMAP_NOCACHE_SER, NULL);
CyberRegs = (char*) (CyberMem + 0x00c00000);
}
}
+void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p,
+ int bottom_only)
+{
+ u32 offset;
+ int bytes;
+ int lines;
+ u32 cval;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+ bytes = p->next_line;
+ if (fontheightlog(p)) {
+ lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+ offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+ } else {
+ lines = p->var.yres - conp->vc_rows * fontheight(p);
+ offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+ }
+ if (lines) {
+ cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
+ memset_even_2p(p->screen_base+offset, lines * bytes, cval);
+ }
+}
+
/*
* `switch' for the low level operations
struct display_switch fbcon_iplan2p2 = {
fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear,
fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc, NULL,
- NULL, NULL, FONTWIDTH(8)
+ NULL, fbcon_iplan2p2_clear_margins, FONTWIDTH(8)
};
EXPORT_SYMBOL(fbcon_iplan2p2_putc);
EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
EXPORT_SYMBOL(fbcon_iplan2p2_revc);
+EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins);
}
}
+void fbcon_iplan2p4_clear_margins(struct vc_data *conp, struct display *p,
+ int bottom_only)
+{
+ u32 offset;
+ int bytes;
+ int lines;
+ u32 cval1, cval2;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+ bytes = p->next_line;
+ if (fontheightlog(p)) {
+ lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+ offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+ } else {
+ lines = p->var.yres - conp->vc_rows * fontheight(p);
+ offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+ }
+ if (lines) {
+ expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
+ memset_even_4p(p->screen_base+offset, lines * bytes, cval1, cval2);
+ }
+}
+
/*
* `switch' for the low level operations
struct display_switch fbcon_iplan2p4 = {
fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear,
fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc, NULL,
- NULL, NULL, FONTWIDTH(8)
+ NULL, fbcon_iplan2p4_clear_margins, FONTWIDTH(8)
};
EXPORT_SYMBOL(fbcon_iplan2p4_putc);
EXPORT_SYMBOL(fbcon_iplan2p4_putcs);
EXPORT_SYMBOL(fbcon_iplan2p4_revc);
+EXPORT_SYMBOL(fbcon_iplan2p4_clear_margins);
}
}
+void fbcon_iplan2p8_clear_margins(struct vc_data *conp, struct display *p,
+ int bottom_only)
+{
+ u32 offset;
+ int bytes;
+ int lines;
+ u32 cval1, cval2, cval3, cval4;
+
+/* No need to handle right margin, cannot occur with fontwidth == 8 */
+
+ bytes = p->next_line;
+ if (fontheightlog(p)) {
+ lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
+ offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
+ } else {
+ lines = p->var.yres - conp->vc_rows * fontheight(p);
+ offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
+ }
+ if (lines) {
+ expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4);
+ memset_even_8p(p->screen_base+offset, lines * bytes,
+ cval1, cval2, cval3, cval4);
+ }
+}
+
/*
* `switch' for the low level operations
struct display_switch fbcon_iplan2p8 = {
fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear,
fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc, NULL,
- NULL, NULL, FONTWIDTH(8)
+ NULL, fbcon_iplan2p8_clear_margins, FONTWIDTH(8)
};
EXPORT_SYMBOL(fbcon_iplan2p8_putc);
EXPORT_SYMBOL(fbcon_iplan2p8_putcs);
EXPORT_SYMBOL(fbcon_iplan2p8_revc);
+EXPORT_SYMBOL(fbcon_iplan2p8_clear_margins);
{
u8 *dest;
u_int rows;
- int inverse = conp ? attr_reverse(p,conp->vc_attr) : 0;
+ int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
*dest = ~*dest;
}
+void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
+ int bottom_only)
+{
+ u8 *dest;
+ int height, bottom;
+ int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+ /* XXX Need to handle right margin? */
+
+ height = p->var.yres - conp->vc_rows * fontheight(p);
+ if (!height)
+ return;
+ bottom = conp->vc_rows + p->yscroll;
+ if (bottom >= p->vrows)
+ bottom -= p->vrows;
+ dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+ if (inverse)
+ mymemset(dest, height * p->next_line);
+ else
+ mymemclear(dest, height * p->next_line);
+}
+
/*
* `switch' for the low level operations
struct display_switch fbcon_mfb = {
fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc,
- fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, fbcon_mfb_clear_margins,
+ FONTWIDTH(8)
};
EXPORT_SYMBOL(fbcon_mfb_putc);
EXPORT_SYMBOL(fbcon_mfb_putcs);
EXPORT_SYMBOL(fbcon_mfb_revc);
+EXPORT_SYMBOL(fbcon_mfb_clear_margins);
#include <linux/slab.h>
#include <asm/uaccess.h>
+#include <asm/io.h>
static int currcon = 0;
memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
fbhw->encode_fix(&fix, &par, info);
- display->screen_base = fix.smem_start;
+ display->screen_base = phys_to_virt((unsigned long)fix.smem_start);
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
#include <linux/kmod.h>
#endif
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
#include <asm/setup.h>
#endif
#ifdef __powerpc__
extern void macfb_setup(char *options, int *ints);
extern void cyberfb_init(void);
extern void cyberfb_setup(char *options, int *ints);
+extern void cvppcfb_init(void);
+extern void cvppcfb_setup(char *options, int *ints);
extern void retz3fb_init(void);
extern void retz3fb_setup(char *options, int *ints);
extern void clgenfb_init(void);
extern void igafb_init(void);
extern void igafb_setup(char *options, int *ints);
extern void imsttfb_init(void);
+extern void imsttfb_setup(char *options, int *ints);
extern void dnfb_init(void);
extern void tgafb_init(void);
extern void virgefb_init(void);
extern void s3triofb_setup(char *options, int *ints);
extern void vesafb_init(void);
extern void vesafb_setup(char *options, int *ints);
+extern void matroxfb_init(void);
+extern void matroxfb_setup(char* options, int *ints);
extern void hpfb_init(void);
extern void hpfb_setup(char *options, int *ints);
extern void sbusfb_init(void);
#ifdef CONFIG_FB_CYBER
{ "cyber", cyberfb_init, cyberfb_setup },
#endif
+#ifdef CONFIG_FB_CVPPC
+ { "cvppcfb", cvppcfb_init, cvppcfb_setup },
+#endif
#ifdef CONFIG_FB_CLGEN
{ "clgen", clgenfb_init, clgenfb_setup },
#endif
#ifdef CONFIG_FB_OF
{ "offb", offb_init, offb_setup },
#endif
+#ifdef CONFIG_FB_SBUS
+ { "sbus", sbusfb_init, sbusfb_setup },
+#endif
#ifdef CONFIG_FB_ATY
{ "atyfb", atyfb_init, atyfb_setup },
#endif
{ "igafb", igafb_init, igafb_setup },
#endif
#ifdef CONFIG_FB_IMSTT
- { "imsttfb", imsttfb_init, NULL },
+ { "imsttfb", imsttfb_init, imsttfb_setup },
#endif
#ifdef CONFIG_APOLLO
{ "apollo", dnfb_init, NULL },
#ifdef CONFIG_FB_VESA
{ "vesa", vesafb_init, vesafb_setup },
#endif
+#ifdef CONFIG_FB_MATROX
+ { "matrox", matroxfb_init, matroxfb_setup },
+#endif
#ifdef CONFIG_FB_HP300
{ "hpfb", hpfb_init, hpfb_setup },
#endif
-#ifdef CONFIG_FB_SBUS
- { "sbus", sbusfb_init, sbusfb_setup },
-#endif
#ifdef CONFIG_FB_VALKYRIE
{ "valkyriefb", valkyriefb_init, valkyriefb_setup },
#endif
}
+static int set_all_vcs(int fbidx, struct fb_ops *fb,
+ struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int unit, err;
+
+ var->activate |= FB_ACTIVATE_TEST;
+ err = fb->fb_set_var(var, PROC_CONSOLE(), info);
+ var->activate &= ~FB_ACTIVATE_TEST;
+ if (err)
+ return err;
+ info->disp->var = *var;
+ for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+ if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
+ fb->fb_set_var(var, unit, info);
+ return 0;
+}
+
static void set_con2fb_map(int unit, int newidx)
{
int oldidx = con2fb_map[unit];
case FBIOPUT_VSCREENINFO:
if (copy_from_user(&var, (void *) arg, sizeof(var)))
return -EFAULT;
- if ((i = fb->fb_set_var(&var, PROC_CONSOLE(), info)))
+ i = var.activate & FB_ACTIVATE_ALL
+ ? set_all_vcs(fbidx, fb, &var, info)
+ : fb->fb_set_var(&var, PROC_CONSOLE(), info);
+ if (i)
return i;
if (copy_to_user((void *) arg, &var, sizeof(var)))
return -EFAULT;
for(i=0; i<num_fonts; i++) {
f = fbcon_fonts[i];
c = f->pref;
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
#ifdef CONFIG_FONT_PEARL_8x8
if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
c = 100;
CLKCTL = 0x02, /* (0x01) Miscellaneous Clock Control */
SYNCCTL = 0x03, /* (0x00) Sync Control */
HSYNCPOS = 0x04, /* (0x00) Horizontal Sync Position */
- PWRMNGMT = 0x05, /* (0x00) Power Management [multiples of 4 unblack screen] */
- DACOP = 0x06, /* (0x02) DAC Operation [0-3 coloured, 4-7 green, odd light, even dark] */
+ PWRMNGMT = 0x05, /* (0x00) Power Management */
+ DACOP = 0x06, /* (0x02) DAC Operation */
PALETCTL = 0x07, /* (0x00) Palette Control */
SYSCLKCTL = 0x08, /* (0x01) System Clock Control */
PIXFMT = 0x0a, /* () Pixel Format [bpp >> 3 + 2] */
BPP8 = 0x0b, /* () 8 Bits/Pixel Control */
- BPP16 = 0x0c, /* () 16 Bits/Pixel Control [15 or 1 for 555] */
+ BPP16 = 0x0c, /* () 16 Bits/Pixel Control [bit 1=1 for 565] */
BPP24 = 0x0d, /* () 24 Bits/Pixel Control */
BPP32 = 0x0e, /* () 32 Bits/Pixel Control */
- PIXCTL1 = 0x10, /* (0x05) Pixel PLL Control 1 [5-7 ok] */
- PIXCTL2 = 0x11, /* (0x00) Pixel PLL Control 2 [multiples of 20 ok] */
+ PIXCTL1 = 0x10, /* (0x05) Pixel PLL Control 1 */
+ PIXCTL2 = 0x11, /* (0x00) Pixel PLL Control 2 */
SYSCLKN = 0x15, /* () System Clock N (System PLL Reference Divider) */
SYSCLKM = 0x16, /* () System Clock M (System PLL VCO Divider) */
SYSCLKP = 0x17, /* () System Clock P */
* Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
* c is charge pump bias which depends on the VCO frequency
*/
- PIXCLKM = 0x20, /* () Pixel Clock M */
- PIXCLKN = 0x21, /* () Pixel Clock N */
- PIXCLKP = 0x22, /* () Pixel Clock P */
- PIXCLKC = 0x23, /* () Pixel Clock C */
- CURSCTL = 0x30, /* (0x00) Cursor Control [1=curs1, 2=curs2, 5=curs3] */
+ PIXM0 = 0x20, /* () Pixel M 0 */
+ PIXN0 = 0x21, /* () Pixel N 0 */
+ PIXP0 = 0x22, /* () Pixel P 0 */
+ PIXC0 = 0x23, /* () Pixel C 0 */
+ CURSCTL = 0x30, /* (0x00) Cursor Control */
CURSXLO = 0x31, /* () Cursor X position, low 8 bits */
CURSXHI = 0x32, /* () Cursor X position, high 8 bits */
CURSYLO = 0x33, /* () Cursor Y position, low 8 bits */
CURSYHI = 0x34, /* () Cursor Y position, high 8 bits */
- CURSHOTX = 0x35, /* () ??? [position relative to CURSX] */
- CURSHOTY = 0x36, /* () ??? [position relative to CURSY] */
- CURSACAEN = 0x37, /* () ??? [even=cursor on, odd=cursor off] */
+ CURSHOTX = 0x35, /* () Cursor Hot Spot X */
+ CURSHOTY = 0x36, /* () Cursor Hot Spot Y */
+ CURSACCTL = 0x37, /* () Advanced Cursor Control Enable */
+ CURSACATTR = 0x38, /* () Advanced Cursor Attribute */
CURS1R = 0x40, /* () Cursor 1 Red */
CURS1G = 0x41, /* () Cursor 1 Green */
CURS1B = 0x42, /* () Cursor 1 Blue */
__u8 addr, value;
};
-static struct initvalues ibm_initregs[] = {
+static struct initvalues ibm_initregs[] __initdata = {
{ CLKCTL, 0x21 },
{ SYNCCTL, 0x00 },
{ HSYNCPOS, 0x00 },
{ SYSCLKM, 0x4f },
{ SYSCLKP, 0x00 },
{ SYSCLKC, 0x00 },
- { CURSCTL, 0x00 },
+ { CURSCTL, 0x02 },
+ { CURSACCTL, 0x01 },
+ { CURSACATTR, 0xa8 },
+ { CURS1R, 0xff },
+ { CURS1G, 0xff },
+ { CURS1B, 0xff },
{ CURS2R, 0xff },
{ CURS2G, 0xff },
{ CURS2B, 0xff },
+ { CURS3R, 0xff },
+ { CURS3G, 0xff },
+ { CURS3B, 0xff },
{ BORDR, 0xff },
{ BORDG, 0xff },
{ BORDB, 0xff },
{ KEYCTL, 0x00 }
};
-static struct initvalues tvp_initregs[] = {
+static struct initvalues tvp_initregs[] __initdata = {
{ 0x6, 0x00 },
{ 0x7, 0xe4 },
{ 0xf, 0x06 },
};
struct imstt_cursor {
+ struct timer_list timer;
int enable;
int on;
int vbl_cnt;
int blink_rate;
- __u16 x, y;
- struct timer_list timer;
+ __u16 x, y, width, height;
};
struct fb_info_imstt {
} palette[256];
struct imstt_regvals init;
struct imstt_cursor cursor;
- __u8 *frame_buffer_phys, *frame_buffer;
- __u32 *dc_regs_phys, *dc_regs;
- __u8 *cmap_regs_phys, *cmap_regs;
+ volatile __u8 *frame_buffer_phys, *frame_buffer;
+ volatile __u32 *dc_regs_phys, *dc_regs;
+ volatile __u8 *cmap_regs_phys, *cmap_regs;
__u32 total_vram;
__u32 ramdac;
};
#define CURSOR_DRAW_DELAY 2
static int currcon = 0;
+static char fontname[40] __initdata = { 0 };
+static char curblink __initdata = 1;
+static char noaccel __initdata = 0;
+#if defined(CONFIG_PPC)
+static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
+#endif
static struct imstt_regvals tvp_reg_init_2 = {
512,
init->hes = hes;
init->heb = heb;
- init->hsb = init->heb + xres / 8;
+ init->hsb = init->heb + (xres >> 3);
init->ht = init->hsb + htp;
init->ves = 0x0003;
init->veb = veb;
__u8 pformat = (bpp >> 3) + 2;
p->cmap_regs[PIDXHI] = 0; eieio();
- p->cmap_regs[PIDXLO] = PIXCLKM; eieio();
+ p->cmap_regs[PIDXLO] = PIXM0; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_m; eieio();
- p->cmap_regs[PIDXLO] = PIXCLKN; eieio();
+ p->cmap_regs[PIDXLO] = PIXN0; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_n; eieio();
- p->cmap_regs[PIDXLO] = PIXCLKP; eieio();
+ p->cmap_regs[PIDXLO] = PIXP0; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_p; eieio();
- p->cmap_regs[PIDXLO] = PIXCLKC; eieio();
+ p->cmap_regs[PIDXLO] = PIXC0; eieio();
p->cmap_regs[PIDXDATA] = 0x02; eieio();
- p->cmap_regs[PIDXHI] = 0; eieio();
p->cmap_regs[PIDXLO] = PIXFMT; eieio();
p->cmap_regs[PIDXDATA] = pformat; eieio();
}
set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
{
struct imstt_regvals *init = &p->init;
- __u32 ctl, pitch, byteswap, scr;
+ __u32 ctl, pitch, byteswap, scr, line_pitch = init->pitch * (bpp >> 3);
if (p->ramdac == IBM)
set_imstt_regvals_ibm(p, bpp);
switch (bpp) {
case 8:
ctl = 0x17b1;
- pitch = init->pitch / 4;
- byteswap = 0x0;
+ pitch = init->pitch >> 2;
+ byteswap = 0x000;
break;
case 16:
ctl = 0x17b3;
- pitch = init->pitch / 2;
- byteswap = 0x1;
+ pitch = init->pitch >> 1;
+ byteswap = 0x100;
break;
case 24:
ctl = 0x17b9;
- pitch = init->pitch - (p->init.pitch / 4);
- byteswap = 0x2;
+ pitch = init->pitch - (p->init.pitch >> 2);
+ byteswap = 0x200;
break;
case 32:
ctl = 0x17b5;
pitch = init->pitch;
- byteswap = 0x3;
+ byteswap = 0x300;
break;
}
if (p->ramdac == TVP)
out_le32(&p->dc_regs[RRSC], 0x980);
out_le32(&p->dc_regs[RRCR], 0x11);
- out_le32(&p->dc_regs[SSR], 0);
if (p->ramdac == IBM) {
out_le32(&p->dc_regs[HRIR], 0x0100);
out_le32(&p->dc_regs[CMR], 0x00ff);
switch (p->total_vram) {
case 0x00200000:
- scr = 0x059d | (byteswap << 8);
+ scr = 0x059d | byteswap;
break;
case 0x00400000:
- pitch /= 2;
- scr = 0xd0dc | (byteswap << 8);
- break;
case 0x00800000:
pitch /= 2;
- scr = 0x150dd | (byteswap << 8);
+ scr = 0x150dd | byteswap;
break;
}
out_le32(&p->dc_regs[SCR], scr);
out_le32(&p->dc_regs[SPR], pitch);
+ out_le32(&p->dc_regs[SP], (line_pitch << 16) | line_pitch);
+ out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
out_le32(&p->dc_regs[STGCTL], ctl);
}
}
}
-#define set_555(_p) set_16(_p, 15)
-#define set_565(_p) set_16(_p, 0) /* 220, 224 is darker in X */
+#define set_555(_p) set_16(_p, 0x01)
+#define set_565(_p) set_16(_p, 0x03)
static void
imstt_set_cursor (struct fb_info_imstt *p, int on)
p->cmap_regs[PIDXHI] = 0;
if (!on) {
- p->cmap_regs[PIDXLO] = CURSCTL;
- p->cmap_regs[PIDXDATA] = 0x00;
+ p->cmap_regs[PIDXLO] = CURSCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0x00; eieio();
} else {
- p->cmap_regs[PIDXLO] = CURSXHI;
- p->cmap_regs[PIDXDATA] = c->x >> 8;
- p->cmap_regs[PIDXLO] = CURSXLO;
- p->cmap_regs[PIDXDATA] = c->x & 0xff;
- p->cmap_regs[PIDXLO] = CURSYHI;
- p->cmap_regs[PIDXDATA] = c->y >> 8;
- p->cmap_regs[PIDXLO] = CURSYLO;
- p->cmap_regs[PIDXDATA] = c->y & 0xff;
- p->cmap_regs[PIDXLO] = CURSCTL;
- p->cmap_regs[PIDXDATA] = 0x02;
+ p->cmap_regs[PIDXLO] = CURSXHI; eieio();
+ p->cmap_regs[PIDXDATA] = c->x >> 8; eieio();
+ p->cmap_regs[PIDXLO] = CURSXLO; eieio();
+ p->cmap_regs[PIDXDATA] = c->x & 0xff; eieio();
+ p->cmap_regs[PIDXLO] = CURSYHI; eieio();
+ p->cmap_regs[PIDXDATA] = c->y >> 8; eieio();
+ p->cmap_regs[PIDXLO] = CURSYLO; eieio();
+ p->cmap_regs[PIDXDATA] = c->y & 0xff; eieio();
+ p->cmap_regs[PIDXLO] = CURSCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0x02; eieio();
}
}
c->enable = 0;
if (c->on)
imstt_set_cursor(p, 0);
- c->x = x;
- c->y = y;
+ c->x = x - disp->var.xoffset;
+ c->y = y - disp->var.yoffset;
switch (mode) {
case CM_ERASE:
static int
imsttfb_set_font (struct display *disp, int width, int height)
{
+ struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
+ struct imstt_cursor *c = &p->cursor;
+ u_int x, y;
+
+ if (width > 32 || height > 32)
+ return -EINVAL;
+
+ c->height = height;
+ c->width = width;
+
+ p->cmap_regs[PIDXHI] = 1; eieio();
+ for (x = 0; x < 0x100; x++) {
+ p->cmap_regs[PIDXLO] = x; eieio();
+ p->cmap_regs[PIDXDATA] = 0x00; eieio();
+ }
+ p->cmap_regs[PIDXHI] = 1; eieio();
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width >> 2; x++) {
+ p->cmap_regs[PIDXLO] = x + y * 8; eieio();
+ p->cmap_regs[PIDXDATA] = 0xff; eieio();
+ }
+
return 1;
}
{
struct imstt_cursor *c = &p->cursor;
+ imsttfb_set_font(&p->disp, fontwidth(&p->disp), fontheight(&p->disp));
+
c->enable = 1;
c->on = 1;
- c->blink_rate = CURSOR_BLINK_RATE;
- c->vbl_cnt = CURSOR_DRAW_DELAY;
c->x = c->y = 0;
+ c->blink_rate = 0;
+ c->vbl_cnt = CURSOR_DRAW_DELAY;
- init_timer(&c->timer);
- c->timer.expires = jiffies + (HZ / 50);
- c->timer.data = (unsigned long)p;
- c->timer.function = imstt_cursor_timer_handler;
- add_timer(&c->timer);
+ if (curblink) {
+ c->blink_rate = CURSOR_BLINK_RATE;
+ init_timer(&c->timer);
+ c->timer.expires = jiffies + (HZ / 50);
+ c->timer.data = (unsigned long)p;
+ c->timer.function = imstt_cursor_timer_handler;
+ add_timer(&c->timer);
+ }
}
static void
imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
- __u32 cnt_reg, stat, xxx = 0;
- __u32 line_pitch = disp->var.xres * (disp->var.bits_per_pixel >> 3),
- rect_height = height,
- rect_width = width * (disp->var.bits_per_pixel >> 3),
- fb_offset_old = sy * line_pitch + (sx * (disp->var.bits_per_pixel >> 3)),
- fb_offset_new = dy * line_pitch + (dx * (disp->var.bits_per_pixel >> 3));
+ __u32 Bpp = disp->var.bits_per_pixel >> 3,
+ line_pitch = disp->line_length,
+ fb_offset_old, fb_offset_new;
- stat = in_le32(&p->dc_regs[SSTATUS]) & 0xff;
+ fb_offset_old = sy * line_pitch + sx * Bpp;
+ fb_offset_new = dy * line_pitch + dx * Bpp;
- cnt_reg = ((rect_height - 1) << 16) | (rect_width - 1);
- out_le32(&p->dc_regs[CNT], cnt_reg);
+ while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+ out_le32(&p->dc_regs[CNT], ((height - 1) << 16) | (width * Bpp - 1));
out_le32(&p->dc_regs[S1SA], fb_offset_old);
- out_le32(&p->dc_regs[DSA], fb_offset_old);
- out_le32(&p->dc_regs[SP], line_pitch);
- out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
- out_le32(&p->dc_regs[BLTCTL], 0x5);
-
- if (++stat == 0x20)
- stat = 0x10;
- while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
- eieio();
-
- cnt_reg = ((rect_height - 1) << 16) | (0xffff - (rect_width - 2));
- out_le32(&p->dc_regs[CNT], cnt_reg);
+ /* out_le32(&p->dc_regs[S2SA], fb_offset_new); */
out_le32(&p->dc_regs[DSA], fb_offset_new);
-#if 0
- out_le32(&p->dc_regs[S1SA], fb_offset_old);
- out_le32(&p->dc_regs[SP], line_pitch);
- out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
-#endif
- out_le32(&p->dc_regs[BLTCTL], 0x85);
-
- if (++stat == 0x20)
- stat = 0x10;
- while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
- eieio();
+ out_le32(&p->dc_regs[BLTCTL], 0xc0000005);
+ while (in_le32(&p->dc_regs[SSTATUS]) & 0x80);
+ while (in_le32(&p->dc_regs[SSTATUS]) & 0x40);
}
static void
imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
{
+ /* XXX .. */
+ if (sy < dy || (sy == dy && sx < dx)) {
+ switch (disp->var.bits_per_pixel) {
+ case 8: fbcon_cfb8_bmove(disp, sy, sx, dy, dx, height, width); break;
+ case 16: fbcon_cfb16_bmove(disp, sy, sx, dy, dx, height, width); break;
+ case 24: fbcon_cfb24_bmove(disp, sy, sx, dy, dx, height, width); break;
+ case 32: fbcon_cfb32_bmove(disp, sy, sx, dy, dx, height, width); break;
+ }
+ return;
+ }
+
sy *= fontheight(disp);
sx *= fontwidth(disp);
dy *= fontheight(disp);
p->palette[regno].blue = blue;
/* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
- if (p->ramdac == TVP && fb_display[currcon].var.green.length == 5 /* && bpp == 16 */) {
+ if (bpp == 16 && p->ramdac == TVP && fb_display[currcon].var.green.length == 5) {
p->cmap_regs[PADDRW] = regno << 3; eieio();
} else {
p->cmap_regs[PADDRW] = regno; eieio();
}
static void
-set_dispsw (struct display *disp, struct fb_info_imstt *p)
+set_disp (struct display *disp, struct fb_info_imstt *p)
{
u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
- disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_DIRECTCOLOR;
p->dispsw = fbcon_dummy;
disp->dispsw = &p->dispsw;
disp->dispsw_data = 0;
#endif
break;
case 16: /* RGB 555 */
- if (disp->var.red.offset != 11)
+ if (disp->var.green.length != 6)
disp->var.red.offset = 10;
disp->var.red.length = 5;
disp->var.green.offset = 5;
p->dispsw.cursor = imsttfb_cursor;
p->dispsw.set_font = imsttfb_set_font;
}
+
+ disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ disp->screen_base = (__u8 *)p->frame_buffer;
+ disp->visual = p->fix.visual;
+ disp->type = p->fix.type;
+ disp->type_aux = p->fix.type_aux;
+ disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
+ disp->can_soft_blank = 1;
+ disp->inverse = 0;
+ disp->ypanstep = 1;
+ disp->ywrapstep = 0;
+ if (accel) {
+ disp->scrollmode = SCROLL_YNOMOVE;
+ if (disp->var.yres == disp->var.yres_virtual) {
+ __u32 vram = (p->total_vram - (PAGE_SIZE << 2));
+ disp->var.yres_virtual = ((vram << 3) / disp->var.bits_per_pixel) / disp->var.xres_virtual;
+ if (disp->var.yres_virtual < disp->var.yres)
+ disp->var.yres_virtual = disp->var.yres;
+ }
+ } else {
+ disp->scrollmode = SCROLL_YREDRAW;
+ disp->var.yoffset = disp->var.xoffset = 0;
+ out_le32(&p->dc_regs[SSR], 0);
+ }
+
+ disp->var.activate = 0;
+ disp->var.red.msb_right = 0;
+ disp->var.green.msb_right = 0;
+ disp->var.blue.msb_right = 0;
+ disp->var.transp.msb_right = 0;
+ disp->var.height = -1;
+ disp->var.width = -1;
+ disp->var.vmode = FB_VMODE_NONINTERLACED;
+ disp->var.left_margin = disp->var.right_margin = 16;
+ disp->var.upper_margin = disp->var.lower_margin = 16;
+ disp->var.hsync_len = disp->var.vsync_len = 8;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ set_display_info(disp);
+#endif
}
static int
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
struct display *disp;
- u_int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
+ u_int oldbpp, oldxres, oldyres, oldgreenlen;
disp = &fb_display[con];
oldxres = disp->var.xres;
oldyres = disp->var.yres;
oldgreenlen = disp->var.green.length;
- oldaccel = disp->var.accel_flags;
-
- disp->var = *var;
-
- disp->var.activate = 0;
- disp->var.red.msb_right = 0;
- disp->var.green.msb_right = 0;
- disp->var.blue.msb_right = 0;
- disp->var.transp.msb_right = 0;
- disp->var.height = -1;
- disp->var.width = -1;
- disp->var.vmode = FB_VMODE_NONINTERLACED;
- disp->var.left_margin = disp->var.right_margin = 16;
- disp->var.upper_margin = disp->var.lower_margin = 16;
- disp->var.hsync_len = disp->var.vsync_len = 8;
- disp->screen_base = p->frame_buffer;
- disp->inverse = 0;
- disp->ypanstep = 1;
- disp->ywrapstep = 0;
- disp->scrollmode = SCROLL_YREDRAW;
+ disp->var.bits_per_pixel = var->bits_per_pixel;
+ disp->var.xres = var->xres;
+ disp->var.yres = var->yres;
+ disp->var.xres_virtual = var->xres_virtual;
+ disp->var.yres_virtual = var->yres_virtual;
+ disp->var.green.length = var->green.length;
+ disp->var.accel_flags = var->accel_flags;
- if (oldbpp != disp->var.bits_per_pixel || oldgreenlen != disp->var.green.length || oldaccel != disp->var.accel_flags)
- set_dispsw(disp, p);
-
- if (oldxres != disp->var.xres || oldbpp != disp->var.bits_per_pixel)
- disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
- set_display_info(disp);
-#endif
+ set_disp(disp, p);
if (info->changevar)
(*info->changevar)(con);
imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- u_int off;
+ struct display *disp = &fb_display[con];
+ __u32 off;
- if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
- || var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ if (var->xoffset + disp->var.xres > disp->var.xres_virtual
+ || var->yoffset + disp->var.yres > disp->var.yres_virtual)
return -EINVAL;
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
+ disp->var.xoffset = var->xoffset;
+ disp->var.yoffset = var->yoffset;
if (con == currcon) {
- off = var->yoffset * (fb_display[con].line_length / 8)
- + (var->xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
+ off = var->yoffset * (disp->line_length >> 3)
+ + ((var->xoffset * (disp->var.bits_per_pixel >> 3)) >> 3);
out_le32(&p->dc_regs[SSR], off);
}
#define FBIMSTT_GETREG 0x545402
#define FBIMSTT_SETCMAPREG 0x545403
#define FBIMSTT_GETCMAPREG 0x545404
-#define FBIMSTT_SETINITREG 0x545405
-#define FBIMSTT_GETINITREG 0x545406
+#define FBIMSTT_SETIDXREG 0x545405
+#define FBIMSTT_GETIDXREG 0x545406
static int
imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
out_le32(&p->dc_regs[reg[0]], reg[1]);
- break;
+ return 0;
case FBIMSTT_GETREG:
if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
reg[1] = in_le32(&p->dc_regs[reg[0]]);
if (copy_to_user((void *)(arg + 4), ®[1], 4))
return -EFAULT;
- break;
+ return 0;
case FBIMSTT_SETCMAPREG:
if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]);
- break;
+ return 0;
case FBIMSTT_GETCMAPREG:
if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]);
if (copy_to_user((void *)(arg + 4), ®[1], 4))
return -EFAULT;
- break;
- case FBIMSTT_SETINITREG:
+ return 0;
+ case FBIMSTT_SETIDXREG:
if (copy_from_user(init, (void *)arg, 2))
return -EFAULT;
p->cmap_regs[PIDXHI] = 0; eieio();
p->cmap_regs[PIDXLO] = init[0]; eieio();
p->cmap_regs[PIDXDATA] = init[1]; eieio();
- break;
- case FBIMSTT_GETINITREG:
+ return 0;
+ case FBIMSTT_GETIDXREG:
if (copy_from_user(init, (void *)arg, 1))
return -EFAULT;
p->cmap_regs[PIDXHI] = 0; eieio();
init[1] = p->cmap_regs[PIDXDATA];
if (copy_to_user((void *)(arg + 1), &init[1], 1))
return -EFAULT;
- break;
+ return 0;
default:
return -ENOIOCTLCMD;
}
-
- return 0;
}
static struct fb_ops imsttfb_ops = {
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
struct display *old = &fb_display[currcon], *new = &fb_display[con];
+ __u32 off;
if (old->cmap.len)
fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
|| old->var.yres != new->var.yres
|| old->var.bits_per_pixel != new->var.bits_per_pixel
|| old->var.green.length != new->var.green.length) {
- set_dispsw(new, p);
+ set_disp(new, p);
if (!compute_imstt_regvals(p, new->var.xres, new->var.yres))
return -1;
if (new->var.bits_per_pixel == 16) {
set_555(p);
}
set_imstt_regvals(p, new->var.bits_per_pixel);
-#ifdef CONFIG_FB_COMPAT_XPMAC
- set_display_info(new);
-#endif
+ }
+ if (old->var.yoffset != new->var.yoffset || old->var.xoffset != new->var.xoffset) {
+ off = new->var.yoffset * (new->line_length >> 3)
+ + ((new->var.xoffset * (new->var.bits_per_pixel >> 3)) >> 3);
+ out_le32(&p->dc_regs[SSR], off);
}
do_install_cmap(con, info);
return 0;
}
+static inline void
+imsttfb_rectfill (struct display *disp, u_int sy, u_int sx, u_int height, u_int width, __u32 bgx)
+{
+ memset(disp->screen_base + sy + sx, bgx, height * width * (disp->var.bits_per_pixel >> 3));
+}
+
static int
imsttfbcon_updatevar (int con, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- u_int off;
+ struct display *disp = &fb_display[con];
+ struct vc_data *conp = disp->conp;
+ __u32 off, yres, yoffset, sy, height;
- if (con == currcon) {
- off = fb_display[con].var.yoffset * (fb_display[con].line_length / 8)
- + (fb_display[con].var.xoffset * (fb_display[con].var.bits_per_pixel >> 3)) / 8;
- out_le32(&p->dc_regs[SSR], off);
+ if (con != currcon)
+ goto out;
+
+ yres = disp->var.yres;
+ yoffset = disp->var.yoffset;
+ sy = (conp->vc_rows + disp->yscroll) * fontheight(disp);
+ height = yres - conp->vc_rows * fontheight(disp);
+
+ if (height && (yoffset + yres > sy)) {
+ __u32 bgx = attr_bgcol_ec(disp, conp);
+
+ if (sy + height > disp->var.yres_virtual)
+ printk("updatevar: %u + %u > %u\n", sy, height, disp->var.yres_virtual);
+ imsttfb_rectfill(disp, sy, disp->var.xoffset, height, disp->var.xres, bgx);
}
+ if (p->ramdac == IBM && (yoffset + yres <= sy))
+ imsttfb_cursor(disp, CM_ERASE, p->cursor.x, p->cursor.y);
+
+ off = disp->var.yoffset * (disp->line_length >> 3)
+ + ((disp->var.xoffset * (disp->var.bits_per_pixel >> 3)) >> 3);
+ out_le32(&p->dc_regs[SSR], off);
+
+out:
return 0;
}
if (blank > 0) {
switch (blank - 1) {
case VESA_NO_BLANKING:
+ case VESA_POWERDOWN:
ctrl &= ~0x00000380;
+ if (p->ramdac == IBM) {
+ p->cmap_regs[PIDXHI] = 0; eieio();
+ p->cmap_regs[PIDXLO] = MISCTL2; eieio();
+ p->cmap_regs[PIDXDATA] = 0x55; eieio();
+ p->cmap_regs[PIDXLO] = MISCTL1; eieio();
+ p->cmap_regs[PIDXDATA] = 0x11; eieio();
+ p->cmap_regs[PIDXLO] = SYNCCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0x0f; eieio();
+ p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+ p->cmap_regs[PIDXDATA] = 0x1f; eieio();
+ p->cmap_regs[PIDXLO] = CLKCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0xc0;
+ }
break;
case VESA_VSYNC_SUSPEND:
ctrl &= ~0x00000020;
case VESA_HSYNC_SUSPEND:
ctrl &= ~0x00000010;
break;
- case VESA_POWERDOWN:
- ctrl &= ~0x00000380;
- break;
}
} else {
- ctrl |= p->ramdac == IBM ? 0x000017b0 : 0x00001780;
+ if (p->ramdac == IBM) {
+ ctrl |= 0x000017b0;
+ p->cmap_regs[PIDXHI] = 0; eieio();
+ p->cmap_regs[PIDXLO] = CLKCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0x01; eieio();
+ p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
+ p->cmap_regs[PIDXDATA] = 0x00; eieio();
+ p->cmap_regs[PIDXLO] = SYNCCTL; eieio();
+ p->cmap_regs[PIDXDATA] = 0x00; eieio();
+ p->cmap_regs[PIDXLO] = MISCTL1; eieio();
+ p->cmap_regs[PIDXDATA] = 0x01; eieio();
+ p->cmap_regs[PIDXLO] = MISCTL2; eieio();
+ p->cmap_regs[PIDXDATA] = 0x45; eieio();
+ } else
+ ctrl |= 0x00001780;
}
out_le32(&p->dc_regs[STGCTL], ctrl);
}
init_imstt(struct fb_info_imstt *p))
{
__u32 i, tmp;
+ __u32 *ip, *end;
tmp = in_le32(&p->dc_regs[PRC]);
if (p->ramdac == IBM)
else
p->total_vram = 0x00800000;
- memset(p->frame_buffer, 0, p->total_vram);
+ ip = (__u32 *)p->frame_buffer;
+ end = (__u32 *)(p->frame_buffer + p->total_vram);
+ while (ip < end)
+ *ip++ = 0;
/* initialize the card */
tmp = in_le32(&p->dc_regs[STGCTL]);
out_le32(&p->dc_regs[STGCTL], tmp & ~0x1);
+ out_le32(&p->dc_regs[SSR], 0);
/* set default values for DAC registers */
if (p->ramdac == IBM) {
- p->cmap_regs[PPMASK] = 0xff;
+ p->cmap_regs[PPMASK] = 0xff; eieio();
p->cmap_regs[PIDXHI] = 0; eieio();
for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
p->cmap_regs[PIDXLO] = ibm_initregs[i].addr; eieio();
#if USE_NV_MODES && defined(CONFIG_PPC)
{
- int vmode, cmode;
-
- vmode = nvram_read_byte(NV_VMODE);
- if (vmode <= 0 || vmode > VMODE_MAX)
- vmode = VMODE_640_480_67;
- cmode = nvram_read_byte(NV_CMODE);
- if (cmode < CMODE_8 || cmode > CMODE_32)
- cmode = CMODE_8;
+ int vmode = init_vmode, cmode = init_cmode;
+
+ if (vmode == -1) {
+ vmode = nvram_read_byte(NV_VMODE);
+ if (vmode <= 0 || vmode > VMODE_MAX)
+ vmode = VMODE_640_480_67;
+ }
+ if (cmode == -1) {
+ cmode = nvram_read_byte(NV_CMODE);
+ if (cmode < CMODE_8 || cmode > CMODE_32)
+ cmode = CMODE_8;
+ }
if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) {
p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES;
p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES;
p->disp.var.bits_per_pixel = INIT_BPP;
#endif
- p->disp.var.height = p->disp.var.width = -1;
- p->disp.var.vmode = FB_VMODE_NONINTERLACED;
- p->disp.var.left_margin = p->disp.var.right_margin = 16;
- p->disp.var.upper_margin = p->disp.var.lower_margin = 16;
- p->disp.var.hsync_len = p->disp.var.vsync_len = 8;
- p->disp.var.accel_flags = 0; /* FB_ACCELF_TEXT; */
-
- set_dispsw(&p->disp, p);
- if (p->ramdac == IBM)
- imstt_cursor_init(p);
-
- if (p->disp.var.green.length == 6)
- set_565(p);
- else
- set_555(p);
-
if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram
|| !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
return;
}
- set_imstt_regvals(p, p->disp.var.bits_per_pixel);
-
- p->disp.var.pixclock = 1000000 / getclkMHz(p);
-
sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP");
p->fix.smem_start = (__u8 *)p->frame_buffer_phys;
p->fix.smem_len = p->total_vram;
p->fix.ypanstep = 1;
p->fix.ywrapstep = 0;
- p->disp.screen_base = p->frame_buffer;
- p->disp.visual = p->fix.visual;
- p->disp.type = p->fix.type;
- p->disp.type_aux = p->fix.type_aux;
- p->disp.line_length = p->fix.line_length;
- p->disp.can_soft_blank = 1;
- p->disp.ypanstep = 1;
- p->disp.ywrapstep = 0;
- p->disp.scrollmode = SCROLL_YREDRAW;
+ p->disp.var.accel_flags = noaccel ? 0 : FB_ACCELF_TEXT;
+ set_disp(&p->disp, p);
+
+ if (p->ramdac == IBM)
+ imstt_cursor_init(p);
+ if (p->disp.var.green.length == 6)
+ set_565(p);
+ else
+ set_555(p);
+ set_imstt_regvals(p, p->disp.var.bits_per_pixel);
+
+ p->disp.var.pixclock = 1000000 / getclkMHz(p);
strcpy(p->info.modename, p->fix.id);
+ strcpy(p->info.fontname, fontname);
p->info.node = -1;
p->info.fbops = &imsttfb_ops;
p->info.disp = &p->disp;
- p->info.fontname[0] = 0;
p->info.changevar = 0;
p->info.switch_con = &imsttfbcon_switch;
p->info.updatevar = &imsttfbcon_updatevar;
GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20, tmp);
#ifdef CONFIG_FB_COMPAT_XPMAC
- strncpy(display_info.name, p->fix.id, sizeof display_info.name);
+ strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
display_info.fb_address = (__u32)p->frame_buffer_phys;
display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW];
display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
- display_info.disp_reg_address = 0;
+ display_info.disp_reg_address = (__u32)p->dc_regs_phys;
set_display_info(&p->disp);
if (!console_fb_info)
console_fb_info = &p->info;
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
-#if defined(CONFIG_FB_OF) || defined(CONFIG_PPC)
+#if defined(CONFIG_FB_OF)
__initfunc(void
imsttfb_of_init(struct device_node *dp))
{
__initfunc(void
imsttfb_init(void))
{
-#if defined(CONFIG_PPC)
- u_int i;
- struct device_node *dp;
- char *names[4] = {"IMS,tt128mb","IMS,tt128mbA","IMS,tt128mb8","IMS,tt128mb8A"};
+#if !defined(CONFIG_FB_OF)
+ /* ... */
+#endif
+}
+
+__initfunc(void
+imsttfb_setup(char *options, int *ints))
+{
+ char *this_opt;
-#ifdef CONFIG_FB_OF
- if (prom_num_displays)
+ if (!options || !*options)
return;
-#endif
- for (i = 0; i < 4; i++) {
- dp = find_devices(names[i]);
- if (dp)
- imsttfb_of_init(dp);
- }
-#else
- /* ... */
+ 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;
+ } else if (!strncmp(this_opt, "noblink", 7)) {
+ curblink = 0;
+ } else if (!strncmp(this_opt, "noaccel", 7)) {
+ noaccel = 1;
+ }
+#if defined(CONFIG_PPC)
+ else if (!strncmp(this_opt, "vmode:", 6)) {
+ int vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX)
+ init_vmode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ int cmode = simple_strtoul(this_opt+6, NULL, 0);
+ switch (cmode) {
+ case CMODE_8:
+ case 8:
+ init_cmode = CMODE_8;
+ break;
+ case CMODE_16:
+ case 15:
+ case 16:
+ init_cmode = CMODE_16;
+ break;
+ case CMODE_32:
+ case 24:
+ case 32:
+ init_cmode = CMODE_32;
+ break;
+ }
+ }
#endif
+ }
}
--- /dev/null
+/*
+ *
+ * Hardware accelerated Matrox Millenium I, II, Mystique and G200
+ *
+ * (c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.3 1998/10/28
+ *
+ * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <tmrini@ntplx.net>
+ * MTRR stuff, betatesting, fixes, ideas
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifndef __i386__
+#ifndef ioremap_nocache
+#define ioremap_nocache(X,Y) ioremap(X,Y)
+#endif
+#endif
+
+#ifdef DEBUG
+#define dprintk(X...) printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G200_AGP
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100
+#define PCI_DEVICE_ID_MATROX_G100 0x1000
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_UNSPECIFIED 0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G100, G200 and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
+#define NEED_DAC1064 1
+#endif
+
+struct matroxfb_par
+{
+ struct fb_var_screeninfo var;
+
+ unsigned int final_bppShift;
+ int visual; /* unfortunately, fix */
+ int video_type;
+ int cmap_len;
+};
+
+struct my_timming {
+ unsigned int pixclock;
+ unsigned int HDisplay;
+ unsigned int HSyncStart;
+ unsigned int HSyncEnd;
+ unsigned int HTotal;
+ unsigned int VDisplay;
+ unsigned int VSyncStart;
+ unsigned int VSyncEnd;
+ unsigned int VTotal;
+ unsigned int sync;
+ int dblscan;
+ int interlaced;
+};
+
+struct matrox_fb_info;
+
+#define MATROX_2MB_WITH_4MB_ADDON
+
+struct matrox_pll_features {
+ unsigned int vco_freq_min;
+ unsigned int ref_freq;
+ unsigned int feed_div_min;
+ unsigned int feed_div_max;
+ unsigned int in_div_min;
+ unsigned int in_div_max;
+ unsigned int post_shift_max;
+};
+
+struct matrox_DAC1064_features {
+ u_int8_t xvrefctrl;
+};
+
+struct matrox_accel_features {
+ int has_cacheflush;
+};
+
+/* current hardware status */
+struct matrox_hw_state {
+ u_int32_t MXoptionReg;
+ unsigned char DACclk[6];
+ unsigned char DACreg[64];
+ unsigned char MiscOutReg;
+ unsigned char DACpal[768];
+ unsigned char CRTC[25];
+ unsigned char CRTCEXT[6];
+ unsigned char SEQ[5];
+ /* unused for MGA mode, but who knows... */
+ unsigned char GCTL[9];
+ /* unused for MGA mode, but who knows... */
+ unsigned char ATTR[21];
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ unsigned char ramdac_rev;
+#endif
+ u_int32_t m_dwg_rect;
+};
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+#define ACCESS_FBINFO(x) (minfo->x)
+#define ACCESS_FBINFO2(info, x) (((struct matrox_fb_info*)info)->x)
+
+#define MINFO minfo
+
+#define WPMINFO struct matrox_fb_info* minfo,
+#define CPMINFO const struct matrox_fb_info* minfo,
+#define PMINFO minfo,
+
+static struct matrox_fb_info* mxinfo(struct display* p) {
+ return (struct matrox_fb_info*)p->fb_info;
+}
+
+#define PMXINFO(p) mxinfo(p),
+#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+
+#else
+
+struct matrox_fb_info global_mxinfo;
+struct display global_disp;
+
+#define ACCESS_FBINFO(x) (global_mxinfo.x)
+#define ACCESS_FBINFO2(info, x) (global_mxinfo.x)
+
+#define MINFO (&global_mxinfo)
+
+#define WPMINFO
+#define CPMINFO
+#define PMINFO
+
+#if 0
+static struct matrox_fb_info* mxinfo(struct display* p) {
+ return &global_mxinfo;
+}
+#endif
+
+#define PMXINFO(p)
+#define MINFO_FROM_DISP(x)
+
+#endif
+
+struct matrox_switch {
+ int (*preinit)(WPMINFO struct matrox_hw_state*);
+ void (*reset)(WPMINFO struct matrox_hw_state*);
+ int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*);
+ void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
+};
+
+struct matrox_fb_info {
+ /* fb_info must be first */
+ struct fb_info fbcon;
+
+ struct matrox_fb_info* next_fb;
+
+ struct matroxfb_par curr;
+ struct matrox_hw_state hw1;
+ struct matrox_hw_state hw2;
+ struct matrox_hw_state* newhw;
+ struct matrox_hw_state* currenthw;
+
+ struct matrox_accel_data accel;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+ unsigned int _mga_ydstorg;
+ unsigned int _curr_ydstorg;
+#endif
+
+ struct pci_dev* pcidev;
+
+ unsigned long video_base; /* physical */
+ char* video_vbase; /* CPU view */
+ unsigned int video_len;
+
+ unsigned long mmio_base; /* physical */
+ unsigned char* mmio; /* CPU view */
+ unsigned int mmio_len;
+
+ unsigned int max_pixel_clock;
+
+ struct matrox_switch* hw_switch;
+ int currcon;
+
+ struct {
+ struct matrox_pll_features pll;
+ struct matrox_DAC1064_features DAC1064;
+ struct matrox_accel_features accel;
+ } features;
+
+ int interleave;
+ int millenium;
+ int milleniumII;
+ struct {
+ int cfb4;
+ const int* vxres;
+ } capable;
+#ifdef CONFIG_MTRR
+ struct {
+ int vram;
+ int vram_valid;
+ } mtrr;
+#endif
+ struct {
+ int precise_width;
+ int mga_24bpp_fix;
+ int novga;
+ int nobios;
+ int nopciretry;
+ int inverse;
+ int hwcursor;
+
+ int accelerator;
+ int video64bits;
+ } devflags;
+ struct display_switch dispsw;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ struct {
+ unsigned int x;
+ unsigned int y;
+ unsigned int w;
+ unsigned int h;
+ volatile unsigned int mode;
+ } cursor;
+#endif
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
+ union {
+#ifdef FBCON_HAS_CFB16
+ u_int16_t cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u_int32_t cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u_int32_t cfb32[16];
+#endif
+ } cmap;
+#endif
+ struct { unsigned red, green, blue, transp; } palette[256];
+};
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#define mga_ydstorg(x) ACCESS_FBINFO2(x, _mga_ydstorg)
+#define curr_ydstorg(x) ACCESS_FBINFO2(x, _curr_ydstorg)
+#else
+#define mga_ydstorg(x) (0)
+#define curr_ydstorg(x) (0)
+#endif
+
+#define PCI_OPTION_REG 0x40
+#define PCI_MGA_INDEX 0x44
+#define PCI_MGA_DATA 0x48
+
+#define M_DWGCTL 0x1C00
+#define M_MACCESS 0x1C04
+#define M_CTLWTST 0x1C08
+
+#define M_PLNWT 0x1C1C
+
+#define M_BCOL 0x1C20
+#define M_FCOL 0x1C24
+
+#define M_SGN 0x1C58
+#define M_LEN 0x1C5C
+#define M_AR0 0x1C60
+#define M_AR1 0x1C64
+#define M_AR2 0x1C68
+#define M_AR3 0x1C6C
+#define M_AR4 0x1C70
+#define M_AR5 0x1C74
+#define M_AR6 0x1C78
+
+#define M_CXBNDRY 0x1C80
+#define M_FXBNDRY 0x1C84
+#define M_YDSTLEN 0x1C88
+#define M_PITCH 0x1C8C
+#define M_YDST 0x1C90
+#define M_YDSTORG 0x1C94
+#define M_YTOP 0x1C98
+#define M_YBOT 0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH 0x1FFF
+
+#define M_EXEC 0x0100
+
+#define M_DWG_TRAP 0x04
+#define M_DWG_BITBLT 0x08
+#define M_DWG_ILOAD 0x09
+
+#define M_DWG_LINEAR 0x0080
+#define M_DWG_SOLID 0x0800
+#define M_DWG_ARZERO 0x1000
+#define M_DWG_SGNZERO 0x2000
+#define M_DWG_SHIFTZERO 0x4000
+
+#define M_DWG_REPLACE 0x000C0000
+#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR 0x00060010
+
+#define M_DWG_BFCOL 0x04000000
+#define M_DWG_BMONOWF 0x08000000
+
+#define M_DWG_TRANSC 0x40000000
+
+#define M_FIFOSTATUS 0x1E10
+#define M_STATUS 0x1E14
+
+#define M_IEN 0x1E1C
+
+#define M_VCOUNT 0x1E20
+
+#define M_RESET 0x1E40
+
+#define M_OPMODE 0x1E54
+#define M_OPMODE_DMA_GEN_WRITE 0x00
+#define M_OPMODE_DMA_BLIT 0x04
+#define M_OPMODE_DMA_VECTOR_WRITE 0x08
+#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */
+#define M_OPMODE_DMA_BE_8BPP 0x0000
+#define M_OPMODE_DMA_BE_16BPP 0x0100
+#define M_OPMODE_DMA_BE_32BPP 0x0200
+#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */
+#define M_OPMODE_DIR_BE_8BPP 0x000000
+#define M_OPMODE_DIR_BE_16BPP 0x010000
+#define M_OPMODE_DIR_BE_32BPP 0x020000
+
+#define M_ATTR_INDEX 0x1FC0
+#define M_ATTR_DATA 0x1FC1
+
+#define M_MISC_REG 0x1FC2
+#define M_3C2_RD 0x1FC2
+
+#define M_SEQ_INDEX 0x1FC4
+#define M_SEQ_DATA 0x1FC5
+
+#define M_MISC_REG_READ 0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA 0x1FCF
+
+#define M_CRTC_INDEX 0x1FD4
+
+#define M_ATTR_RESET 0x1FDA
+#define M_3DA_WR 0x1FDA
+
+#define M_EXTVGA_INDEX 0x1FDE
+#define M_EXTVGA_DATA 0x1FDF
+
+#define M_RAMDAC_BASE 0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG (M_RAMDAC_BASE+0)
+#define M_DAC_VAL (M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK (M_RAMDAC_BASE+2)
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define TVP3026_INDEX 0x00
+#define TVP3026_PALWRADD 0x00
+#define TVP3026_PALDATA 0x01
+#define TVP3026_PIXRDMSK 0x02
+#define TVP3026_PALRDADD 0x03
+#define TVP3026_CURCOLWRADD 0x04
+#define TVP3026_CLOVERSCAN 0x00
+#define TVP3026_CLCOLOR0 0x01
+#define TVP3026_CLCOLOR1 0x02
+#define TVP3026_CLCOLOR2 0x03
+#define TVP3026_CURCOLDATA 0x05
+#define TVP3026_CURCOLRDADD 0x07
+#define TVP3026_CURCTRL 0x09
+#define TVP3026_X_DATAREG 0x0A
+#define TVP3026_CURRAMDATA 0x0B
+#define TVP3026_CURPOSXL 0x0C
+#define TVP3026_CURPOSXH 0x0D
+#define TVP3026_CURPOSYL 0x0E
+#define TVP3026_CURPOSYH 0x0F
+
+#define TVP3026_XSILICONREV 0x01
+#define TVP3026_XCURCTRL 0x06
+#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
+#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
+#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
+#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
+#define TVP3026_XCURCTRL_BLANK2048 0x00
+#define TVP3026_XCURCTRL_BLANK4096 0x10
+#define TVP3026_XCURCTRL_INTERLACED 0x20
+#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */
+#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */
+#define TVP3026_XCURCTRL_INDIRECT 0x00
+#define TVP3026_XCURCTRL_DIRECT 0x80
+#define TVP3026_XLATCHCTRL 0x0F
+#define TVP3026_XLATCHCTRL_1_1 0x06
+#define TVP3026_XLATCHCTRL_2_1 0x07
+#define TVP3026_XLATCHCTRL_4_1 0x06
+#define TVP3026_XLATCHCTRL_8_1 0x06
+#define TVP3026_XLATCHCTRL_16_1 0x06
+#define TVP3026A_XLATCHCTRL_4_3 0x07
+#define TVP3026B_XLATCHCTRL_4_3 0x08
+#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... ??? */
+#define TVP3026_XTRUECOLORCTRL 0x18
+#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00
+#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20
+#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80
+#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */
+#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00
+#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17
+#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06
+#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07
+#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05
+#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04
+#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03
+#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01
+#define TVP3026_XMUXCTRL 0x19
+#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */
+#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */
+#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */
+#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */
+#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */
+#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */
+#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48
+#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50
+#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58
+#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL 0x1A
+#define TVP3026_XCLKCTRL_DIV1 0x00
+#define TVP3026_XCLKCTRL_DIV2 0x10
+#define TVP3026_XCLKCTRL_DIV4 0x20
+#define TVP3026_XCLKCTRL_DIV8 0x30
+#define TVP3026_XCLKCTRL_DIV16 0x40
+#define TVP3026_XCLKCTRL_DIV32 0x50
+#define TVP3026_XCLKCTRL_DIV64 0x60
+#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70
+#define TVP3026_XCLKCTRL_SRC_CLK0 0x00
+#define TVP3026_XCLKCTRL_SRC_CLK1 0x01
+#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/
+#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */
+#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */
+#define TVP3026_XCLKCTRL_SRC_PLL 0x05
+#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */
+#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE 0x1C
+#define TVP3026_XGENCTRL 0x1D
+#define TVP3026_XGENCTRL_HSYNC_POS 0x00
+#define TVP3026_XGENCTRL_HSYNC_NEG 0x01
+#define TVP3026_XGENCTRL_VSYNC_POS 0x00
+#define TVP3026_XGENCTRL_VSYNC_NEG 0x02
+#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08
+#define TVP3026_XGENCTRL_BLACK_0IRE 0x00
+#define TVP3026_XGENCTRL_BLACK_75IRE 0x10
+#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00
+#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20
+#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00
+#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40
+#define TVP3026_XMISCCTRL 0x1E
+#define TVP3026_XMISCCTRL_DAC_PUP 0x00
+#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01
+#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */
+#define TVP3026_XMISCCTRL_DAC_6BIT 0x04
+#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C
+#define TVP3026_XMISCCTRL_PSEL_DIS 0x00
+#define TVP3026_XMISCCTRL_PSEL_EN 0x10
+#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
+#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL 0x2A
+#define TVP3026_XGENIODATA 0x2B
+#define TVP3026_XPLLADDR 0x2C
+#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define TVP3026_XPLLDATA_N 0x00
+#define TVP3026_XPLLDATA_M 0x01
+#define TVP3026_XPLLDATA_P 0x02
+#define TVP3026_XPLLDATA_STAT 0x03
+#define TVP3026_XPIXPLLDATA 0x2D
+#define TVP3026_XMEMPLLDATA 0x2E
+#define TVP3026_XLOOPPLLDATA 0x2F
+#define TVP3026_XCOLKEYOVRMIN 0x30
+#define TVP3026_XCOLKEYOVRMAX 0x31
+#define TVP3026_XCOLKEYREDMIN 0x32
+#define TVP3026_XCOLKEYREDMAX 0x33
+#define TVP3026_XCOLKEYGREENMIN 0x34
+#define TVP3026_XCOLKEYGREENMAX 0x35
+#define TVP3026_XCOLKEYBLUEMIN 0x36
+#define TVP3026_XCOLKEYBLUEMAX 0x37
+#define TVP3026_XCOLKEYCTRL 0x38
+#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01
+#define TVP3026_XCOLKEYCTRL_RED_EN 0x02
+#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08
+#define TVP3026_XCOLKEYCTRL_NEGATE 0x10
+#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00
+#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20
+#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40
+#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60
+#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80
+#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
+#define TVP3026_XMEMPLLCTRL 0x39
+#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08
+#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */
+#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */
+#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00
+#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20
+#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST 0x3A
+#define TVP3026_XTESTMODEDATA 0x3B
+#define TVP3026_XCRCREML 0x3C
+#define TVP3026_XCRCREMH 0x3D
+#define TVP3026_XCRCBITSEL 0x3E
+#define TVP3026_XID 0x3F
+
+#endif
+
+#ifdef NEED_DAC1064
+
+#define DAC1064_OPT_SCLK_PCI 0x00
+#define DAC1064_OPT_SCLK_PLL 0x01
+#define DAC1064_OPT_SCLK_EXT 0x02
+#define DAC1064_OPT_SCLK_MASK 0x03
+#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3 0x00
+#define DAC1064_OPT_MDIV1 0x08
+#define DAC1064_OPT_MDIV2 0x00
+#define DAC1064_OPT_RESERVED 0x10
+
+#define M1064_INDEX 0x00
+#define M1064_PALWRADD 0x00
+#define M1064_PALDATA 0x01
+#define M1064_PIXRDMSK 0x02
+#define M1064_PALRDADD 0x03
+#define M1064_X_DATAREG 0x0A
+#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */
+#define M1064_CURPOSXH 0x0D
+#define M1064_CURPOSYL 0x0E
+#define M1064_CURPOSYH 0x0F
+
+#define M1064_XCURADDL 0x04
+#define M1064_XCURADDH 0x05
+#define M1064_XCURCTRL 0x06
+#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
+#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
+#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
+#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
+#define M1064_XCURCOL0RED 0x08
+#define M1064_XCURCOL0GREEN 0x09
+#define M1064_XCURCOL0BLUE 0x0A
+#define M1064_XCURCOL1RED 0x0C
+#define M1064_XCURCOL1GREEN 0x0D
+#define M1064_XCURCOL1BLUE 0x0E
+#define M1064_XCURCOL2RED 0x10
+#define M1064_XCURCOL2GREEN 0x11
+#define M1064_XCURCOL2BLUE 0x12
+#define DAC1064_XVREFCTRL 0x18
+#define DAC1064_XVREFCTRL_INTERNAL 0x3F
+#define DAC1064_XVREFCTRL_EXTERNAL 0x00
+#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03
+#define M1064_XMULCTRL 0x19
+#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */
+#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */
+#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */
+#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */
+#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */
+#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
+#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08
+#define M1064_XPIXCLKCTRL 0x1A
+#define M1064_XPIXCLKCTRL_SRC_PCI 0x00
+#define M1064_XPIXCLKCTRL_SRC_PLL 0x01
+#define M1064_XPIXCLKCTRL_SRC_EXT 0x02
+#define M1064_XPIXCLKCTRL_SRC_MASK 0x03
+#define M1064_XPIXCLKCTRL_EN 0x00
+#define M1064_XPIXCLKCTRL_DIS 0x04
+#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00
+#define M1064_XPIXCLKCTRL_PLL_UP 0x08
+#define M1064_XGENCTRL 0x1D
+#define M1064_XGENCTRL_VS_0 0x00
+#define M1064_XGENCTRL_VS_1 0x01
+#define M1064_XGENCTRL_ALPHA_DIS 0x00
+#define M1064_XGENCTRL_ALPHA_EN 0x02
+#define M1064_XGENCTRL_BLACK_0IRE 0x00
+#define M1064_XGENCTRL_BLACK_75IRE 0x10
+#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00
+#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20
+#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
+#define M1064_XMISCCTRL 0x1E
+#define M1064_XMISCCTRL_DAC_DIS 0x00
+#define M1064_XMISCCTRL_DAC_EN 0x01
+#define M1064_XMISCCTRL_MFC_VGA 0x00
+#define M1064_XMISCCTRL_MFC_MAFC 0x02
+#define M1064_XMISCCTRL_MFC_DIS 0x06
+#define M1064_XMISCCTRL_DAC_6BIT 0x00
+#define M1064_XMISCCTRL_DAC_8BIT 0x08
+#define M1064_XMISCCTRL_LUT_DIS 0x00
+#define M1064_XMISCCTRL_LUT_EN 0x10
+#define M1064_XGENIOCTRL 0x2A
+#define M1064_XGENIODATA 0x2B
+#define DAC1064_XSYSPLLM 0x2C
+#define DAC1064_XSYSPLLN 0x2D
+#define DAC1064_XSYSPLLP 0x2E
+#define DAC1064_XSYSPLLSTAT 0x2F
+#define M1064_XZOOMCTRL 0x38
+#define M1064_XZOOMCTRL_1 0x00
+#define M1064_XZOOMCTRL_2 0x01
+#define M1064_XZOOMCTRL_4 0x03
+#define M1064_XSENSETEST 0x3A
+#define M1064_XSENSETEST_BCOMP 0x01
+#define M1064_XSENSETEST_GCOMP 0x02
+#define M1064_XSENSETEST_RCOMP 0x04
+#define M1064_XSENSETEST_PDOWN 0x00
+#define M1064_XSENSETEST_PUP 0x80
+#define M1064_XCRCREML 0x3C
+#define M1064_XCRCREMH 0x3D
+#define M1064_XCRCBITSEL 0x3E
+#define M1064_XCOLKEYMASKL 0x40
+#define M1064_XCOLKEYMASKH 0x41
+#define M1064_XCOLKEYL 0x42
+#define M1064_XCOLKEYH 0x43
+#define M1064_XPIXPLLAM 0x44
+#define M1064_XPIXPLLAN 0x45
+#define M1064_XPIXPLLAP 0x46
+#define M1064_XPIXPLLBM 0x48
+#define M1064_XPIXPLLBN 0x49
+#define M1064_XPIXPLLBP 0x4A
+#define M1064_XPIXPLLCM 0x4C
+#define M1064_XPIXPLLCN 0x4D
+#define M1064_XPIXPLLCP 0x4E
+#define M1064_XPIXPLLSTAT 0x4F
+
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define MX_OPTION_BSWAP 0x00000000
+
+#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define MX_OPTION_BSWAP 0x80000000
+
+#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
+#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */
+#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr) (*(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr)))
+/* #define mga_inw(addr) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr)) */
+#define mga_inl(addr) (*(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr)))
+#define mga_outb(addr,val) *(volatile u_int8_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+/* #define mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val) */
+#define mga_outl(addr,val) *(volatile u_int32_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
+#ifdef __LITTLE_ENDIAN
+#define __mga_outw(addr,val) *(volatile u_int16_t*)(ACCESS_FBINFO(mmio)+(addr))=(val)
+#define mga_setr(addr,port,val) __mga_outw(addr, ((val)<<8) | (port))
+#else
+#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n))
+#else
+#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+#endif
+
+static void WaitTillIdle(const struct matrox_fb_info* minfo) {
+ do {} while (mga_inl(M_STATUS) & 0x10000);
+}
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x) (x->interleave)
+#define isMillenium(x) (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x) (0)
+#define isMillenium(x) (0)
+#define isMilleniumII(x) (0)
+#endif
+
+static void matrox_cfbX_init(struct matrox_fb_info* minfo) {
+ u_int32_t maccess;
+ u_int32_t mpitch;
+ u_int32_t mopmode;
+
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+ curr_ydstorg(MINFO) = mga_ydstorg(MINFO);
+#endif
+ mpitch = ACCESS_FBINFO(curr.var.xres_virtual);
+ switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+ case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
+ mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+ mopmode = M_OPMODE_4BPP;
+ break;
+ case 8: maccess = 0x00000000;
+ mopmode = M_OPMODE_8BPP;
+ break;
+ case 16: if (ACCESS_FBINFO(curr.var.green.length) == 5)
+ maccess = 0xC0000001;
+ else
+ maccess = 0x40000001;
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+ curr_ydstorg(MINFO) >>= 1;
+#endif
+ mopmode = M_OPMODE_16BPP;
+ break;
+ case 24: maccess = 0x00000003;
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+ curr_ydstorg(MINFO) /= 3;
+#endif
+ mopmode = M_OPMODE_24BPP;
+ break;
+ case 32: maccess = 0x00000002;
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+ curr_ydstorg(MINFO) >>= 2;
+#endif
+ mopmode = M_OPMODE_32BPP;
+ break;
+ default: maccess = 0x00000000;
+ mopmode = 0x00000000;
+ break; /* turn off acceleration!!! */
+ }
+ mga_fifo(8);
+ mga_outl(M_PITCH, mpitch);
+ mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
+ mga_outl(M_PLNWT, -1);
+ mga_outl(M_OPMODE, mopmode);
+ mga_outl(M_CXBNDRY, 0xFFFF0000);
+ mga_outl(M_YTOP, 0);
+ mga_outl(M_YBOT, 0x007FFFFF);
+ mga_outl(M_MACCESS, maccess);
+ ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+ if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
+}
+
+static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+ int pixx = p->var.xres_virtual, start, end;
+ MINFO_FROM_DISP(p);
+
+ sx *= fontwidth(p);
+ dx *= fontwidth(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+ mga_fifo(2);
+ mga_outl(M_AR5, pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+ M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ start = sy*pixx+sx+curr_ydstorg(MINFO);
+ end = start+width;
+ } else {
+ mga_fifo(3);
+ mga_outl(M_SGN, 5);
+ mga_outl(M_AR5, -pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+ start = end+width;
+ dy += height-1;
+ }
+ mga_fifo(4);
+ mga_outl(M_AR0, end);
+ mga_outl(M_AR3, start);
+ mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+ mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+ WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+ int pixx, start, end;
+ MINFO_FROM_DISP(p);
+ /* both (sx or dx or width) and fontwidth() are odd, so their multiply is
+ also odd, that means that we cannot use acceleration */
+ if ((sx | dx | width) & fontwidth(p) & 1) {
+ fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
+ return;
+ }
+ sx *= fontwidth(p);
+ dx *= fontwidth(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ pixx = p->var.xres_virtual >> 1;
+ sx >>= 1;
+ dx >>= 1;
+ width >>= 1;
+ if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+ mga_fifo(2);
+ mga_outl(M_AR5, pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+ M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ start = sy*pixx+sx+curr_ydstorg(MINFO);
+ end = start+width;
+ } else {
+ mga_fifo(3);
+ mga_outl(M_SGN, 5);
+ mga_outl(M_AR5, -pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+ start = end+width;
+ dy += height-1;
+ }
+ mga_fifo(5);
+ mga_outl(M_AR0, end);
+ mga_outl(M_AR3, start);
+ mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+ mga_outl(M_YDST, dy*pixx >> 5);
+ mga_outl(M_LEN | M_EXEC, height);
+ WaitTillIdle(MINFO);
+}
+#endif
+
+static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height,
+ int width) {
+ mga_fifo(4);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
+ mga_outl(M_FCOL, color);
+ mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+ mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+ WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
+ matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
+ height * fontheight(p), width * fontwidth(p));
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+ int whattodo;
+ MINFO_FROM_DISP(p);
+
+ whattodo = 0;
+ bgx = attr_bgcol_ec(p, conp);
+ bgx |= bgx << 4;
+ bgx |= bgx << 8;
+ bgx |= bgx << 16;
+ sy *= fontheight(p);
+ sx *= fontwidth(p);
+ height *= fontheight(p);
+ width *= fontwidth(p);
+ if (sx & 1) {
+ sx ++;
+ if (!width) return;
+ width --;
+ whattodo = 1;
+ }
+ if (width & 1) {
+ whattodo |= 2;
+ }
+ width >>= 1;
+ sx >>= 1;
+ if (width) {
+ mga_fifo(5);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
+ mga_outl(M_FCOL, bgx);
+ mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+ mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
+ mga_outl(M_LEN | M_EXEC, height);
+ WaitTillIdle(MINFO);
+ }
+ if (whattodo) {
+ u_int32_t step = p->var.xres_virtual >> 1;
+ if (whattodo & 1) {
+ u_int8_t* uaddr = p->screen_base + sy * step + sx - 1;
+ u_int32_t loop;
+ u_int8_t bgx2 = bgx & 0xF0;
+ for (loop = height; loop > 0; loop --) {
+ *uaddr = (*uaddr & 0x0F) | bgx2;
+ uaddr += step;
+ }
+ }
+ if (whattodo & 2) {
+ u_int8_t* uaddr = p->screen_base + sy * step + sx + width;
+ u_int32_t loop;
+ u_int8_t bgx2 = bgx & 0x0F;
+ for (loop = height; loop > 0; loop --) {
+ *uaddr = (*uaddr & 0xF0) | bgx2;
+ uaddr += step;
+ }
+ }
+ }
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ bgx = attr_bgcol_ec(p, conp);
+ bgx |= bgx << 8;
+ bgx |= bgx << 16;
+ matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
+ u_int32_t ar0;
+ u_int32_t step;
+ MINFO_FROM_DISP(p);
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ mga_fifo(7);
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ ar0 = fontwidth(p) - 1;
+ mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
+ if (fontwidth(p) <= 8)
+ step = 1;
+ else if (fontwidth(p) <= 16)
+ step = 2;
+ else
+ step = 4;
+ /* TODO: set OPMODE_DMA_LE for BE */
+ if (fontwidth(p) == step << 3) {
+ size_t charcell = fontheight(p)*step;
+ /* TODO: Align charcell to 4B for BE */
+ mga_outl(M_AR3, 0);
+ mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
+ mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+ memcpy(ACCESS_FBINFO(mmio), p->fontdata+(c&p->charmask)*charcell, charcell);
+ } else {
+ u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
+ u_int32_t ydstlen_tmp = (yy << 16) | 1;
+ int i;
+ switch (step) {
+ case 1:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+ ydstlen_tmp += 0x10000;
+ }
+ break;
+ case 2:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 16;
+#endif
+ ydstlen_tmp += 0x10000;
+ chardata += 2;
+ }
+ break;
+ case 4:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+ ydstlen_tmp += 0x10000;
+ chardata += 4;
+ }
+ break;
+ }
+ }
+ /* TODO: restore OPMODE for BE */
+ WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = attr_fgcol(p, c);
+ bgx = attr_bgcol(p, c);
+ fgx |= (fgx << 8);
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+ matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 16);
+ matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
+ matrox_cfbX_putc(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t step;
+ u_int32_t ydstlen;
+ u_int32_t xlen;
+ u_int32_t ar0;
+ u_int32_t charcell;
+ u_int32_t fxbndry;
+ int easy;
+ MINFO_FROM_DISP(p);
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ if (fontwidth(p) <= 8)
+ step = 1;
+ else if (fontwidth(p) <= 16)
+ step = 2;
+ else
+ step = 4;
+ charcell = fontheight(p)*step;
+ xlen = (charcell + 3) & ~3;
+ if (fontwidth(p) == step << 3) {
+ ydstlen = (yy<<16) | fontheight(p);
+ ar0 = fontheight(p)*fontwidth(p) - 1;
+ easy = 1;
+ } else {
+ ydstlen = (yy<<16) | 1;
+ ar0 = fontwidth(p) - 1;
+ easy = 0;
+ }
+ mga_fifo(3);
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ /* TODO: set OPMODE_DMA_LE for BE */
+ fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
+ while (count--) {
+ u_int8_t* chardata = p->fontdata + (*s++ & p->charmask)*charcell;
+
+ mga_fifo(4);
+ mga_outl(M_FXBNDRY, fxbndry);
+ if (easy) {
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen);
+ memcpy(ACCESS_FBINFO(mmio), chardata, xlen);
+ } else {
+ u_int32_t ydstlen_tmp = ydstlen;
+ int i;
+ switch (step) {
+ case 1:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *chardata++;
+#else
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = (*chardata++) << 24;
+#endif
+ ydstlen_tmp += 0x10000;
+ }
+ break;
+ case 2:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+#ifdef __LITTLE_ENDIAN
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int16_t*)chardata;
+#else
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = (*(u_int16_t*)chardata) << 32;
+#endif
+ ydstlen_tmp += 0x10000;
+ chardata += 2;
+ }
+ break;
+ case 4:
+ for (i = fontheight(p); i > 0; i--) {
+ mga_fifo(3);
+ mga_outl(M_AR0, ar0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_YDSTLEN | M_EXEC, ydstlen_tmp);
+ *(u_int32_t*)ACCESS_FBINFO(mmio) = *(u_int32_t*)chardata;
+ ydstlen_tmp += 0x10000;
+ chardata += 4;
+ }
+ break;
+ }
+ }
+ fxbndry += fontwidth(p) + (fontwidth(p) << 16);
+ }
+ /* TODO: restore OPMODE for BE */
+ WaitTillIdle(MINFO);
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = attr_fgcol(p, *s);
+ bgx = attr_bgcol(p, *s);
+ fgx |= (fgx << 8);
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+ matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 16);
+ matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+
+ fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, *s)];
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, *s)];
+ matrox_cfbX_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
+ MINFO_FROM_DISP(p);
+
+ if (fontwidth(p) & 1) {
+ fbcon_cfb4_revc(p, xx, yy);
+ return;
+ }
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ xx |= (xx + fontwidth(p)) << 16;
+ xx >>= 1;
+
+ mga_fifo(5);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0xFFFFFFFF);
+ mga_outl(M_FXBNDRY, xx);
+ mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
+ mga_outl(M_LEN | M_EXEC, fontheight(p));
+ WaitTillIdle(MINFO);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
+ MINFO_FROM_DISP(p);
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ mga_fifo(4);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0x0F0F0F0F);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+ mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ WaitTillIdle(MINFO);
+}
+#endif
+
+static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
+ MINFO_FROM_DISP(p);
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ mga_fifo(4);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0xFFFFFFFF);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+ mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+ WaitTillIdle(MINFO);
+}
+
+static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
+ unsigned int bottom_height, right_width;
+ unsigned int bottom_start, right_start;
+ unsigned int cell_h, cell_w;
+
+ cell_w = fontwidth(p);
+ if (!cell_w) return; /* PARANOID */
+ right_width = p->var.xres % cell_w;
+ right_start = p->var.xres - right_width;
+ if (!bottom_only && right_width) {
+ matroxfb_accel_clear( PMXINFO(p)
+ /* color */ 0x00000000,
+ /* y */ p->var.yoffset,
+ /* x */ p->var.xoffset + right_start,
+ /* height */ p->var.yres,
+ /* width */ right_width);
+ }
+ cell_h = fontheight(p);
+ if (!cell_h) return; /* PARANOID */
+ bottom_height = p->var.yres % cell_h;
+ if (bottom_height) {
+ bottom_start = p->var.yres - bottom_height;
+ matroxfb_accel_clear( PMXINFO(p)
+ /* color */ 0x00000000,
+ /* y */ p->var.yoffset + bottom_start,
+ /* x */ p->var.xoffset,
+ /* height */ bottom_height,
+ /* width */ right_start);
+ }
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void outTi3026(CPMINFO int reg, int val) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+ mga_outb(M_RAMDAC_BASE+TVP3026_X_DATAREG, val);
+}
+
+static int inTi3026(CPMINFO int reg) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg);
+ return mga_inb(M_RAMDAC_BASE+TVP3026_X_DATAREG);
+}
+
+#define POS3026_XCURCTRL 20
+
+static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
+ MINFO_FROM_DISP(p);
+
+ if (mode == CM_ERASE) {
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+ return;
+ }
+ x *= fontwidth(p);
+ y *= fontheight(p);
+ y -= p->var.yoffset;
+ if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y))) {
+ ACCESS_FBINFO(cursor.x) = x;
+ ACCESS_FBINFO(cursor.y) = y;
+ x += 64;
+ y += 64;
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) & ~3);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
+ }
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | 2);
+}
+#undef POS3026_XCURCTRL
+
+static void matroxfb_ti3026_createcursor(WPMINFO int w, int h) {
+ u_int32_t xline;
+ int i;
+
+ ACCESS_FBINFO(cursor.w) = w;
+ ACCESS_FBINFO(cursor.h) = h;
+ xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
+ mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
+ for (i = 0; i < ACCESS_FBINFO(cursor.h); i++) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ }
+ i *= 8;
+ for (; i < 512; i++)
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ for (i = 0; i < 512; i++)
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
+}
+
+static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
+ matroxfb_ti3026_createcursor(PMXINFO(p) width, height);
+ return 0;
+}
+#endif
+
+#define matrox_cfb16_revc matrox_cfbX_revc
+#define matrox_cfb24_revc matrox_cfbX_revc
+#define matrox_cfb32_revc matrox_cfbX_revc
+
+#define matrox_cfb24_clear matrox_cfb32_clear
+#define matrox_cfb24_putc matrox_cfb32_putc
+#define matrox_cfb24_putcs matrox_cfb32_putcs
+
+#ifdef FBCON_HAS_CFB4
+static struct display_switch matroxfb_cfb4 = {
+ fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear,
+ fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc,
+ NULL, NULL, NULL,
+ /* cursor... */ /* set_font... */
+ FONTWIDTH(8) /* fix, fix, fix it */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch matroxfb_cfb8 = {
+ fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear,
+ matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch matroxfb_cfb16 = {
+ fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear,
+ matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static struct display_switch matroxfb_cfb24 = {
+ fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear,
+ matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch matroxfb_cfb32 = {
+ fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear,
+ matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+static struct pci_dev* pci_find(struct pci_dev* p) {
+ if (p) return p->next;
+ return pci_devices;
+}
+
+static void initMatrox(WPMINFO int con, struct display* p) {
+ struct display_switch *swtmp;
+
+ p->dispsw_data = NULL;
+ if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ swtmp = &fbcon_cfb4;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ swtmp = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+ swtmp = &fbcon_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+ swtmp = &fbcon_cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+ swtmp = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ p->dispsw = &fbcon_dummy;
+ return;
+ }
+ dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
+ } else {
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ swtmp = &matroxfb_cfb4;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ swtmp = &matroxfb_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+ swtmp = &matroxfb_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+ swtmp = &matroxfb_cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+ swtmp = &matroxfb_cfb32;
+ break;
+#endif
+ default:
+ p->dispsw = &fbcon_dummy;
+ return;
+ }
+ dprintk(KERN_INFO "matroxfb: now accelerated\n");
+ }
+ memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
+ p->dispsw = &ACCESS_FBINFO(dispsw);
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ if (isMillenium(MINFO) && ACCESS_FBINFO(devflags.hwcursor)) {
+ ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
+ ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
+ }
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined __initdata = {
+ 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/
+ 0,0, /* virtual -> visible no offset */
+ 8, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ -1,-1,
+ FB_ACCELF_TEXT, /* accel flags */
+ 0L,0L,0L,0L,0L,
+ 0L,0L,0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(struct fb_var_screeninfo *var, struct matrox_fb_info* minfo) {
+ struct matroxfb_par* p = &ACCESS_FBINFO(curr);
+ unsigned int pos;
+ unsigned short p0, p1, p2;
+
+ p->var.xoffset = var->xoffset;
+ p->var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ p->var.vmode |= FB_VMODE_YWRAP;
+ else
+ p->var.vmode &= FB_VMODE_YWRAP;
+
+ pos = (p->var.yoffset * p->var.xres_virtual + p->var.xoffset) * p->final_bppShift / 32;
+ if (mga_ydstorg(MINFO)) {
+ if (isInterleave(MINFO))
+ pos += mga_ydstorg(MINFO) >> 3;
+ else
+ pos += mga_ydstorg(MINFO) >> 2;
+ }
+
+ p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
+ p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+ p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+ mga_setr(M_CRTC_INDEX, 0x0D, p0);
+ mga_setr(M_CRTC_INDEX, 0x0C, p1);
+ mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+}
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info* info) {
+#define minfo ((struct matrox_fb_info*)info)
+ if (var->vmode & FB_VMODE_YWRAP) {
+ if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+ return -EINVAL;
+ } else {
+ if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+ var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ return -EINVAL;
+ }
+ if (con == ACCESS_FBINFO(currcon))
+ matrox_pan_var(var, MINFO);
+ fb_display[con].var.xoffset = var->xoffset;
+ fb_display[con].var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+ else
+ fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_updatevar(int con, struct fb_info *info)
+{
+ matrox_pan_var(&fb_display[con].var, (struct matrox_fb_info*)info);
+ return 0;
+}
+
+static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
+ int bppshft2;
+
+ bppshft2 = bpp;
+ if (isInterleave(MINFO))
+ bppshft2 >>= 1;
+ if (ACCESS_FBINFO(devflags.video64bits))
+ bppshft2 >>= 1;
+ return bppshft2;
+}
+
+static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
+ int over;
+ int rounding;
+
+ switch (bpp) {
+ case 4: rounding = 128;
+ break;
+ case 8: rounding = 64;
+ break;
+ case 16: rounding = 32;
+ break;
+ case 24: rounding = 64;
+ break;
+ default: rounding = 16;
+ break;
+ }
+ if (isInterleave(MINFO)) {
+ rounding *= 2;
+ }
+ over = xres % rounding;
+ if (over)
+ xres += rounding-over;
+ return xres;
+}
+
+static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
+ const int* width;
+ int xres_new;
+
+ width = ACCESS_FBINFO(capable.vxres);
+
+ if (ACCESS_FBINFO(devflags.precise_width)) {
+ while (*width) {
+ if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
+ break;
+ }
+ width++;
+ }
+ xres_new = *width;
+ } else {
+ xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
+ }
+ if (!xres_new) return 0;
+ if (xres != xres_new) {
+ printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
+ }
+ return xres_new;
+}
+
+#ifdef NEED_DAC1064
+static void outDAC1064(CPMINFO int reg, int val) {
+ mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+ mga_outb(M_RAMDAC_BASE+M1064_X_DATAREG, val);
+}
+
+static int inDAC1064(CPMINFO int reg) {
+ mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg);
+ return mga_inb(M_RAMDAC_BASE+M1064_X_DATAREG);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
+ TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
+ TVP3026_XPALETTEPAGE,
+ TVP3026_XGENCTRL,
+ TVP3026_XMISCCTRL,
+ TVP3026_XGENIOCTRL,
+ TVP3026_XGENIODATA,
+ TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+ TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+ TVP3026_XCOLKEYCTRL,
+ TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL 0
+#define POS3026_XTRUECOLORCTRL 1
+#define POS3026_XMUXCTRL 2
+#define POS3026_XCLKCTRL 3
+#define POS3026_XGENCTRL 5
+#define POS3026_XMISCCTRL 6
+#define POS3026_XMEMPLLCTRL 18
+#define POS3026_XCURCTRL 20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+ 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
+ 0x00,
+ TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
+ TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
+ 0x00,
+ 0x1E,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ TVP3026_XCOLKEYCTRL_ZOOM1,
+ 0x00, 0x00, TVP3026_XCURCTRL_DIS };
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+
+static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+ unsigned int bestdiff = ~0;
+ unsigned int bestvco = 0;
+ unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq);
+ unsigned int fwant;
+ int p;
+
+ fwant = freq;
+
+#ifdef DEBUG
+ printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max));
+ printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq));
+ printk(KERN_ERR "freq: %d\n", freq);
+ printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min));
+ printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min));
+ printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max));
+ printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min));
+ printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max));
+ printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+ for (p = 0; p < ACCESS_FBINFO(features.pll.post_shift_max); p++) {
+ if (fwant * 2 > fmax)
+ break;
+ fwant *= 2;
+ }
+ if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min);
+ if (fwant > fmax) fwant = fmax;
+ for (; p >= 0; fwant >>= 1, bestdiff >>= 1, --p) {
+ int m;
+
+ if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break;
+ for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) {
+ unsigned int diff, fvco;
+ int n;
+
+ n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+ if (n > ACCESS_FBINFO(features.pll.feed_div_max))
+ break;
+ if (n < ACCESS_FBINFO(features.pll.feed_div_min))
+ n = ACCESS_FBINFO(features.pll.feed_div_min);
+ fvco = (fxtal * (n + 1)) / (m + 1);
+ if (fvco < fwant)
+ diff = fwant - fvco;
+ else
+ diff = fvco - fwant;
+ if (diff < bestdiff) {
+ bestdiff = diff;
+ *post = p;
+ *in = m;
+ *feed = n;
+ bestvco = fvco;
+ }
+ }
+ }
+ dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+ return bestvco;
+}
+
+#ifdef NEED_DAC1064
+static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+ unsigned int fvco;
+ unsigned int p;
+
+ fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
+ p = (1 << p) - 1;
+ if (fvco <= 100000)
+ ;
+ else if (fvco <= 140000)
+ p |= 0x08;
+ else if (fvco <= 180000)
+ p |= 0x10;
+ else
+ p |= 0x18;
+ *post = p;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
+ unsigned int fvco;
+ unsigned int lin, lfeed, lpost;
+
+ fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
+ fvco >>= (*post = lpost);
+ *in = 64 - lin;
+ *feed = 64 - lfeed;
+ return fvco;
+}
+
+static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, int Bpp) {
+ unsigned int f_pll;
+ unsigned int pixfeed, pixin, pixpost;
+ unsigned int loopfeed, loopin, looppost, loopdiv, z;
+
+ f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
+
+ hw->DACclk[0] = pixin | 0xC0;
+ hw->DACclk[1] = pixfeed;
+ hw->DACclk[2] = pixpost | 0xB0;
+ if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+ loopfeed = 3; /* set lm to any possible value */
+ loopin = 3 * 32 / Bpp;
+ } else {
+ loopfeed = 4;
+ loopin = 4 * 32 / Bpp;
+ }
+ z = (110000 * loopin) / (f_pll * loopfeed);
+ loopdiv = 0; /* div 2 */
+ if (z < 2)
+ looppost = 0;
+ else if (z < 4)
+ looppost = 1;
+ else if (z < 8)
+ looppost = 2;
+ else {
+ looppost = 3;
+ loopdiv = z/16;
+ }
+ if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) {
+ hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+ hw->DACclk[4] = (65 - loopfeed) | 0x80;
+ if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
+ if (isInterleave(MINFO))
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+ else {
+ hw->DACclk[4] &= ~0xC0;
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+ }
+ }
+ hw->DACclk[5] = looppost | 0xF8;
+ if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
+ hw->DACclk[5] ^= 0x40;
+ } else {
+ hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+ hw->DACclk[4] = 65 - loopfeed;
+ hw->DACclk[5] = looppost | 0xF0;
+ }
+ hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+ return 0;
+}
+#endif
+
+static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+ unsigned int pixclock = var->pixclock;
+ if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
+ mt->pixclock = 1000000000 / pixclock;
+ if (mt->pixclock < 1) mt->pixclock = 1;
+ mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+ mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+ mt->HDisplay = var->xres;
+ mt->HSyncStart = mt->HDisplay + var->right_margin;
+ mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+ mt->HTotal = mt->HSyncEnd + var->left_margin;
+ mt->VDisplay = var->yres;
+ mt->VSyncStart = mt->VDisplay + var->lower_margin;
+ mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+ mt->VTotal = mt->VSyncEnd + var->upper_margin;
+ mt->sync = var->sync;
+}
+
+static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ unsigned int hd, hs, he, ht;
+ unsigned int vd, vs, ve, vt;
+ unsigned int wd;
+ unsigned int divider;
+ int i;
+
+ hw->SEQ[0] = 0x00;
+ hw->SEQ[1] = 0x01; /* or 0x09 */
+ hw->SEQ[2] = 0x0F; /* bitplanes */
+ hw->SEQ[3] = 0x00;
+ hw->SEQ[4] = 0x0E;
+ /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */
+ if (m->dblscan) {
+ m->VTotal <<= 1;
+ m->VDisplay <<= 1;
+ m->VSyncStart <<= 1;
+ m->VSyncEnd <<= 1;
+ }
+ if (m->interlaced) {
+ m->VTotal >>= 1;
+ m->VDisplay >>= 1;
+ m->VSyncStart >>= 1;
+ m->VSyncEnd >>= 1;
+ }
+
+ /* GCTL is ignored when not using 0xA0000 aperture */
+ hw->GCTL[0] = 0x00;
+ hw->GCTL[1] = 0x00;
+ hw->GCTL[2] = 0x00;
+ hw->GCTL[3] = 0x00;
+ hw->GCTL[4] = 0x00;
+ hw->GCTL[5] = 0x40;
+ hw->GCTL[6] = 0x05;
+ hw->GCTL[7] = 0x0F;
+ hw->GCTL[8] = 0xFF;
+
+ /* Whole ATTR is ignored in PowerGraphics mode */
+ for (i = 0; i < 16; i++)
+ hw->ATTR[i] = i;
+ hw->ATTR[16] = 0x41;
+ hw->ATTR[17] = 0xFF;
+ hw->ATTR[18] = 0x0F;
+ hw->ATTR[19] = 0x00;
+ hw->ATTR[20] = 0x00;
+
+ hd = m->HDisplay >> 3;
+ hs = m->HSyncStart >> 3;
+ he = m->HSyncEnd >> 3;
+ ht = m->HTotal >> 3;
+ /* standard timmings are in 8pixels, but for interleaved we cannot */
+ /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+ /* using 16 or more pixels per unit can save us */
+ divider = ACCESS_FBINFO(curr.final_bppShift);
+ while (divider & 3) {
+ hd >>= 1;
+ hs >>= 1;
+ he >>= 1;
+ ht >>= 1;
+ divider <<= 1;
+ }
+ divider = divider / 4;
+ /* divider can be from 1 to 8 */
+ while (divider > 8) {
+ hd <<= 1;
+ hs <<= 1;
+ he <<= 1;
+ ht <<= 1;
+ divider >>= 1;
+ }
+ hd = hd - 1;
+ hs = hs - 1;
+ he = he - 1;
+ ht = ht - 1;
+ vd = m->VDisplay - 1;
+ vs = m->VSyncStart - 1;
+ ve = m->VSyncEnd - 1;
+ vt = m->VTotal - 2;
+ if (((ht & 0x0F) == 0x0E) || ((ht & 0x0F) == 0x04))
+ ht++;
+ wd = ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.final_bppShift) / 64;
+
+ hw->CRTCEXT[0] = 0;
+ hw->CRTCEXT[5] = 0;
+ if (m->interlaced) {
+ hw->CRTCEXT[0] = 0x80;
+ hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+ if (!m->dblscan)
+ wd <<= 1;
+ vt &= ~1;
+ }
+ hw->CRTCEXT[0] |= (wd & 0x300) >> 4;
+ hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+ ((hd & 0x100) >> 7) | /* blanking */
+ ((hs & 0x100) >> 6) | /* sync start */
+ (ht & 0x040); /* end hor. blanking */
+ hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
+ ((vd & 0x400) >> 8) | /* disp end */
+ ((vd & 0xC00) >> 7) | /* vblanking start */
+ ((vs & 0xC00) >> 5);
+ hw->CRTCEXT[3] = (divider - 1) | 0x80;
+ hw->CRTCEXT[4] = 0;
+
+ hw->CRTC[0] = ht-4;
+ hw->CRTC[1] = hd;
+ hw->CRTC[2] = hd;
+ hw->CRTC[3] = (ht & 0x1F) | 0x80;
+ hw->CRTC[4] = hs;
+ hw->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F);
+ hw->CRTC[6] = vt & 0xFF;
+ hw->CRTC[7] = ((vt & 0x100) >> 8) |
+ ((vd & 0x100) >> 7) |
+ ((vs & 0x100) >> 6) |
+ ((vd & 0x100) >> 5) |
+ 0x10 |
+ ((vt & 0x200) >> 4) |
+ ((vd & 0x200) >> 3) |
+ ((vs & 0x200) >> 2);
+ hw->CRTC[8] = 0x00;
+ hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
+ if (m->dblscan && !m->interlaced)
+ hw->CRTC[9] |= 0x80;
+ for (i = 10; i < 16; i++)
+ hw->CRTC[i] = 0x00;
+ hw->CRTC[16] = vs /* & 0xFF */;
+ hw->CRTC[17] = (ve & 0x0F) | 0x20;
+ hw->CRTC[18] = vd /* & 0xFF */;
+ hw->CRTC[19] = wd /* & 0xFF */;
+ hw->CRTC[20] = 0x00;
+ hw->CRTC[21] = vd /* & 0xFF */;
+ hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+ hw->CRTC[23] = 0xC3;
+ hw->CRTC[24] = 0xFF;
+ return 0;
+};
+
+#ifdef NEED_DAC1064
+
+static const unsigned char MGA1064_DAC_regs[] = {
+ M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+ M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+ M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+ M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
+ DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
+ M1064_XMISCCTRL,
+ M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
+ M1064_XCRCBITSEL,
+ M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+#define POS1064_XVREFCTRL 12
+#define POS1064_XMULCTRL 13
+#define POS1064_XGENCTRL 15
+
+static const unsigned char MGA1064_DAC[] = {
+ 0xFF, 0x1F/*Memsizedependent*/, M1064_XCURCTRL_DIS,
+ 0x00, 0x00, 0x00, /* black */
+ 0xFF, 0xFF, 0xFF, /* white */
+ 0xFF, 0x00, 0x00, /* red */
+ 0x00, 0,
+ M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
+ M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
+ M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_VGA | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN,
+ 0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
+ 0x00,
+ 0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
+ unsigned int m, n, p;
+
+ DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ hw->DACclk[0] = m;
+ hw->DACclk[1] = n;
+ hw->DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem) {
+ u_int32_t mx;
+
+ mx = hw->MXoptionReg | 0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x000000BB;
+ if (oscinfo & DAC1064_OPT_GDIV1)
+ mx |= 0x00000008;
+ if (oscinfo & DAC1064_OPT_MDIV1)
+ mx |= 0x00000010;
+ if (oscinfo & DAC1064_OPT_RESERVED)
+ mx |= 0x00000080;
+ if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+ /* select PCI clock until we have setup oscilator... */
+ int clk;
+ unsigned int m, n, p;
+
+ /* powerup system PLL, select PCI clock */
+ mx |= 0x00000020;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+
+ /* !!! you must not access device if MCLK is not running !!!
+ Doing so cause immediate PCI lockup :-( Maybe they should
+ generate ABORT or I/O (parity...) error and Linux should
+ recover from this... (kill driver/process). But world is not
+ perfect... */
+ /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+ select PLL... because of PLL can be stopped at this time) */
+ DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+ outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+ outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+ for (clk = 65536; clk; --clk) {
+ if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+ break;
+ }
+ if (!clk)
+ printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+ /* select PLL */
+ mx |= 0x00000005;
+ } else {
+ /* select specified system clock source */
+ mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+ }
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ hw->MXoptionReg = mx;
+}
+
+static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+ switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+ /* case 4: not supported by MGA1064 DAC */
+ case 8:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 16:
+ if (ACCESS_FBINFO(curr.var.green.length) == 5)
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ else
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 24:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 32:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ default:
+ return 1; /* unsupported depth */
+ }
+ hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
+ hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+ hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+ return 0;
+}
+
+static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ DAC1064_setpclk(PMINFO hw, m->pixclock);
+ if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 16) { /* 256 entries */
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ hw->DACpal[i * 3 + 0] = i;
+ hw->DACpal[i * 3 + 1] = i;
+ hw->DACpal[i * 3 + 2] = i;
+ }
+ } else if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 8) {
+ if (ACCESS_FBINFO(curr.var.green.length) == 5) { /* 0..31, 128..159 */
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ /* with p15 == 0 */
+ hw->DACpal[i * 3 + 0] = i << 3;
+ hw->DACpal[i * 3 + 1] = i << 3;
+ hw->DACpal[i * 3 + 2] = i << 3;
+ /* with p15 == 1 */
+ hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+ hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+ hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+ }
+ } else {
+ int i;
+
+ for (i = 0; i < 64; i++) { /* 0..63 */
+ hw->DACpal[i * 3 + 0] = i << 3;
+ hw->DACpal[i * 3 + 1] = i << 2;
+ hw->DACpal[i * 3 + 2] = i << 3;
+ }
+ }
+ } else {
+ memset(hw->DACpal, 0, 768);
+ }
+ return 0;
+}
+
+static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
+ outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
+ outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
+ if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
+ int i;
+
+ for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
+ outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
+ }
+}
+
+static void DAC1064_restore_2(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+ int i;
+ for (i = 0; i < 3; i++)
+ outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
+ while (!(inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40));
+#ifdef DEBUG
+ dprintk(KERN_DEBUG "DAC1064regs ");
+ for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+ dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
+ if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+ }
+ dprintk("\n" KERN_DEBUG "DAC1064clk ");
+ for (i = 0; i < 6; i++)
+ dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+ dprintk("\n");
+#endif
+}
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ if (DAC1064_init_1(PMINFO hw, m)) return 1;
+ if (vgaHWinit(PMINFO hw, m)) return 1;
+
+ hw->MiscOutReg = 0xCB;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->MiscOutReg &= ~0x40;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->MiscOutReg &= ~0x80;
+ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+ hw->CRTCEXT[3] |= 0x40;
+
+ if (DAC1064_init_2(PMINFO hw, m)) return 1;
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ if (DAC1064_init_1(PMINFO hw, m)) return 1;
+ hw->MXoptionReg &= ~0x2000;
+ if (vgaHWinit(PMINFO hw, m)) return 1;
+
+ hw->MiscOutReg = 0xEF;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->MiscOutReg &= ~0x40;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->MiscOutReg &= ~0x80;
+ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+ hw->CRTCEXT[3] |= 0x40;
+
+ if (DAC1064_init_2(PMINFO hw, m)) return 1;
+ return 0;
+}
+#endif /* G100 */
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) {
+ u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+
+ memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+ switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+ case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+ hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+ break;
+ case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+ hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+ break;
+ case 16:
+ /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(curr.var.green.length) == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+ break;
+ case 24:
+ /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+ break;
+ case 32:
+ /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+ break;
+ default:
+ return 1; /* TODO: failed */
+ }
+ if (vgaHWinit(PMINFO hw, m)) return 1;
+
+ /* set SYNC */
+ hw->MiscOutReg = 0xCB;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+ if (m->sync & FB_SYNC_ON_GREEN)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+ /* set DELAY */
+ if (ACCESS_FBINFO(video_len) < 0x400000)
+ hw->CRTCEXT[3] |= 0x08;
+ else if (ACCESS_FBINFO(video_len) > 0x400000)
+ hw->CRTCEXT[3] |= 0x10;
+
+ /* set HWCURSOR */
+ if (m->interlaced) {
+ hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+ }
+
+ /* set interleaving */
+ hw->MXoptionReg &= ~0x00001000;
+ if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+
+ /* set DAC */
+ Ti3026_setpclk(PMINFO hw, m->pixclock, ACCESS_FBINFO(curr.final_bppShift));
+ return 0;
+}
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ return 16; /* pseudocolor... 16 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ return 256; /* pseudocolor... 256 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+ }
+ return 16; /* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len) {
+ unsigned int vramlen;
+ unsigned int memlen;
+
+ if ((var->xres > var->xres_virtual) || (var->yres > var->yres_virtual) ||
+ (var->xoffset > var->xres_virtual) || (var->yoffset > var->yres_virtual))
+ return -EINVAL;
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8: break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16: break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24: break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32: break;
+#endif
+ default: return -EINVAL;
+ }
+ vramlen = ACCESS_FBINFO(video_len);
+ if (vramlen > 0x800000) vramlen = 0x800000;
+ var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
+ memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+ if (memlen > vramlen)
+ return -EINVAL; /* out of memory */
+ /* There is hardware bug that no line can cross 4MB boundary */
+ /* give up for CFB24, it is impossible to easy workaround it */
+ /* for other try to do something */
+ if ((memlen > 0x400000) && (var->bits_per_pixel != 24)) {
+ int new_xres = var->xres_virtual;
+
+ if (new_xres <= 512)
+ new_xres = 512;
+ else if (new_xres <= 1024)
+ new_xres = 1024;
+ else if (new_xres <= 2048)
+ new_xres = 2048;
+ else
+ new_xres = var->xres_virtual;
+ memlen = new_xres * var->bits_per_pixel / 8;
+ /* if now out of memory, try shrink virtual height */
+ /* but if new virtual height is smaller than visible height, return -EINVAL */
+ if (var->yres_virtual * memlen > vramlen) {
+ int new_yres;
+
+ new_yres = vramlen / memlen;
+ if (new_yres < var->yres)
+ return -EINVAL;
+ var->yres_virtual = new_yres;
+ }
+ var->xres_virtual = new_xres;
+ }
+
+ if (var->bits_per_pixel == 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;
+ *visual = MX_VISUAL_PSEUDOCOLOR;
+ } else if (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;
+ *visual = MX_VISUAL_PSEUDOCOLOR;
+ } else {
+ if (var->bits_per_pixel <= 16) {
+ if (var->green.length == 5) {
+ 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 = 15;
+ var->transp.length = 1;
+ } else {
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ } else if (var->bits_per_pixel <= 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;
+ } else {
+ 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;
+ }
+ dprintk("matroxfb: truecolor: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ var->transp.length,
+ var->red.length,
+ var->green.length,
+ var->blue.length,
+ var->transp.offset,
+ var->red.offset,
+ var->green.offset,
+ var->blue.offset);
+ *visual = MX_VISUAL_DIRECTCOLOR;
+ }
+ *video_cmap_len = matroxfb_get_cmap_len(var);
+ dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual);
+ return 0;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+ unsigned int f_pll;
+ unsigned int pclk_m, pclk_n, pclk_p;
+ unsigned int mclk_m, mclk_n, mclk_p;
+ unsigned int rfhcnt, mclk_ctl;
+ int tmout;
+
+ f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
+
+ /* save pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
+ pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+
+ /* stop pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ /* set pclk to new mclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ };
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+ /* output pclk on mclk pin */
+ mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+ /* stop MCLK */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
+
+ /* set mclk to new freq */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+ f_pll = f_pll * 333 / (10000 << mclk_p);
+ if (isMilleniumII(MINFO)) {
+ rfhcnt = (f_pll - 128) / 256;
+ if (rfhcnt > 15)
+ rfhcnt = 15;
+ } else {
+ rfhcnt = (f_pll - 64) / 128;
+ if (rfhcnt > 15)
+ rfhcnt = 0;
+ }
+ hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ /* output MCLK to MCLK pin */
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+ /* stop PCLK */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ /* restore pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 114545;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 2;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 24;
+ ACCESS_FBINFO(features.pll.in_div_min) = 2;
+ ACCESS_FBINFO(features.pll.in_div_max) = 63;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ ACCESS_FBINFO(max_pixel_clock) = 220000;
+ ti3026_setMCLK(PMINFO hw, 60000);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+ unsigned char rev;
+
+ /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 50000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 14318;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 100;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+ ACCESS_FBINFO(features.pll.in_div_min) = 1;
+ ACCESS_FBINFO(features.pll.in_div_max) = 31;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
+ /* I hope */
+ pci_read_config_byte(ACCESS_FBINFO(pcidev), PCI_REVISION_ID, &rev);
+ if (rev < 3)
+ ACCESS_FBINFO(max_pixel_clock) = 170000;
+ else
+ ACCESS_FBINFO(max_pixel_clock) = 220000;
+ /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+ DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+
+__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+ static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+ /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+ ACCESS_FBINFO(capable.vxres) = vxres_mystique;
+ ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x00094E20;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+ mga_outl(M_CTLWTST, 0x00000000);
+ udelay(200);
+ mga_outl(M_MACCESS, 0x00008000);
+ udelay(100);
+ mga_outl(M_MACCESS, 0x0000C000);
+ return 0;
+}
+
+__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+ MGA1064_ramdac_init(PMINFO hw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+/* BIOS environ */
+static int x7AF4 = 0; /* flags */
+#if 0
+static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+#if 0
+__initfunc(static int G100_ReadFeatureConn(const struct matrox_fb_info* minfo)) {
+ int ret;
+
+ mga_outb(M_3DA_WR, 0x01);
+ ret = (mga_inb(M_3C2_RD) >> 5) & 0x03;
+ mga_outb(M_3DA_WR, 0x02);
+ return ret | ((mga_inb(M_3C2_RD) >> 3) & 0x0C);
+}
+#endif
+
+__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+ int reg;
+ int selClk;
+ int clk;
+
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS);
+ switch (flags & 3) {
+ case 0: reg = M1064_XPIXPLLAM; break;
+ case 1: reg = M1064_XPIXPLLBM; break;
+ default: reg = M1064_XPIXPLLCM; break;
+ }
+ outDAC1064(PMINFO reg++, m);
+ outDAC1064(PMINFO reg++, n);
+ outDAC1064(PMINFO reg, p);
+ selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+ /* there should be flags & 0x03 & case 0/1/else */
+ /* and we should first select source and after that we should wait for PLL */
+ /* and we are waiting for PLL with oscilator disabled... Is it right? */
+ switch (flags & 0x03) {
+ case 0x00: break;
+ case 0x01: selClk |= 4; break;
+ default: selClk |= 0x0C; break;
+ }
+ mga_outb(M_MISC_REG, selClk);
+ for (clk = 65536; clk; clk--)
+ if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+ break;
+ if (!clk)
+ printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+ selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+ switch (flags & 0x0C) {
+ case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+ case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+ default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+ }
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+ unsigned int m, n, p;
+
+ DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ MGAG100_progPixClock(PMINFO flags, m, n, p);
+}
+
+__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+ static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+#if 0
+ u_int32_t reg50;
+ u_int32_t q;
+#endif
+
+ /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+ ACCESS_FBINFO(capable.vxres) = vxres_g100;
+ ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x00078C20;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ mga_outl(M_CTLWTST, 0x03258A31); /* 03258A31 is x7AF0, default is 0x02032521 */
+#if 0
+ hw->MXoptionReg |= 0x1000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50);
+ q = def50 & 0x3000;
+ reg50 = (reg50 & ~0x3000) | q;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
+ mga_outb(0x1C05, 0x00);
+ mga_outb(0x1C05, 0x80);
+ udelay(100);
+ mga_outb(0x1C05, 0x40);
+ mga_outb(0x1C05, 0xC0);
+ pci_write_config_byte(ACCESS_FBINFO(pcidev), 0x50, def50 & 0x0F);
+ {
+ volatile u_int8_t* ptr;
+ mga_outb(M_GRAPHICS_INDEX, 6);
+ mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+ mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+ mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+ ptr = ACCESS_FBINFO(video_vbase);
+ ptr[0x000] = 0xAA;
+ ptr[0x800] = 0x55;
+ if (ptr[0x000] != 0xAA) {
+ hw->MXoptionReg &= ~0x1000;
+ }
+ }
+#endif
+ hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
+#if 0
+ if (!(x7AF4 & 0x10))
+ hw->MXoptionReg |= 0x4000;
+#endif
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ return 0;
+}
+
+__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+ u_int8_t b;
+
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 50000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 27000;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 7;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+ ACCESS_FBINFO(features.pll.in_div_min) = 1;
+ ACCESS_FBINFO(features.pll.in_div_max) = 31;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
+ ACCESS_FBINFO(max_pixel_clock) = 220000;
+
+ {
+#ifdef G100_BROKEN_IBM_82351
+ u_int32_t d;
+
+ find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+ pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+ if (b == ACCESS_FBINFO(pcidev)->bus->number) {
+ pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
+ pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
+ pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
+ pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
+ }
+#endif
+ if (x7AF4 & 8) {
+ hw->MXoptionReg |= 0x40;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ }
+ mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
+ }
+ DAC1064_setmclk(PMINFO hw, DAC1064_OPT_SCLK_PLL, 120000);
+ MGAG100_setPixClock(PMINFO 4, 25175);
+ MGAG100_setPixClock(PMINFO 5, 28322);
+ if (x7AF4 & 0x10) {
+ b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
+ outDAC1064(PMINFO M1064_XGENIODATA, b);
+ b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
+ outDAC1064(PMINFO M1064_XGENIOCTRL, b);
+ }
+}
+#endif
+
+static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
+ int i;
+
+ dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+ dprintk(KERN_INFO "SEQ regs: ");
+ for (i = 0; i < 5; i++)
+ dprintk("%02X:", hw->SEQ[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "GDC regs: ");
+ for (i = 0; i < 9; i++)
+ dprintk("%02X:", hw->GCTL[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "CRTC regs: ");
+ for (i = 0; i < 25; i++)
+ dprintk("%02X:", hw->CRTC[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "ATTR regs: ");
+ for (i = 0; i < 21; i++)
+ dprintk("%02X:", hw->ATTR[i]);
+ dprintk("\n");
+
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, 0);
+ mga_outb(M_MISC_REG, hw->MiscOutReg);
+ for (i = 1; i < 5; i++)
+ mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+ mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+ for (i = 0; i < 25; i++)
+ mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+ for (i = 0; i < 9; i++)
+ mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+ for (i = 0; i < 21; i++) {
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, i);
+ mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+ }
+ mga_outb(M_PALETTE_MASK, 0xFF);
+ mga_outb(M_DAC_REG, 0x00);
+ for (i = 0; i < 768; i++)
+ mga_outb(M_DAC_VAL, hw->DACpal[i]);
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, 0x20);
+}
+
+static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info)
+{
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+#endif
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= ACCESS_FBINFO(curr.cmap_len))
+ return 1;
+
+ ACCESS_FBINFO(palette[regno].red) = red;
+ ACCESS_FBINFO(palette[regno].green) = green;
+ ACCESS_FBINFO(palette[regno].blue) = blue;
+ ACCESS_FBINFO(palette[regno].transp) = transp;
+
+ red = CNVT_TOHW(red, ACCESS_FBINFO(curr.var.red.length));
+ green = CNVT_TOHW(green, ACCESS_FBINFO(curr.var.green.length));
+ blue = CNVT_TOHW(blue, ACCESS_FBINFO(curr.var.blue.length));
+ transp = CNVT_TOHW(transp, ACCESS_FBINFO(curr.var.transp.length));
+
+ switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) {
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4)
+#ifdef FBCON_HAS_CFB4
+ case 4:
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+#endif
+ mga_outb(M_DAC_REG, regno);
+ mga_outb(M_DAC_VAL, red);
+ mga_outb(M_DAC_VAL, green);
+ mga_outb(M_DAC_VAL, blue);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ ACCESS_FBINFO(cmap.cfb16[regno]) =
+ (red << ACCESS_FBINFO(curr.var.red.offset)) |
+ (green << ACCESS_FBINFO(curr.var.green.offset)) |
+ (blue << ACCESS_FBINFO(curr.var.blue.offset)) |
+ (transp << ACCESS_FBINFO(curr.var.transp.offset)); /* for 1:5:5:5 */
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ ACCESS_FBINFO(cmap.cfb24[regno]) =
+ (red << ACCESS_FBINFO(curr.var.red.offset)) |
+ (green << ACCESS_FBINFO(curr.var.green.offset)) |
+ (blue << ACCESS_FBINFO(curr.var.blue.offset));
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ ACCESS_FBINFO(cmap.cfb32[regno]) =
+ (red << ACCESS_FBINFO(curr.var.red.offset)) |
+ (green << ACCESS_FBINFO(curr.var.green.offset)) |
+ (blue << ACCESS_FBINFO(curr.var.blue.offset)) |
+ (transp << ACCESS_FBINFO(curr.var.transp.offset)); /* 8:8:8:8 */
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(WPMINFO int con)
+{
+ struct display* dsp;
+
+ if (con != ACCESS_FBINFO(currcon))
+ return;
+ if (con >= 0)
+ dsp = fb_display+con;
+ else
+ dsp = ACCESS_FBINFO(fbcon.disp);
+ if (dsp->cmap.len)
+ fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+ else
+ fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
+ 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+}
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ mga_outb(M_IEN, 0x00);
+ mga_outb(M_CACHEFLUSH, 0x00);
+ DAC1064_restore_1(PMINFO hw, oldhw);
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+ vgaHWrestore(PMINFO hw, oldhw);
+ DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ DAC1064_restore_1(PMINFO hw, oldhw);
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+ vgaHWrestore(PMINFO hw, oldhw);
+ DAC1064_restore_2(PMINFO hw, oldhw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+
+ dprintk(KERN_INFO "EXTVGA regs: ");
+ for (i = 0; i < 6; i++)
+ dprintk("%02X:", hw->CRTCEXT[i]);
+ dprintk("\n");
+
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ vgaHWrestore(PMINFO hw, oldhw);
+
+ for (i = 0; i < 21; i++) {
+ outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
+ }
+ if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
+ /* agrhh... setting up PLL is very slow on Millenium... */
+ /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
+ /* Maybe even we should call schedule() ? */
+
+ outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
+
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+ for (i = 0; i < 3; i++)
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+ /* wait for PLL only if PLL clock requested (always for PowerMode) */
+ if (hw->MiscOutReg & 0x08) {
+ int tmout;
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+ for (tmout = 500000; tmout; --tmout) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+ else
+ dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+ }
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+ for (i = 3; i < 6; i++)
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+ if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[3] & 0xC0) == 0xC0)) {
+ int tmout;
+
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+ for (tmout = 500000; tmout; --tmout) {
+ if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+ else
+ dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+ }
+ }
+ matroxfb_ti3026_createcursor(PMINFO fontwidth(p), fontheight(p));
+
+ dprintk(KERN_DEBUG "3026DACregs ");
+ for (i = 0; i < 21; i++) {
+ dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+ if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+ }
+ dprintk("\n" KERN_DEBUG "DACclk ");
+ for (i = 0; i < 6; i++)
+ dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+ dprintk("\n");
+}
+#endif
+
+static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id,"MATROX");
+
+ fix->smem_start = (void*)ACCESS_FBINFO(video_base);
+ fix->smem_len = ACCESS_FBINFO(video_len);
+ fix->type = ACCESS_FBINFO(curr.video_type);
+ fix->visual = ACCESS_FBINFO(curr.visual);
+ fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = (ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.var.bits_per_pixel)) >> 3;
+ fix->mmio_start = (void*)ACCESS_FBINFO(mmio_base);
+ fix->mmio_len = ACCESS_FBINFO(mmio_len);
+ fix->accel = ACCESS_FBINFO(devflags.accelerator);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if(con < 0)
+ *var=ACCESS_FBINFO2(info, curr.var);
+ else
+ *var=fb_display[con].var;
+ return 0;
+}
+
+static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ int err;
+ int visual;
+ int cmap_len;
+ struct display* display;
+ int chgvar;
+
+ if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len)) != 0)
+ return err;
+ switch (var->activate & FB_ACTIVATE_MASK) {
+ case FB_ACTIVATE_TEST: return 0;
+ case FB_ACTIVATE_NXTOPEN: /* ?? */
+ case FB_ACTIVATE_NOW: break; /* continue */
+ default: return -EINVAL; /* unknown */
+ }
+ if (con >= 0) {
+ display = fb_display+con;
+ chgvar = ((display->var.xres != var->xres) ||
+ (display->var.yres != var->yres) ||
+ (display->var.xres_virtual != var->xres_virtual) ||
+ (display->var.yres_virtual != var->yres_virtual) ||
+ (display->var.bits_per_pixel != var->bits_per_pixel) ||
+ memcmp(&display->var.red, &var->red, sizeof(var->red)) ||
+ memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
+ memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
+ } else {
+ display = ACCESS_FBINFO(fbcon.disp);
+ chgvar = 0;
+ }
+ display->var = *var;
+ /* cmap */
+ display->screen_base = ACCESS_FBINFO(video_vbase);
+ display->visual = visual;
+ display->type = FB_TYPE_PACKED_PIXELS;
+ display->type_aux = 0;
+ display->ypanstep = 1;
+ display->ywrapstep = 0;
+ display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+ display->can_soft_blank = 1;
+ display->inverse = ACCESS_FBINFO(devflags.inverse);
+ /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
+ /* next_plane, fontdata, _font*, userfont */
+ initMatrox(PMINFO con, display); /* dispsw */
+ /* dispsw, scrollmode, yscroll */
+ /* fgshift, bgshift, charmask */
+ if (chgvar && info && info->changevar)
+ info->changevar(con);
+ if (con == ACCESS_FBINFO(currcon)) {
+ unsigned int pos;
+
+ ACCESS_FBINFO(curr.var) = *var;
+ ACCESS_FBINFO(curr.visual) = visual;
+ ACCESS_FBINFO(curr.cmap_len) = cmap_len;
+ ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
+ if (visual == MX_VISUAL_PSEUDOCOLOR) {
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ int j;
+
+ j = color_table[i];
+ ACCESS_FBINFO(palette[i].red) = default_red[j];
+ ACCESS_FBINFO(palette[i].green) = default_grn[j];
+ ACCESS_FBINFO(palette[i].blue) = default_blu[j];
+ }
+ }
+
+ { struct my_timming mt;
+ struct matrox_hw_state* hw;
+ struct matrox_hw_state* ohw;
+
+ var2my(var, &mt);
+ hw = ACCESS_FBINFO(newhw);
+ ohw = ACCESS_FBINFO(currenthw);
+
+ /* MXoptionReg is not set from scratch */
+ hw->MXoptionReg = ohw->MXoptionReg;
+ /* DACclk[3]..[5] are not initialized with DAC1064 */
+ memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk));
+ /* others are initialized by init() */
+
+ ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt));
+ pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+ if (mga_ydstorg(MINFO)) {
+ if (isInterleave(MINFO))
+ pos += mga_ydstorg(MINFO) >> 3;
+ else
+ pos += mga_ydstorg(MINFO) >> 2;
+ }
+
+ hw->CRTC[0x0D] = pos & 0xFF;
+ hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+ hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+ ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
+ ACCESS_FBINFO(currenthw) = hw;
+ ACCESS_FBINFO(newhw) = ohw;
+ matrox_cfbX_init(MINFO);
+ do_install_cmap(PMINFO con);
+ }
+ }
+ return 0;
+#undef minfo
+}
+
+static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ if (regno >= ACCESS_FBINFO(curr.cmap_len))
+ return 1;
+
+ *red = ACCESS_FBINFO(palette[regno].red);
+ *green = ACCESS_FBINFO(palette[regno].green);
+ *blue = ACCESS_FBINFO(palette[regno].blue);
+ *transp = ACCESS_FBINFO(palette[regno].transp);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ struct display* dsp = (con < 0) ? info->disp : fb_display+con;
+
+ if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */
+ return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
+ else if (dsp->cmap.len) /* non default colormap? */
+ fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
+ cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int cmap_len;
+ struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
+
+ cmap_len = matroxfb_get_cmap_len(&dsp->var);
+ if (dsp->cmap.len != cmap_len) {
+ int err;
+
+ err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
+ if (err)
+ return err;
+ }
+ if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */
+ return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int matroxfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+static struct fb_ops matroxfb_ops = {
+ matroxfb_open,
+ matroxfb_release,
+ matroxfb_get_fix,
+ matroxfb_get_var,
+ matroxfb_set_var,
+ matroxfb_get_cmap,
+ matroxfb_set_cmap,
+ matroxfb_pan_display,
+ matroxfb_ioctl,
+ NULL /* mmap */
+};
+
+static int matroxfb_switch(int con, struct fb_info *info)
+{
+ struct fb_cmap* cmap;
+ if (ACCESS_FBINFO2(info, currcon) >= 0) {
+ /* Do we have to save the colormap? */
+ cmap = &fb_display[ACCESS_FBINFO2(info, currcon)].cmap;
+ dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO2(info, currcon), cmap->len);
+
+ if (cmap->len) {
+ dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ fb_get_cmap(cmap, 1, matrox_getcolreg, info);
+#ifdef DEBUG
+ if (cmap->red) {
+ dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
+ }
+#endif
+ }
+ }
+ ACCESS_FBINFO2(info, currcon) = con;
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+#ifdef DEBUG
+ cmap = &fb_display[con].cmap;
+ dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
+ dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ if (fb_display[con].cmap.red) {
+ dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
+ }
+#endif
+ matroxfb_set_var(&fb_display[con].var, con, info);
+#ifdef DEBUG
+ dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
+ dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ if (fb_display[con].cmap.red) {
+ dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
+ }
+#endif
+ return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ int seq;
+ int crtc;
+
+ switch (blank) {
+ case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */
+ case 2: seq = 0x20; crtc = 0x10; break;
+ case 3: seq = 0x20; crtc = 0x20; break;
+ case 4: seq = 0x20; crtc = 0x30; break;
+ default: seq = 0x00; crtc = 0x00; break;
+ }
+ mga_outb(M_SEQ_INDEX, 1);
+ mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+ mga_outb(M_EXTVGA_INDEX, 1);
+ mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+#undef minfo
+}
+
+#define RSResolution(X) ((X) & 0x0F)
+#define RS640x400 1
+#define RS640x480 2
+#define RS800x600 3
+#define RS1024x768 4
+#define RS1280x1024 5
+#define RS1600x1200 6
+#define RS768x576 7
+#define RS960x720 8
+#define RS1152x864 9
+#define RS1408x1056 10
+/* B-F */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+ { 640, 400, 48, 16, 39, 8, 96, 2, 70 },
+ { 640, 480, 48, 16, 33, 10, 96, 2, 60 },
+ { 800, 600, 144, 24, 28, 8, 112, 6, 60 },
+ { 1024, 768, 160, 32, 30, 4, 128, 4, 60 },
+ { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 },
+ { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 },
+ { 768, 576, 144, 16, 28, 6, 112, 4, 60 },
+ { 960, 720, 144, 24, 28, 8, 112, 4, 60 },
+ { 1152, 864, 192, 32, 30, 4, 128, 4, 60 },
+ { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }
+};
+
+#define RSDepth(X) (((X) >> 4) & 0x0F)
+#define RS8bpp 0x1
+#define RS15bpp 0x2
+#define RS16bpp 0x3
+#define RS32bpp 0x4
+#define RS4bpp 0x5
+#define RS24bpp 0x6
+/* 7-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = {
+ { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
+ { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+ { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
+ { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+ { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
+ { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }
+};
+
+#define RSCreate(X,Y) ((X) | ((Y) << 4))
+static struct { int vesa; int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+#ifdef FBCON_HAS_CFB8
+ { 0x101, RSCreate(RS640x480, RS8bpp ) },
+ { 0x100, RSCreate(RS640x400, RS8bpp ) },
+ { 0x180, RSCreate(RS768x576, RS8bpp ) },
+ { 0x103, RSCreate(RS800x600, RS8bpp ) },
+ { 0x188, RSCreate(RS960x720, RS8bpp ) },
+ { 0x105, RSCreate(RS1024x768, RS8bpp ) },
+ { 0x190, RSCreate(RS1152x864, RS8bpp ) },
+ { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+ { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+ { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB4
+ { 0x102, RSCreate(RS800x600, RS4bpp ) },
+ { 0x104, RSCreate(RS1024x768, RS4bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB16
+ { 0x110, RSCreate(RS640x480, RS15bpp) },
+ { 0x181, RSCreate(RS768x576, RS15bpp) },
+ { 0x113, RSCreate(RS800x600, RS15bpp) },
+ { 0x189, RSCreate(RS960x720, RS15bpp) },
+ { 0x116, RSCreate(RS1024x768, RS15bpp) },
+ { 0x191, RSCreate(RS1152x864, RS15bpp) },
+ { 0x119, RSCreate(RS1280x1024, RS15bpp) },
+ { 0x199, RSCreate(RS1408x1056, RS15bpp) },
+ { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+ { 0x111, RSCreate(RS640x480, RS16bpp) },
+ { 0x182, RSCreate(RS768x576, RS16bpp) },
+ { 0x114, RSCreate(RS800x600, RS16bpp) },
+ { 0x18A, RSCreate(RS960x720, RS16bpp) },
+ { 0x117, RSCreate(RS1024x768, RS16bpp) },
+ { 0x192, RSCreate(RS1152x864, RS16bpp) },
+ { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+ { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+ { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+#endif
+#ifdef FBCON_HAS_CFB24
+ { 0x1B2, RSCreate(RS640x480, RS24bpp) },
+ { 0x184, RSCreate(RS768x576, RS24bpp) },
+ { 0x1B5, RSCreate(RS800x600, RS24bpp) },
+ { 0x18C, RSCreate(RS960x720, RS24bpp) },
+ { 0x1B8, RSCreate(RS1024x768, RS24bpp) },
+ { 0x194, RSCreate(RS1152x864, RS24bpp) },
+ { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+ { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+ { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+#endif
+#ifdef FBCON_HAS_CFB32
+ { 0x112, RSCreate(RS640x480, RS32bpp) },
+ { 0x183, RSCreate(RS768x576, RS32bpp) },
+ { 0x115, RSCreate(RS800x600, RS32bpp) },
+ { 0x18B, RSCreate(RS960x720, RS32bpp) },
+ { 0x118, RSCreate(RS1024x768, RS32bpp) },
+ { 0x193, RSCreate(RS1152x864, RS32bpp) },
+ { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+ { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+#endif
+ { 0, 0 }};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */
+static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24 = 0; /* "matrox:inv24" */
+static int disabled = 0; /* "matrox:disabled" */
+static int noaccel = 0; /* "matrox:noaccel" */
+static int nopan = 0; /* "matrox:nopan" */
+static int no_pci_retry = 0; /* "matrox:nopciretry" */
+static int novga = 0; /* "matrox:novga" */
+static int nobios = 0; /* "matrox:nobios" */
+static int inverse = 0; /* "matrox:inverse" */
+static int hwcursor = 0; /* "matrox:hwcursor" */
+static int dev = -1; /* "matrox:dev:xxxxx" */
+static unsigned int vesa = 0x101; /* "matrox:vesa:xxxxx" */
+static unsigned int depth = 0; /* "matrox:depth:xxxxx" */
+static unsigned int xres = 0; /* "matrox:xres:xxxxx" */
+static unsigned int yres = 0; /* "matrox:yres:xxxxx" */
+static unsigned int upper = 0; /* "matrox:upper:xxxxx" */
+static unsigned int lower = 0; /* "matrox:lower:xxxxx" */
+static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */
+static unsigned int left = 0; /* "matrox:left:xxxxx" */
+static unsigned int right = 0; /* "matrox:right:xxxxx" */
+static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */
+static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */
+static int sync = -1; /* "matrox:sync:xxxxx" */
+static int fv = 0; /* "matrox:fv:xxxxx" */
+static int fh = 0; /* "matrox:fh:xxxxxk" */
+static int maxclk = 0; /* "matrox:maxclk:xxxxM" */
+static char fontname[64]; /* "matrox:font:xxxxx" */
+
+#ifndef MODULE
+__initfunc(void matroxfb_setup(char *options, int *ints)) {
+ char *this_opt;
+
+ fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ dprintk("matroxfb_setup: option %s\n", this_opt);
+
+ if (! strcmp(this_opt, "inverse"))
+ inverse = 1;
+ else if (!strcmp(this_opt, "disabled"))
+ disabled = 1;
+ else if (!strcmp(this_opt, "noaccel"))
+ noaccel = 1;
+ else if (!strcmp(this_opt, "nopan"))
+ nopan = 1;
+ else if (!strcmp(this_opt, "nopciretry"))
+ no_pci_retry = 1;
+ else if (!strcmp(this_opt, "novga"))
+ novga = 1;
+ else if (!strcmp(this_opt, "nobios"))
+ nobios = 1;
+ else if (!strcmp(this_opt, "inv24"))
+ inv24 = 1;
+ else if (!strcmp(this_opt, "hwcursor"))
+ hwcursor = 1;
+ else if (!strncmp(this_opt, "dev:", 4))
+ dev = simple_strtoul(this_opt+4, NULL, 0);
+ else if (!strncmp(this_opt, "depth:", 6)) {
+ switch (simple_strtoul(this_opt+6, NULL, 0)) {
+ case 4: depth = RS4bpp; break;
+ case 8: depth = RS8bpp; break;
+ case 15:depth = RS15bpp; break;
+ case 16:depth = RS16bpp; break;
+ case 24:depth = RS24bpp; break;
+ case 32:depth = RS32bpp; break;
+ default:
+ printk(KERN_ERR "matroxfb: unsupported color depth\n");
+ }
+ } else if (!strncmp(this_opt, "xres:", 5))
+ xres = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "yres:", 5))
+ yres = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "vslen:", 6))
+ vslen = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "hslen:", 6))
+ hslen = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "left:", 5))
+ left = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "right:", 6))
+ right = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "upper:", 6))
+ upper = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "lower:", 6))
+ lower = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "pixclock:", 9))
+ pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ else if (!strncmp(this_opt, "sync:", 5))
+ sync = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "vesa:", 5))
+ vesa = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "font:", 5))
+ strcpy(fontname, this_opt+5);
+ else if (!strncmp(this_opt, "maxclk:", 7))
+ maxclk = simple_strtoul(this_opt+7, NULL, 0);
+ else if (!strncmp(this_opt, "fh:", 3))
+ fh = simple_strtoul(this_opt+3, NULL, 0);
+ else if (!strncmp(this_opt, "fv:", 3))
+ fv = simple_strtoul(this_opt+3, NULL, 0);
+ else if (!strncmp(this_opt, "mem:", 4))
+ mem = simple_strtoul(this_opt+4, NULL, 0);
+ else {
+ printk(KERN_ERR "matroxfb: unknown parameter %s\n", this_opt);
+ }
+ }
+}
+#endif
+
+__initfunc(static int matroxfb_getmemory(WPMINFO int maxSize, unsigned int* realOffset, int *realSize)) {
+ volatile unsigned char* vm;
+ int offs;
+ int offs2;
+ unsigned char store;
+ unsigned char bytes[16];
+ unsigned char* tmp;
+ unsigned long cbase;
+ unsigned long mbase;
+ unsigned int clen;
+ unsigned int mlen;
+
+ vm = ACCESS_FBINFO(video_vbase);
+ maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
+ /* at least 2MB */
+ if (maxSize < 0x0200000) return 0;
+ if (maxSize > 0x1000000) maxSize = 0x1000000;
+
+ mga_outb(M_EXTVGA_INDEX, 0x03);
+ mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+
+ store = vm[0x1234];
+ tmp = bytes;
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+ *tmp++ = vm[offs];
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+ vm[offs] = 0x02;
+ if (ACCESS_FBINFO(features.accel.has_cacheflush))
+ mga_outb(M_CACHEFLUSH, 0x00);
+ else
+ vm[0x1234] = 0x99;
+ cbase = mbase = 0;
+ clen = mlen = 0;
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+ if (vm[offs] != 0x02)
+ continue;
+ vm[offs] -= 0x02;
+ if (vm[offs])
+ continue;
+ if (offs - 0x100000 == cbase + clen) {
+ clen += 0x200000;
+ } else {
+ cbase = offs - 0x100000;
+ clen = 0x200000;
+ }
+ if ((clen > mlen)
+#ifndef MATROX_2MB_WITH_4MB_ADDON
+ && (cbase == 0)
+#endif
+ ) {
+ mbase = cbase;
+ mlen = clen;
+ }
+ }
+ tmp = bytes;
+ for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+ vm[offs2] = *tmp++;
+ vm[0x1234] = store;
+
+ mga_outb(M_EXTVGA_INDEX, 0x03);
+ mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+
+ *realOffset = mbase;
+ *realSize = mlen;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF));
+#endif
+ return 1;
+}
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+ static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+ static const int vxres_mill1[] = { 640, 768, 800, 960,
+ 1024, 1152, 1280, 1600, 1920,
+ 2048, 0};
+ ACCESS_FBINFO(millenium) = 1;
+ ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
+ ACCESS_FBINFO(capable.cfb4) = 1;
+ ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
+ /* preserve VGA I/O, BIOS and PPC */
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x002C0000;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ return 0;
+}
+
+__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+ ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
+
+ outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+ outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+ outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ mga_outb(M_MISC_REG, 0x67);
+
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+ ti3026_ramdac_init(PMINFO hw);
+
+ dprintk(KERN_INFO "matroxfb: PCI OPTION = %08X\n", hw->MXoptionReg);
+
+ mga_outl(M_RESET, 1);
+ udelay(250);
+ mga_outl(M_RESET, 0);
+ udelay(250);
+ /* wait for retrace, draw black square and so on... */
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct matrox_switch matrox_millenium = {
+ Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct matrox_switch matrox_mystique = {
+ MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore
+};
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static struct matrox_switch matrox_G100 = {
+ MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore
+};
+#endif
+
+struct video_board {
+ int maxvram;
+ int accelID;
+ struct matrox_switch* lowlevel;
+ };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillenium __initdata = {0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium};
+static struct video_board vbMillenium2 __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium};
+static struct video_board vbMillenium2A __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique __initdata = {0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
+#endif /* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G100
+static struct video_board vbG100 __initdata = {0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
+static struct video_board vbG200 __initdata = {0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
+#endif
+
+#define DEVF_VIDEO64BIT 0x01
+#define DEVF_SWAPS 0x02
+#define DEVF_MILLENIUM 0x04
+#define DEVF_MILLENIUM2 0x08
+static struct board {
+ unsigned short vendor, device, rev, svid, sid;
+ unsigned flags;
+ struct video_board* base;
+ const char* name;
+ } dev_list[] __initdata = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF,
+ 0, 0,
+ DEVF_MILLENIUM,
+ &vbMillenium,
+ "Millenium (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF,
+ 0, 0,
+ DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+ &vbMillenium2,
+ "Millenium II (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
+ 0, 0,
+ DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
+ &vbMillenium2A,
+ "Millenium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02,
+ 0, 0,
+ DEVF_VIDEO64BIT,
+ &vbMystique,
+ "Mystique (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF,
+ 0, 0,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbMystique,
+ "Mystique 220 (PCI)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G100
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "MGA-G100 (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
+ 0, 0,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "unknown G100 (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_UNSPECIFIED,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "Productiva G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ 0, 0,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG100,
+ "unknown G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_UNSPECIFIED,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "MGA-G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "Mystique G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "Millenium G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "Marvel G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "MGA-G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ 0, 0,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ &vbG200,
+ "unknown G200 (AGP)"},
+#endif
+ {0, 0, 0xFF,
+ 0, 0,
+ 0,
+ NULL,
+ NULL}};
+
+__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+ unsigned long ctrlptr_phys = 0;
+ unsigned long video_base_phys = 0;
+ int memsize;
+ struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
+
+ /* set default values... */
+ vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+ ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
+ ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
+
+ printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+ ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
+ if (b->flags & DEVF_SWAPS) {
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF;
+ video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF; /* aligned at 8MB (or 16 for Mill 2) */
+ } else {
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF;
+ video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF; /* aligned at 8MB */
+ }
+ if (!ctrlptr_phys) {
+ printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+ return -EINVAL;
+ }
+ if (!video_base_phys) {
+ printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+ return -EINVAL;
+ }
+ ACCESS_FBINFO(mmio) = ioremap_nocache(ctrlptr_phys, 16384); /* do we really need ioremap_nocache? */
+ if (!ACCESS_FBINFO(mmio)) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+ return -ENOMEM;
+ }
+ ACCESS_FBINFO(mmio_base) = ctrlptr_phys;
+ ACCESS_FBINFO(mmio_len) = 16384;
+ memsize = b->base->maxvram;
+/* convert mem (autodetect k, M) */
+ if (mem < 1024) mem *= 1024;
+ if (mem < 0x00100000) mem *= 1024;
+
+ if (mem && (mem < memsize))
+ memsize = mem;
+ ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, memsize);
+ ACCESS_FBINFO(video_base) = video_base_phys;
+ if (!ACCESS_FBINFO(video_vbase)) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+ video_base_phys, memsize);
+ iounmap(ACCESS_FBINFO(mmio));
+ return -ENOMEM;
+ }
+ {
+ u_int32_t cmd;
+ u_int32_t mga_option;
+
+ /* Matrox MilleniumII is deactivated on bootup, but address
+ regions are assigned to board. So we have to enable it */
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
+ mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+ if ((cmd & PCI_COMMAND_MEMORY) !=
+ PCI_COMMAND_MEMORY) {
+ /* But if we have to enable it, we have probably to
+ disable VGA I/O and BIOS... Sure? */
+ dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n");
+ cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE;
+ mga_option &= 0xBFFFFEFF;
+ ACCESS_FBINFO(devflags.novga) = 1;
+ ACCESS_FBINFO(devflags.nobios) = 1;
+ }
+ mga_option |= MX_OPTION_BSWAP;
+ if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
+ if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
+ printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+ }
+ mga_option |= 0x20000000;
+ ACCESS_FBINFO(devflags.nopciretry) = 1;
+ }
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
+ hw->MXoptionReg = mga_option;
+
+ /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+ /* maybe preinit() candidate, but it is same... for all devices... at this time... */
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
+ }
+
+ if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
+ iounmap(ACCESS_FBINFO(video_vbase));
+ iounmap(ACCESS_FBINFO(mmio));
+ return -ENXIO;
+ }
+
+ {
+ unsigned int offs;
+
+ if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video_len)) || !ACCESS_FBINFO(video_len)) {
+ printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+ iounmap(ACCESS_FBINFO(video_vbase));
+ iounmap(ACCESS_FBINFO(mmio));
+ return -ENOMEM;
+ }
+#ifdef MATROX_2MB_WITH_4MB_ADDON
+#ifdef FBCON_HAS_CFB24
+ {
+ unsigned int end = offs + ACCESS_FBINFO(video_len);
+
+ if (offs)
+ offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3;
+ ACCESS_FBINFO(video_len) = end - offs;
+ }
+#endif
+ mga_ydstorg(MINFO) = offs;
+ video_base_phys += offs;
+#endif
+ }
+ ACCESS_FBINFO(curr.video_type) = FB_TYPE_PACKED_PIXELS;
+ ACCESS_FBINFO(currcon) = -1;
+ iounmap(ACCESS_FBINFO(video_vbase));
+ ACCESS_FBINFO(video_vbase) = ioremap(video_base_phys, ACCESS_FBINFO(video_len));
+ ACCESS_FBINFO(video_base) = video_base_phys;
+ if (!ACCESS_FBINFO(video_vbase)) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+ video_base_phys, ACCESS_FBINFO(video_len));
+ iounmap(ACCESS_FBINFO(mmio));
+ return -ENOMEM;
+ }
+#ifdef CONFIG_MTRR
+ ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video_len), MTRR_TYPE_WRCOMB, 1);
+ ACCESS_FBINFO(mtrr.vram_valid) = 1;
+ printk(KERN_INFO "matroxfb: MTRR's turned on\n");
+#endif /* CONFIG_MTRR */
+
+/* validate params, autodetect k, M */
+ if (fh < 1000) fh *= 1000; /* 1kHz minimum */
+ if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
+ if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
+ vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
+
+ ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
+ ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
+ ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
+ ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
+ ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
+
+/* static settings */
+ for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+ if (RSptr->vesa == vesa) break;
+ }
+ if (!RSptr->vesa) {
+ printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+ RSptr = vesamap;
+ }
+ {
+ int res = RSResolution(RSptr->info)-1;
+ if (!left)
+ left = timmings[res].left;
+ if (!xres)
+ xres = timmings[res].xres;
+ if (!right)
+ right = timmings[res].right;
+ if (!hslen)
+ hslen = timmings[res].hslen;
+ if (!upper)
+ upper = timmings[res].upper;
+ if (!yres)
+ yres = timmings[res].yres;
+ if (!lower)
+ lower = timmings[res].lower;
+ if (!vslen)
+ vslen = timmings[res].vslen;
+ if (!(fv||fh||maxclk||pixclock))
+ fv = timmings[res].vfreq;
+ if (!depth)
+ depth = RSDepth(RSptr->info);
+ }
+ if (sync == -1) {
+ sync = 0;
+ if (yres < 480)
+ sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+ if (xres < 320)
+ xres = 320;
+ if (xres > 2048)
+ xres = 2048;
+ if (yres < 200)
+ yres = 200;
+ if (yres > 2048)
+ yres = 2048;
+ {
+ int tmp;
+
+ if (fv) {
+ tmp = fv * (upper + yres + lower + vslen);
+ if ((tmp < fh) || (fh == 0)) fh = tmp;
+ }
+ if (fh) {
+ tmp = fh * (left + xres + right + hslen);
+ if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+ }
+ maxclk = (maxclk + 499) / 500;
+ if (maxclk) {
+ tmp = (2000000000 + maxclk) / maxclk;
+ if (tmp > pixclock) pixclock = tmp;
+ }
+ }
+ vesafb_defined.red = colors[depth-1].red;
+ vesafb_defined.green = colors[depth-1].green;
+ vesafb_defined.blue = colors[depth-1].blue;
+ vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+ if (pixclock < 2000) /* > 500MHz */
+ pixclock = 4000; /* 250MHz */
+ if (pixclock > 1000000)
+ pixclock = 1000000; /* 1MHz */
+ vesafb_defined.xres = xres;
+ vesafb_defined.yres = yres;
+ {
+ int pixel_size = vesafb_defined.bits_per_pixel;
+ int avamem = ACCESS_FBINFO(video_len);
+
+ /* displaying is possible only in first 8MB */
+ if (avamem > 0x8000000)
+ avamem = 0x8000000;
+
+ vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO xres, pixel_size);
+ if (nopan) {
+ vesafb_defined.yres_virtual = yres;
+ } else {
+ vesafb_defined.yres_virtual = (avamem * 8 / (pixel_size * vesafb_defined.xres_virtual)) & ~0x1F;
+ if (vesafb_defined.yres_virtual < vesafb_defined.yres)
+ vesafb_defined.yres_virtual = yres;
+ }
+ }
+ vesafb_defined.xoffset = 0;
+ vesafb_defined.yoffset = 0;
+ vesafb_defined.grayscale = 0;
+ vesafb_defined.pixclock = pixclock;
+ vesafb_defined.left_margin = left;
+ vesafb_defined.right_margin = right;
+ vesafb_defined.hsync_len = hslen;
+ vesafb_defined.upper_margin = upper;
+ vesafb_defined.lower_margin = lower;
+ vesafb_defined.vsync_len = vslen;
+ vesafb_defined.sync = sync;
+ vesafb_defined.vmode = 0;
+
+ if (!ACCESS_FBINFO(devflags.novga))
+ request_region(0x3C0, 32, "matrox");
+ if (noaccel)
+ vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+ strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
+ ACCESS_FBINFO(fbcon.changevar) = NULL;
+ ACCESS_FBINFO(fbcon.node) = -1;
+ ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
+ ACCESS_FBINFO(fbcon.disp) = d;
+ ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
+ ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
+ ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+ ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
+ ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
+ if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
+ printk(KERN_ERR "matroxfb: cannot set required parameters\n");
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+ vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+ vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+ printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+ ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_vbase), ACCESS_FBINFO(video_len));
+
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+ if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+ return -EINVAL;
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
+ if (ACCESS_FBINFO(currcon) < 0) {
+ /* there is no console on this fb... but we have to initialize hardware
+ * until someone tells me what is proper thing to do */
+ printk(KERN_INFO "fb%d: initializing hardware\n",
+ GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
+ matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
+ }
+ return 0;
+}
+
+static struct matrox_fb_info* fb_list = NULL;
+
+__initfunc(static int matrox_init(void)) {
+ struct pci_dev* pdev = NULL;
+
+ if (disabled)
+ return -ENXIO;
+ while ((pdev = pci_find(pdev)) != NULL) {
+ struct board* b;
+ u_int8_t rev;
+ u_int16_t svid;
+ u_int16_t sid;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
+ for (b = dev_list; b->vendor; b++) {
+ if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+ if (b->svid)
+ if ((b->svid != svid) || (b->sid != sid)) continue;
+ if (dev <= 0) {
+ struct matrox_fb_info* minfo;
+ struct display* d;
+ int err;
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+ if (minfo) {
+ d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
+ if (d) {
+#else
+ minfo = &global_mxinfo;
+ d = &global_disp;
+#endif
+ memset(MINFO, 0, sizeof(*MINFO));
+ memset(d, 0, sizeof(*d));
+
+ ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
+ ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
+ ACCESS_FBINFO(pcidev) = pdev;
+ /* CMDLINE */
+ memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
+ /* DEVFLAGS */
+ ACCESS_FBINFO(devflags.inverse) = inverse;
+ ACCESS_FBINFO(devflags.novga) = novga;
+ ACCESS_FBINFO(devflags.nobios) = nobios;
+ ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
+ ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
+ ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
+ ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
+
+ err = initMatrox2(PMINFO d, b);
+ if (!err) {
+ ACCESS_FBINFO(next_fb) = fb_list;
+ fb_list = MINFO;
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ goto leave;
+#else
+ return 0;
+#endif
+ }
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ kfree(d);
+ }
+ kfree(minfo);
+ }
+#endif
+ }
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+leave:;
+#endif
+ if (dev == 0) return 0;
+ if (dev > 0) dev--;
+ break;
+ }
+ }
+ return 0;
+}
+
+#ifndef MODULE
+__initfunc(void matroxfb_init(void))
+{
+ matrox_init();
+}
+
+#else
+
+MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millenium/Mystique");
+MODULE_PARM(mem, "i");
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+MODULE_PARM(nopan, "i");
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+MODULE_PARM(no_pci_retry, "i");
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(novga, "i");
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(nobios, "i");
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
+MODULE_PARM(inv24, "i");
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+#else
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
+#endif
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa, "Startup videomode (0x100-0x1FF) (default=0x101)");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+MODULE_PARM(upper, "i");
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+MODULE_PARM(lower, "i");
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(vslen, "i");
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(left, "i");
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+MODULE_PARM(right, "i");
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+MODULE_PARM(hslen, "i");
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+MODULE_PARM(pixclock, "i");
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+MODULE_PARM(depth, "i");
+MODULE_PARM_DESC(depth, "Color depth (8,15,16,24,32) (default=vesa)");
+MODULE_PARM(maxclk, "i");
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+MODULE_PARM(fh, "i");
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+MODULE_PARM(fv, "i");
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
+
+
+__initfunc(int init_module(void)) {
+ if (depth == 0)
+ depth = 0; /* default */
+ else if (depth == 4)
+ depth = RS4bpp;
+ else if (depth == 8)
+ depth = RS8bpp;
+ else if (depth == 15)
+ depth = RS15bpp;
+ else if (depth == 16)
+ depth = RS16bpp;
+ else if (depth == 24)
+ depth = RS24bpp;
+ else if (depth == 32)
+ depth = RS32bpp;
+ else {
+ printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+ depth = 0;
+ }
+ matrox_init();
+ if (!fb_list) return -ENXIO;
+ return 0;
+}
+
+void cleanup_module(void) {
+ while (fb_list) {
+ struct matrox_fb_info* minfo;
+
+ minfo = fb_list;
+ fb_list = fb_list->next_fb;
+ unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+#ifdef CONFIG_MTRR
+ if (ACCESS_FBINFO(mtrr.vram_valid))
+ mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video_base), ACCESS_FBINFO(video_len));
+#endif
+ iounmap(ACCESS_FBINFO(mmio));
+ iounmap(ACCESS_FBINFO(video_vbase));
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
+ kfree_s(minfo, sizeof(struct matrox_fb_info));
+#endif
+ }
+}
+#endif /* MODULE */
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
+#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
long v_dispend; /* Horizontal Display End */
};
-static struct retz3fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp;
-static struct fb_info fb_info;
-
-
-/*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
+struct retz3_fb_info {
+ struct fb_info info;
+ unsigned long base;
+ unsigned long fbmem;
+ unsigned long fbsize;
+ volatile unsigned char *regs;
+ unsigned long physfbmem;
+ unsigned long physregs;
+ int currcon;
+ int current_par_valid; /* set to 0 by memset */
+ struct display disp;
+ struct retz3fb_par current_par;
+ unsigned char color_table [256][3];
+};
- int (*init)(void);
- /* Display Control */
+static char fontname[40] __initdata = { 0 };
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
- int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
- int *green, unsigned int *blue, unsigned int *transp,
- struct fb_info *info);
- int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
- green, unsigned int blue, unsigned int transp,
- struct fb_info *info);
- void (*blank)(int blank);
-} *fbhw;
+#define retz3info(info) ((struct retz3_fb_info *)(info))
+#define fbinfo(info) ((struct fb_info *)(info))
/*
static char retz3fb_name[16] = "RetinaZ3";
-static unsigned char retz3_color_table [256][3];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-
/*
* A small info on how to convert XFree86 timing values into fb
* timings - by Frank Neumann:
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_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
}
},
/*
640, 480, 640, 480, 0, 0, 16, 0,
{11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
}
}, {
"640x480-24", { /* 640x480, 24 bpp */
640, 480, 640, 480, 0, 0, 24, 0,
{8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
}
},
};
* Accelerated Functions used by the low level console driver
*/
-static void retz3_bitblt(struct fb_var_screeninfo *scr,
+static void retz3_bitblt(struct display *p,
unsigned short curx, unsigned short cury, unsigned
short destx, unsigned short desty, unsigned short
width, unsigned short height, unsigned short cmd,
* Hardware Specific Routines
*/
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3fb_par *par);
+static int retz3_encode_fix(struct fb_info *info,
+ struct fb_fix_screeninfo *fix,
+ struct retz3fb_par *par);
static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par);
+ struct retz3fb_par *par);
static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par);
+ struct retz3fb_par *par);
static int retz3_getcolreg(unsigned int regno, unsigned int *red,
unsigned int *green, unsigned int *blue,
unsigned int *transp, struct fb_info *info);
static int retz3_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info);
-static void retz3_blank(int blank);
-
/*
* Internal routines
*/
-static void retz3fb_get_par(struct retz3fb_par *par);
-static void retz3fb_set_par(struct retz3fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
+static int do_fb_set_var(struct fb_info *info,
+ struct fb_var_screeninfo *var, int isactive);
static void do_install_cmap(int con, struct fb_info *info);
static void retz3fb_set_disp(int con, struct fb_info *info);
static int get_video_mode(const char *name);
}
-static int retz3_set_video(struct fb_var_screeninfo *var,
+static int retz3_set_video(struct fb_info *info,
+ struct fb_var_screeninfo *var,
struct retz3fb_par *par)
{
-#if 0
- float freq_f;
-#endif
+ volatile unsigned char *regs = retz3info(info)->regs;
unsigned int freq;
int xres, hfront, hsync, hback;
if (data.v_total >= 1024)
printk("MAYDAY: v_total >= 1024; bailing out!\n");
- reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
- reg_w(GREG_FEATURE_CONTROL_W, 0x00);
+ reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
+ reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
- seq_w(SEQ_RESET, 0x00);
- seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
+ seq_w(regs, SEQ_RESET, 0x00);
+ seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */
/*
* CLOCKING_MODE bits:
* (The CL drivers sets it to 0x21 with the comment:
* FullBandwidth (video off) and 8/9 dot clock)
*/
- seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
+ seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
- seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
- seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
- seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
- seq_w(SEQ_RESET, 0x01);
- seq_w(SEQ_RESET, 0x03);
+ seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
+ seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
+ seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
+ seq_w(regs, SEQ_RESET, 0x01);
+ seq_w(regs, SEQ_RESET, 0x03);
- seq_w(SEQ_EXTENDED_ENABLE, 0x05);
+ seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
- seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_LINEAR_0, 0x4a);
- seq_w(SEQ_LINEAR_1, 0x00);
+ seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
+ seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+ seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+ seq_w(regs, SEQ_LINEAR_0, 0x4a);
+ seq_w(regs, SEQ_LINEAR_1, 0x00);
- seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
- seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
- seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
+ seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
+ seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
+ seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
/*
* The lower 4 bits (0-3) are used to set the font-width for
* text-mode - DON'T try to set this for gfx-mode.
*/
- seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
- seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
+ seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
+ seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
/*
* Extended Pixel Control:
* bit 1: (Packed/Nibble Pixel Format ?)
* bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
*/
- seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
- seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
- seq_w(SEQ_COLOR_EXP_WFG, 0x01);
- seq_w(SEQ_COLOR_EXP_WBG, 0x00);
- seq_w(SEQ_EXT_RW_CONTROL, 0x00);
- seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
- seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
- seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
- seq_w(SEQ_CRC_CONTROL, 0x00);
- seq_w(SEQ_PERF_SELECT, 0x10);
- seq_w(SEQ_ACM_APERTURE_1, 0x00);
- seq_w(SEQ_ACM_APERTURE_2, 0x30);
- seq_w(SEQ_ACM_APERTURE_3, 0x00);
- seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
+ seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
+
+ seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
+ seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
+ seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
+ seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
+ seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
+ seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
+ seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
+ seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
+ seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
+ seq_w(regs, SEQ_CRC_CONTROL, 0x00);
+ seq_w(regs, SEQ_PERF_SELECT, 0x10);
+ seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
+ seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
+ seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
+ seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
/* unlock register CRT0..CRT7 */
- crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
+ crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
/* Zuerst zu schreibende Werte nur per printk ausgeben */
DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
- crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
+ crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
- crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
+ crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
- crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
+ crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
- crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
+ crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
- crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
+ crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
tmp = (data.h_sstop & 0x1f);
if (data.h_bstop & 0x20)
tmp |= 0x80;
DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
- crt_w(CRT_END_HOR_RETR, tmp);
+ crt_w(regs, CRT_END_HOR_RETR, tmp);
DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
- crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
+ crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
tmp = 0x10; /* LineCompare bit #9 */
if (data.v_total & 256)
if (data.v_sstart & 512)
tmp |= 0x80;
DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
- crt_w(CRT_OVERFLOW, tmp);
+ crt_w(regs, CRT_OVERFLOW, tmp);
- crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
+ crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
tmp = 0x40; /* LineCompare bit #8 */
if (data.v_bstart & 512)
if (var->vmode & FB_VMODE_DOUBLE)
tmp |= 0x80;
DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
- crt_w(CRT_MAX_SCAN_LINE, tmp);
+ crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
- crt_w(CRT_CURSOR_START, 0x00);
- crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
+ crt_w(regs, CRT_CURSOR_START, 0x00);
+ crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
- crt_w(CRT_START_ADDR_HIGH, 0x00);
- crt_w(CRT_START_ADDR_LOW, 0x00);
+ crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
+ crt_w(regs, CRT_START_ADDR_LOW, 0x00);
- crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
- crt_w(CRT_CURSOR_LOC_LOW, 0x00);
+ crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
+ crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
- crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
+ crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
#if 1
/* 5 refresh cycles per scanline */
DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
+ crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
#else
DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
+ crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
#endif
DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
- crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
+ crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
- crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
+ crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
- crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
+ crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
- crt_w(CRT_MODE_CONTROL, 0xe3);
+ crt_w(regs, CRT_MODE_CONTROL, 0xe3);
DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
- crt_w(CRT_LINE_COMPARE, 0xff);
+ crt_w(regs, CRT_LINE_COMPARE, 0xff);
tmp = (var->xres_virtual / 8) * (bpp / 8);
- crt_w(CRT_OFFSET, tmp);
+ crt_w(regs, CRT_OFFSET, tmp);
- crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
+ crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
tmp = 0x20; /* Enable extended end bits */
if (data.h_total & 0x100)
if (var->vmode & FB_VMODE_INTERLACED)
tmp |= 0x10;
DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
- crt_w(CRT_EXT_HOR_TIMING1, tmp);
+ crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
tmp = 0x00;
if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
tmp |= 0x10;
- crt_w(CRT_EXT_START_ADDR, tmp);
+ crt_w(regs, CRT_EXT_START_ADDR, tmp);
tmp = 0x00;
if (data.h_total & 0x200)
tmp |= 0x08;
tmp |= ((data.h_bstop & 0xc0) >> 2);
tmp |= ((data.h_sstop & 0x60) << 1);
- crt_w(CRT_EXT_HOR_TIMING2, tmp);
+ crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
tmp = 0x10; /* Line compare bit 10 */
tmp |= ((data.v_bstop & 0x300) >> 3);
if (data.v_sstop & 0x10)
tmp |= 0x80;
- crt_w(CRT_EXT_VER_TIMING, tmp);
+ crt_w(regs, CRT_EXT_VER_TIMING, tmp);
DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
- crt_w(CRT_MONITOR_POWER, 0x00);
+ crt_w(regs, CRT_MONITOR_POWER, 0x00);
/*
* Convert from ps to Hz.
*/
-#if 0
- freq_f = (1.0/(float)var->pixclock) * 1000000000;
- freq = ((unsigned int)freq_f) * 1000;
-#else
freq = 2000000000 / var->pixclock;
freq = freq * 500;
-#endif
best_freq = find_fq(freq);
- pll_w(0x02, best_freq);
+ pll_w(regs, 0x02, best_freq);
best_freq = find_fq(61000000);
- pll_w(0x0a, best_freq);
- pll_w(0x0e, 0x22);
-
- gfx_w(GFX_SET_RESET, 0x00);
- gfx_w(GFX_ENABLE_SET_RESET, 0x00);
- gfx_w(GFX_COLOR_COMPARE, 0x00);
- gfx_w(GFX_DATA_ROTATE, 0x00);
- gfx_w(GFX_READ_MAP_SELECT, 0x00);
- gfx_w(GFX_GRAPHICS_MODE, 0x00);
- gfx_w(GFX_MISC, 0x05);
- gfx_w(GFX_COLOR_XCARE, 0x0f);
- gfx_w(GFX_BITMASK, 0xff);
-
- reg_r(ACT_ADDRESS_RESET);
- attr_w(ACT_PALETTE0 , 0x00);
- attr_w(ACT_PALETTE1 , 0x01);
- attr_w(ACT_PALETTE2 , 0x02);
- attr_w(ACT_PALETTE3 , 0x03);
- attr_w(ACT_PALETTE4 , 0x04);
- attr_w(ACT_PALETTE5 , 0x05);
- attr_w(ACT_PALETTE6 , 0x06);
- attr_w(ACT_PALETTE7 , 0x07);
- attr_w(ACT_PALETTE8 , 0x08);
- attr_w(ACT_PALETTE9 , 0x09);
- attr_w(ACT_PALETTE10, 0x0a);
- attr_w(ACT_PALETTE11, 0x0b);
- attr_w(ACT_PALETTE12, 0x0c);
- attr_w(ACT_PALETTE13, 0x0d);
- attr_w(ACT_PALETTE14, 0x0e);
- attr_w(ACT_PALETTE15, 0x0f);
- reg_r(ACT_ADDRESS_RESET);
-
- attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
- attr_w(ACT_OVERSCAN_COLOR, 0x00);
- attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
- attr_w(ACT_HOR_PEL_PANNING, 0x00);
- attr_w(ACT_COLOR_SELECT, 0x00);
-
- reg_r(ACT_ADDRESS_RESET);
- reg_w(ACT_DATA, 0x20);
-
- reg_w(VDAC_MASK, 0xff);
+ pll_w(regs, 0x0a, best_freq);
+ pll_w(regs, 0x0e, 0x22);
+
+ gfx_w(regs, GFX_SET_RESET, 0x00);
+ gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
+ gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
+ gfx_w(regs, GFX_DATA_ROTATE, 0x00);
+ gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
+ gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
+ gfx_w(regs, GFX_MISC, 0x05);
+ gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
+ gfx_w(regs, GFX_BITMASK, 0xff);
+
+ reg_r(regs, ACT_ADDRESS_RESET);
+ attr_w(regs, ACT_PALETTE0 , 0x00);
+ attr_w(regs, ACT_PALETTE1 , 0x01);
+ attr_w(regs, ACT_PALETTE2 , 0x02);
+ attr_w(regs, ACT_PALETTE3 , 0x03);
+ attr_w(regs, ACT_PALETTE4 , 0x04);
+ attr_w(regs, ACT_PALETTE5 , 0x05);
+ attr_w(regs, ACT_PALETTE6 , 0x06);
+ attr_w(regs, ACT_PALETTE7 , 0x07);
+ attr_w(regs, ACT_PALETTE8 , 0x08);
+ attr_w(regs, ACT_PALETTE9 , 0x09);
+ attr_w(regs, ACT_PALETTE10, 0x0a);
+ attr_w(regs, ACT_PALETTE11, 0x0b);
+ attr_w(regs, ACT_PALETTE12, 0x0c);
+ attr_w(regs, ACT_PALETTE13, 0x0d);
+ attr_w(regs, ACT_PALETTE14, 0x0e);
+ attr_w(regs, ACT_PALETTE15, 0x0f);
+ reg_r(regs, ACT_ADDRESS_RESET);
+
+ attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
+
+ attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
+ attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
+ attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
+ attr_w(regs, ACT_COLOR_SELECT, 0x00);
+
+ reg_r(regs, ACT_ADDRESS_RESET);
+ reg_w(regs, ACT_DATA, 0x20);
+
+ reg_w(regs, VDAC_MASK, 0xff);
/*
* Extended palette adressing ???
*/
switch (bpp){
case 8:
- reg_w(0x83c6, 0x00);
+ reg_w(regs, 0x83c6, 0x00);
break;
case 16:
- reg_w(0x83c6, 0x60);
+ reg_w(regs, 0x83c6, 0x60);
break;
case 24:
- reg_w(0x83c6, 0xe0);
+ reg_w(regs, 0x83c6, 0xe0);
break;
default:
printk("Illegal color-depth: %i\n", bpp);
}
- reg_w(VDAC_ADDRESS, 0x00);
-
- seq_w(SEQ_MAP_MASK, 0x0f );
-
- return 0;
-}
-
-/*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
- short i;
-#if 0
- volatile unsigned long *CursorBase;
-#endif
-
- for (i = 0; i < 256; i++){
- for (i = 0; i < 256; i++){
- retz3_color_table [i][0] = i;
- retz3_color_table [i][1] = i;
- retz3_color_table [i][2] = i;
- }
- }
-
- /* Disable hardware cursor */
+ reg_w(regs, VDAC_ADDRESS, 0x00);
- seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-#if 0
- /* Initialize hardware cursor */
- CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
- for (i=0; i < 8; i++){
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i=8; i < 64; i++){
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-#endif
-
- retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
- retz3_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
+ seq_w(regs, SEQ_MAP_MASK, 0x0f );
return 0;
}
* values in the `par' structure.
*/
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
+static int retz3_encode_fix(struct fb_info *info,
+ struct fb_fix_screeninfo *fix,
struct retz3fb_par *par)
{
+ struct retz3_fb_info *zinfo = retz3info(info);
+
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, retz3fb_name);
- fix->smem_start = (char *)z3_fbmem;
- fix->smem_len = z3_size;
- fix->mmio_start = (char *)z3_regs;
+ fix->smem_start = (char *)(zinfo->physfbmem);
+ fix->smem_len = zinfo->fbsize;
+ fix->mmio_start = (char *)(zinfo->physregs);
fix->mmio_len = 0x00c00000;
fix->type = FB_TYPE_PACKED_PIXELS;
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info)
{
+ struct retz3_fb_info *zinfo = retz3info(info);
+ volatile unsigned char *regs = zinfo->regs;
+
/* We'll get to this */
if (regno > 255)
green >>= 10;
blue >>= 10;
- retz3_color_table [regno][0] = red;
- retz3_color_table [regno][1] = green;
- retz3_color_table [regno][2] = blue;
+ zinfo->color_table[regno][0] = red;
+ zinfo->color_table[regno][1] = green;
+ zinfo->color_table[regno][2] = blue;
- reg_w(VDAC_ADDRESS_W, regno);
- reg_w(VDAC_DATA, red);
- reg_w(VDAC_DATA, green);
- reg_w(VDAC_DATA, blue);
+ reg_w(regs, VDAC_ADDRESS_W, regno);
+ reg_w(regs, VDAC_DATA, red);
+ reg_w(regs, VDAC_DATA, green);
+ reg_w(regs, VDAC_DATA, blue);
return 0;
}
unsigned int *green, unsigned int *blue,
unsigned int *transp, struct fb_info *info)
{
+ struct retz3_fb_info *zinfo = retz3info(info);
int t;
if (regno > 255)
return 1;
- t = retz3_color_table [regno][0];
+ t = zinfo->color_table[regno][0];
*red = (t<<10) | (t<<4) | (t>>2);
- t = retz3_color_table [regno][1];
+ t = zinfo->color_table[regno][1];
*green = (t<<10) | (t<<4) | (t>>2);
- t = retz3_color_table [regno][2];
+ t = zinfo->color_table[regno][2];
*blue = (t<<10) | (t<<4) | (t>>2);
*transp = 0;
return 0;
}
-/*
- * (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
- short i;
-
- if (blank)
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- }
- else
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, retz3_color_table [i][0]);
- reg_w(VDAC_DATA, retz3_color_table [i][1]);
- reg_w(VDAC_DATA, retz3_color_table [i][2]);
- }
-}
-
-
-static void retz3_bitblt (struct fb_var_screeninfo *var,
+static void retz3_bitblt (struct display *p,
unsigned short srcx, unsigned short srcy,
unsigned short destx, unsigned short desty,
unsigned short width, unsigned short height,
unsigned short cmd, unsigned short mask)
{
-
- volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
- unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
+ struct fb_var_screeninfo *var = &p->var;
+ struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+ volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
+ unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
unsigned short mod;
unsigned long tmp;
}
#endif
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
- retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
- retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
/*
* Fill the hardware's `par' structure.
*/
-static void retz3fb_get_par(struct retz3fb_par *par)
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
{
- if (current_par_valid)
- *par = current_par;
+ struct retz3_fb_info *zinfo = retz3info(info);
+
+ if (zinfo->current_par_valid)
+ *par = zinfo->current_par;
else
- fbhw->decode_var(&retz3fb_default, par);
+ retz3_decode_var(&retz3fb_default, par);
}
-static void retz3fb_set_par(struct retz3fb_par *par)
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
{
- current_par = *par;
- current_par_valid = 1;
+ struct retz3_fb_info *zinfo = retz3info(info);
+
+ zinfo->current_par = *par;
+ zinfo->current_par_valid = 1;
}
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int do_fb_set_var(struct fb_info *info,
+ struct fb_var_screeninfo *var, int isactive)
{
int err, activate;
struct retz3fb_par par;
+ struct retz3_fb_info *zinfo = retz3info(info);
- if ((err = fbhw->decode_var(var, &par)))
+ if ((err = retz3_decode_var(var, &par)))
return err;
activate = var->activate;
/* XXX ... what to do about isactive ? */
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3fb_set_par(&par);
- fbhw->encode_var(var, &par);
+ retz3fb_set_par(info, &par);
+ retz3_encode_var(var, &par);
var->activate = activate;
- retz3_set_video(var, ¤t_par);
+ retz3_set_video(info, var, &zinfo->current_par);
return 0;
}
static void do_install_cmap(int con, struct fb_info *info)
{
- if (con != currcon)
+ struct retz3_fb_info *zinfo = retz3info(info);
+
+ if (con != zinfo->currcon)
return;
if (fb_display[con].cmap.len)
- fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
+ fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info);
else
fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- 1, fbhw->setcolreg, info);
+ 1, retz3_setcolreg, info);
}
int error = 0;
if (con == -1)
- retz3fb_get_par(&par);
+ retz3fb_get_par(info, &par);
else
- error = fbhw->decode_var(&fb_display[con].var, &par);
- return(error ? error : fbhw->encode_fix(fix, &par));
+ error = retz3_decode_var(&fb_display[con].var, &par);
+ return(error ? error : retz3_encode_fix(info, fix, &par));
}
int error = 0;
if (con == -1) {
- retz3fb_get_par(&par);
- error = fbhw->encode_var(var, &par);
+ retz3fb_get_par(info, &par);
+ error = retz3_encode_var(var, &par);
} else
*var = fb_display[con].var;
return error;
{
struct fb_fix_screeninfo fix;
struct display *display;
+ struct retz3_fb_info *zinfo = retz3info(info);
if (con >= 0)
display = &fb_display[con];
else
- display = &disp; /* used during initialization */
+ display = &zinfo->disp; /* used during initialization */
retz3fb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
- display->screen_base = fix.smem_start;
+ display->screen_base = (char *)zinfo->fbmem;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
}
#endif
+
/*
* Set the User Defined Part of the Display
*/
{
int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
struct display *display;
+ struct retz3_fb_info *zinfo = retz3info(info);
if (con >= 0)
display = &fb_display[con];
else
- display = &disp; /* used during initialization */
-
-#if 0
- if (con == -1)
- con = 0;
-#endif
+ display = &zinfo->disp; /* used during initialization */
- if ((err = do_fb_set_var(var, con == currcon)))
+ if ((err = do_fb_set_var(info, var, con == zinfo->currcon)))
return err;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldxres = display->var.xres;
struct fb_fix_screeninfo fix;
retz3fb_get_fix(&fix, con, info);
- display->screen_base = fix.smem_start;
+ display->screen_base = (char *)zinfo->fbmem;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
/*
retz3fb_set_disp(con, info);
*/
- if (fb_info.changevar)
- (*fb_info.changevar)(con);
+ if (info->changevar)
+ (*info->changevar)(con);
}
if (oldbpp != var->bits_per_pixel) {
static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
- if (con == currcon) /* current console? */
- return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
+ struct retz3_fb_info *zinfo = retz3info(info);
+
+ if (con == zinfo->currcon) /* current console? */
+ return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
else if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
else
struct fb_info *info)
{
int err;
+ struct retz3_fb_info *zinfo = retz3info(info);
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
if ((err = fb_alloc_cmap(&fb_display[con].cmap,
0)))
return err;
}
- if (con == currcon) /* current console? */
- return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info));
+ if (con == zinfo->currcon) /* current console? */
+ return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info));
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
{
char *this_opt;
- fb_info.fontname[0] = '\0';
-
if (!options || !*options)
return;
if (!strcmp(this_opt, "inverse")) {
z3fb_inverse = 1;
fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else
+ } else if (!strncmp(this_opt, "font:", 5)) {
+ strncpy(fontname, this_opt+5, 39);
+ fontname[39] = '\0';
+ }else
z3fb_mode = get_video_mode(this_opt);
}
}
unsigned long board_addr, board_size;
unsigned int key;
const struct ConfigDev *cd;
-
+ volatile unsigned char *regs;
struct retz3fb_par par;
+ struct retz3_fb_info *zinfo;
+ struct fb_info *fb_info;
+ short i;
if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
return;
+ if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL)))
+ return;
+ memset(zinfo, 0, sizeof(struct retz3_fb_info));
+
cd = zorro_get_board (key);
zorro_config_board (key, 0);
board_addr = (unsigned long)cd->cd_BoardAddr;
board_size = (unsigned long)cd->cd_BoardSize;
- z3_mem = kernel_map (board_addr, board_size,
- KERNELMAP_NOCACHE_SER, NULL);
-
- z3_regs = (char*) z3_mem;
- z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
+ zinfo->base = kernel_map (board_addr, board_size,
+ KERNELMAP_NOCACHE_SER, NULL);
+ zinfo->regs = (unsigned char *)(zinfo->base);
+ zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
/* Get memory size - for now we asume its a 4MB board */
+ zinfo->fbsize = 0x00400000; /* 4 MB */
+ zinfo->physregs = board_addr;
+ zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
- z3_size = 0x00400000; /* 4 MB */
+ fb_info = fbinfo(zinfo);
- fbhw = &retz3_switch;
-
- fbhw->init();
+ for (i = 0; i < 256; i++){
+ for (i = 0; i < 256; i++){
+ zinfo->color_table[i][0] = i;
+ zinfo->color_table[i][1] = i;
+ zinfo->color_table[i][2] = i;
+ }
+ }
- strcpy(fb_info.modename, retz3fb_name);
- fb_info.changevar = NULL;
- fb_info.node = -1;
- fb_info.fbops = &retz3fb_ops;
- fb_info.disp = &disp;
- fb_info.switch_con = &z3fb_switch;
- fb_info.updatevar = &z3fb_updatevar;
- fb_info.blank = &z3fb_blank;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
+ regs = zinfo->regs;
+ /* Disable hardware cursor */
+ seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
+
+ retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
+ retz3_setcolreg (254, 0, 0, 0, 0, fb_info);
+
+ strcpy(fb_info->modename, retz3fb_name);
+ fb_info->changevar = NULL;
+ fb_info->node = -1;
+ fb_info->fbops = &retz3fb_ops;
+ fb_info->disp = &zinfo->disp;
+ fb_info->switch_con = &z3fb_switch;
+ fb_info->updatevar = &z3fb_updatevar;
+ fb_info->blank = &z3fb_blank;
+ fb_info->flags = FBINFO_FLAG_DEFAULT;
+ strncpy(fb_info->fontname, fontname, 40);
if (z3fb_mode == -1)
retz3fb_default = retz3fb_predefined[0].var;
- fbhw->decode_var(&retz3fb_default, &par);
- fbhw->encode_var(&retz3fb_default, &par);
+ retz3_decode_var(&retz3fb_default, &par);
+ retz3_encode_var(&retz3fb_default, &par);
- do_fb_set_var(&retz3fb_default, 0);
- retz3fb_get_var(&disp.var, -1, &fb_info);
+ do_fb_set_var(fb_info, &retz3fb_default, 0);
+ retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
- retz3fb_set_disp(-1, &fb_info);
+ retz3fb_set_disp(-1, fb_info);
- do_install_cmap(0, &fb_info);
+ do_install_cmap(0, fb_info);
- if (register_framebuffer(&fb_info) < 0)
+ if (register_framebuffer(fb_info) < 0)
return;
printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
- GET_FB_IDX(fb_info.node), fb_info.modename, z3_size>>10);
+ GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10);
/* TODO: This driver cannot be unloaded yet */
MOD_INC_USE_COUNT;
static int z3fb_switch(int con, struct fb_info *info)
{
+ struct retz3_fb_info *zinfo = retz3info(info);
+
/* Do we have to save the colormap? */
- if (fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
- info);
+ if (fb_display[zinfo->currcon].cmap.len)
+ fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1,
+ retz3_getcolreg, info);
- do_fb_set_var(&fb_display[con].var, 1);
- currcon = con;
+ do_fb_set_var(info, &fb_display[con].var, 1);
+ zinfo->currcon = con;
/* Install new colormap */
do_install_cmap(con, info);
return 0;
static void z3fb_blank(int blank, struct fb_info *info)
{
- fbhw->blank(blank);
+ struct retz3_fb_info *zinfo = retz3info(info);
+ volatile unsigned char *regs = retz3info(info)->regs;
+ short i;
+
+ if (blank)
+ for (i = 0; i < 256; i++){
+ reg_w(regs, VDAC_ADDRESS_W, i);
+ reg_w(regs, VDAC_DATA, 0);
+ reg_w(regs, VDAC_DATA, 0);
+ reg_w(regs, VDAC_DATA, 0);
+ }
+ else
+ for (i = 0; i < 256; i++){
+ reg_w(regs, VDAC_ADDRESS_W, i);
+ reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
+ reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
+ reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
+ }
}
*/
#ifdef FBCON_HAS_CFB8
-static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
+ int dy, int dx, int height, int width)
{
int fontwidth = fontwidth(p);
dx *= fontwidth;
width *= fontwidth;
- retz3_bitblt(&p->var,
+ retz3_bitblt(p,
(unsigned short)sx,
(unsigned short)(sy*fontheight(p)),
(unsigned short)dx,
0xffff);
}
-static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width)
+static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width)
{
unsigned short col;
int fontwidth = fontwidth(p);
col &= 0xff;
col |= (col << 8);
- retz3_bitblt(&p->var,
+ retz3_bitblt(p,
(unsigned short)sx,
(unsigned short)(sy*fontheight(p)),
(unsigned short)sx,
/*
* Macros to read and write to registers.
*/
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
+#define reg_w(regs, reg,dat) (*(regs + reg) = dat)
+#define reg_r(regs, reg) (*(regs + reg))
/*
* Macro to access the sequencer.
*/
-#define seq_w(sreg,sdat) \
- do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
+#define seq_w(regs, sreg, sdat) \
+ do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0)
/*
* Macro to access the CRT controller.
*/
-#define crt_w(creg,cdat) \
- do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
+#define crt_w(regs, creg, cdat) \
+ do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0)
/*
* Macro to access the graphics controller.
*/
-#define gfx_w(greg,gdat) \
- do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
+#define gfx_w(regs, greg, gdat) \
+ do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0)
/*
* Macro to access the attribute controller.
*/
-#define attr_w(areg,adat) \
- do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
+#define attr_w(regs, areg, adat) \
+ do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0)
/*
* Macro to access the pll.
*/
-#define pll_w(preg,pdat) \
- do{ reg_w(PLL_IDX, preg); \
- reg_w(PLL_DATA, (pdat & 0xff)); \
- reg_w(PLL_DATA, (pdat >> 8));\
+#define pll_w(regs, preg, pdat) \
+ do{ reg_w(regs, PLL_IDX, preg); \
+ reg_w(regs, PLL_DATA, (pdat & 0xff)); \
+ reg_w(regs, PLL_DATA, (pdat >> 8));\
} while(0)
/*
#ifdef __sparc_v9__
/* Align it as much as desirable */
{
- int j, max = -1, alignment, s = 0;
+ unsigned long j, alignment, s = 0;
+ int max = -1;
map_offset = vma->vm_offset+size;
for (i = 0; fb->mmap_map[i].size; i++) {
static unsigned long CyberSize;
static volatile char *CyberRegs;
static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
/*
0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
}
+ }, {
+ "1024x768-16", { /* Cybervision 16 bpp */
+ 1024, 768, 1024, 768, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
}
};
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, virgefb_name);
- fix->smem_start = (char *)CyberMem;
+ fix->smem_start = (char*) CyberMem_phys;
fix->smem_len = CyberSize;
- fix->mmio_start = (char *)CyberRegs;
+ fix->mmio_start = (char*) CyberRegs_phys;
fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
fix->type = FB_TYPE_PACKED_PIXELS;
virgefb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
- display->screen_base = fix.smem_start;
+ display->screen_base = (char*) CyberMem;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
* Ok we got the board running in Z2 space.
*/
- CyberMem = ZTWO_VADDR(board_addr);
+ CyberMem_phys = board_addr;
+ CyberMem = ZTWO_VADDR(CyberMem_phys);
printk("CV3D detected running in Z2 mode ... not yet supported!\n");
return;
}
{
CyberVGARegs = kernel_map(board_addr +0x0c000000, 0x00010000,
KERNELMAP_NOCACHE_SER, NULL);
- CyberRegs = (char *)kernel_map(board_addr +0x05000000,
+
+ CyberRegs_phys = board_addr + 0x05000000;
+ CyberMem_phys = board_addr + 0x04800000;
+ CyberRegs = (char *)kernel_map(CyberRegs_phys,
0x00010000,
KERNELMAP_NOCACHE_SER, NULL);
- CyberMem = kernel_map(board_addr + 0x04800000, 0x00400000,
+ CyberMem = kernel_map(CyberMem_phys, 0x00400000,
KERNELMAP_NOCACHE_SER, NULL);
printk("CV3D detected running in Z3 mode\n");
}
* changes by Thomas Schoebel-Theuer
*/
-#include <linux/stat.h>
#include <linux/sched.h>
-#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
-#include <asm/system.h>
/* Taken over from the old code... */
if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
do {
if ( status && dentry->d_inode ) {
- printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+ if ( status != -ENOENT )
+ printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
return 0; /* Try to get the kernel to invalidate this dentry */
}
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
-#include <linux/mm.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
extern int *blk_size[];
extern int *blksize_size[];
* - RMK
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
+#include <linux/malloc.h>
#include <linux/locks.h>
#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/quotaops.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/bitops.h>
* formats.
*/
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/mman.h>
#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <linux/ptrace.h>
#include <linux/user.h>
-#include <linux/binfmts.h>
-#include <linux/personality.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
-#include <linux/config.h>
-
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/file.h>
-#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/smp.h>
+#include <linux/file.h>
#include <linux/smp_lock.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
* written by Paul H. Hargrove
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
#include <linux/mm.h>
static int fifo_open(struct inode * inode,struct file * filp)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/string.h>
-#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/file.h>
#include <linux/init.h>
/* SLAB cache for filp's. */
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/termios.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/fcntl.h> /* for f_flags values */
#include <linux/file.h>
#include <asm/uaccess.h>
*/
#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
#include <linux/file.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
* Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
*/
-#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/msdos_fs.h>
-#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/stat.h>
#include <asm/uaccess.h>
* lookup logic.
*/
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <asm/semaphore.h>
-#include <asm/spinlock.h>
#include <asm/page.h>
#include <asm/pgtable.h>
printk("nfs_dentry_iput: pending writes for %s/%s, i_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
#endif
- while (nfs_find_dentry_request(inode, dentry)) {
-#ifdef NFS_PARANOIA
-printk("nfs_dentry_iput: flushing %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
- nfs_flush_dirty_pages(inode, 0, 0, 0);
- }
+ nfs_wbinval(inode);
}
iput(inode);
}
error = -EBUSY;
if (inode) {
if (NFS_WRITEBACK(inode)) {
- nfs_flush_dirty_pages(inode, 0, 0, 0);
+ nfs_wbinval(inode);
if (NFS_WRITEBACK(inode)) {
#ifdef NFS_PARANOIA
printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
printk("nfs_rename: %s/%s has pending writes\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
#endif
- nfs_flush_dirty_pages(old_inode, 0, 0, 0);
+ nfs_wbinval(old_inode);
if (NFS_WRITEBACK(old_inode)) {
#ifdef NFS_PARANOIA
printk("nfs_rename: %s/%s has pending writes after flush\n",
dfprintk(VFS, "nfs: close(%x/%ld)\n", inode->i_dev, inode->i_ino);
- status = nfs_flush_dirty_pages(inode, 0, 0, 0);
+ status = nfs_wbinval(inode);
error = nfs_write_error(inode);
if (!status)
status = error;
dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
- status = nfs_flush_dirty_pages(inode, current->pid, 0, 0);
+ status = nfs_wbinval_pid(inode, current->pid);
error = nfs_write_error(inode);
if (!status)
status = error;
* been killed by a signal, that is). */
if (cmd == F_SETLK && fl->fl_type == F_UNLCK
&& !signal_pending(current)) {
- status = nfs_flush_dirty_pages(inode, current->pid,
+ status = nfs_wb_area(inode, /* current->pid ?*/
fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 :
fl->fl_end - fl->fl_start + 1);
if (status < 0)
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
#endif
- nfs_invalidate_pages(inode);
+ nfs_inval(inode);
while (NFS_WRITEBACK(inode) != NULL &&
time_before(jiffies, timeout)) {
current->state = TASK_INTERRUPTIBLE;
if (!S_ISDIR(inode->i_mode)) {
/* This sends off all dirty pages off to the server.
* Note that this function must not sleep. */
- nfs_invalidate_pages(inode);
+ nfs_inval(inode);
invalidate_inode_pages(inode);
} else
nfs_invalidate_dircache(inode);
* Try to flush any pending writes to the file..
*
* NOTE! Because we own the page lock, there cannot
- * be any new pending writes generated at this point.
+ * be any new pending writes generated at this point
+ * for this page (other pages can be written to).
*/
- error = nfs_flush_pages(inode, 0, 0, 0);
+ error = nfs_wb_page(inode, page);
if (error)
return error;
}
/*
- * Try to flush any dirty pages, returning a success marker..
- *
- * Unlike "nfs_flush_dirty_pages()" this does not invalidate
- * the writes if it is interrupted. The caller will instead
- * look at the error code and gracefully fail to do what it
- * wanted to do.
+ * If we're waiting on somebody else's request
+ * we need to increment the counter during the
+ * wait so that the request doesn't disappear
+ * from under us during the wait..
*/
-int
-nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+static int FASTCALL(wait_on_other_req(struct nfs_wreq *));
+static int wait_on_other_req(struct nfs_wreq *req)
{
int retval;
+ req->wb_count++;
+ retval = wait_on_write_request(req);
+ free_write_request(req);
+ return retval;
+}
- do {
- struct nfs_wreq *req = NFS_WRITEBACK(inode);
- struct nfs_wreq *head = req;
+/*
+ * This writes back a set of requests according to the condition.
+ *
+ * If this ever gets much more convoluted, use a fn pointer for
+ * the condition..
+ */
+#define NFS_WB(inode, cond) { int retval = 0 ; \
+ do { \
+ struct nfs_wreq *req = NFS_WRITEBACK(inode); \
+ struct nfs_wreq *head = req; \
+ if (!req) break; \
+ for (;;) { \
+ if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \
+ if (cond) break; \
+ req = WB_NEXT(req); \
+ if (req == head) goto out; \
+ } \
+ retval = wait_on_other_req(req); \
+ } while (!retval); \
+out: return retval; \
+}
- if (!req)
- return 0;
+int
+nfs_wb_all(struct inode *inode)
+{
+ NFS_WB(inode, 1);
+}
- /*
- * Iterate over all outstanding write requests,
- * looking for any that are ours..
- */
- for (;;) {
- if (!(req->wb_flags & NFS_WRITE_COMPLETE)) {
- if (!pid || req->wb_pid == pid)
- break;
- }
- req = WB_NEXT(req);
- if (req == head)
- return 0;
- }
+/*
+ * Write back all requests on one page - we do this before reading it.
+ */
+int
+nfs_wb_page(struct inode *inode, struct page *page)
+{
+ NFS_WB(inode, req->wb_page == page);
+}
- req->wb_count++;
- retval = wait_on_write_request(req);
- free_write_request(req);
- } while (!retval);
- return retval;
-}
+/*
+ * Write back all pending writes for one user..
+ */
+int
+nfs_wb_pid(struct inode *inode, pid_t pid)
+{
+ NFS_WB(inode, req->wb_pid == pid);
+}
/*
- * Flush out all dirty pages belonging to a certain user process and
- * maybe wait for the RPC calls to complete.
- *
- * Another purpose of this function is sync()ing a file range before a
- * write lock is released. This is what offset and length are for, even if
- * this isn't used by the nlm module yet.
+ * Write back everything in a specific area for locking purposes..
*/
int
-nfs_flush_dirty_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
+nfs_wb_area(struct inode *inode, off_t offset, off_t len)
{
- int retval = nfs_flush_pages(inode, pid, offset, len);
+ NFS_WB(inode, 1);
+}
+
+/*
+ * Write back and invalidate. Sometimes we can't leave the stuff
+ * hanging if we can't write it out.
+ */
+int
+nfs_wbinval(struct inode *inode)
+{
+ int retval = nfs_wb_all(inode);
+
+ if (retval)
+ nfs_cancel_dirty(inode,0);
+ return retval;
+}
+
+int nfs_wbinval_pid(struct inode *inode, pid_t pid)
+{
+ int retval = nfs_wb_pid(inode, pid);
+
if (retval)
nfs_cancel_dirty(inode,pid);
return retval;
}
void
-nfs_invalidate_pages(struct inode *inode)
+nfs_inval(struct inode *inode)
{
nfs_cancel_dirty(inode,0);
}
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/vfs.h>
-#include <linux/types.h>
+#include <linux/mm.h>
#include <linux/utime.h>
-#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/tty.h>
-#include <linux/time.h>
-#include <linux/mm.h>
#include <linux/file.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/poll.h>
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/types.h>
-#include <linux/errno.h>
+#include <linux/malloc.h>
#include <linux/stat.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/file.h>
-#include <linux/mm.h>
#include <linux/uio.h>
-#include <linux/malloc.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/limits.h>
#include <asm/uaccess.h>
* parameter to reflect time remaining.
*/
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/personality.h>
-#include <linux/mm.h>
#include <linux/malloc.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
#include <linux/file.h>
-#include <linux/kernel.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
* Added change_root: Werner Almesberger & Hans Lermen, Feb '96
*/
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mount.h>
#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/fd.h>
#include <linux/init.h>
#include <linux/quotaops.h>
#include <linux/acct.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */
#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */
#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */
+#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */
+#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */
+#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */
+#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */
+#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
/* values */
#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */
#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */
+#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */
#define FB_ACCELF_TEXT 1 /* text mode acceleration */
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/kernel.h>
#ifdef __KERNEL__
extern int nfs_find_dentry_request(struct inode *, struct dentry *);
extern int nfs_check_failed_request(struct inode *);
extern int nfs_check_error(struct inode *);
-extern int nfs_flush_pages(struct inode *, pid_t, off_t, off_t);
-extern int nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
+
+/*
+ * Try to write back everything synchronously (but check the
+ * return value!)
+ */
+extern int nfs_wb_all(struct inode *);
+extern int nfs_wb_page(struct inode *, struct page *);
+extern int nfs_wb_pid(struct inode *, pid_t);
+extern int nfs_wb_area(struct inode *, off_t, off_t);
+
+/*
+ * Invalidate write-backs, possibly trying to write them
+ * back first..
+ */
+extern void nfs_inval(struct inode *);
+extern int nfs_wbinval(struct inode *);
+extern int nfs_wbinval_pid(struct inode *, pid_t);
+
extern int nfs_truncate_dirty_pages(struct inode *, unsigned long);
-extern void nfs_invalidate_pages(struct inode *);
extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int);
/*
PROC_NET_NETSTAT,
PROC_NET_IPFW_CHAINS,
PROC_NET_IPFW_CHAIN_NAMES,
+ PROC_NET_AT_AARP,
PROC_NET_LAST
};
PROC_SCSI_ULTRASTOR,
PROC_SCSI_7000FASST,
PROC_SCSI_IBMMCA,
+ PROC_SCSI_FD_MCS,
PROC_SCSI_EATA2X,
PROC_SCSI_DC390T,
PROC_SCSI_AM53C974,
{
extern void scsi_init_free(char *ptr, unsigned int size);
- if(x <= PROC_SCSI_FILE)
+ if(x < PROC_SCSI_FILE)
return(proc_unregister(proc_scsi, x));
else {
struct proc_dir_entry **p = &driver->subdir, *dp;
/* ================================================================= */
-#ifdef __mc68000__
+#if defined(__mc68000__)
/* ====================================================================== */
: "d0", "d1", "a0", "a1", "memory");
}
-#else /* !m68k */
-
- /*
- * Anyone who'd like to write asm functions for other CPUs?
- * (Why are these functions better than those from include/asm/string.h?)
- */
-
-#ifndef CONFIG_SUN4
-
-static __inline__ void *mymemclear_small(void *s, size_t count)
-{
- return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemclear(void *s, size_t count)
-{
- return(memset(s, 0, count));
-}
-
-static __inline__ void *mymemset(void *s, size_t count)
-{
- return(memset(s, 255, count));
-}
-
-#else
+#elif defined(CONFIG_SUN4)
/* You may think that I'm crazy and that I should use generic
routines. No, I'm not: sun4's framebuffer crashes if we std
{
return sun4_memset(s, 0, count);
}
-#endif
-#ifdef __i386__
+/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
+static __inline__ void fast_memmove(void *d, const void *s, size_t count)
+{
+ int i;
+ if (d<s) {
+ for (i=0; i<count; i++)
+ ((char *) d)[i] = ((char *) s)[i];
+ } else
+ for (i=0; i<count; i++)
+ ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
+}
+
+static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+{
+ fast_memmove(dst, src, size);
+ return dst;
+}
+
+#else
+
+static __inline__ void *mymemclear_small(void *s, size_t count)
+{
+ return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemclear(void *s, size_t count)
+{
+ return(memset(s, 0, count));
+}
+
+static __inline__ void *mymemset(void *s, size_t count)
+{
+ return(memset(s, 255, count));
+}
+
+#if defined(__i386__)
+
static __inline__ void fast_memmove(void *d, const void *s, size_t count)
{
if (d < s) {
return dst;
}
-#else
+#else /* !i386 */
-#ifdef CONFIG_SUN4
-/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
-static __inline__ void fast_memmove(void *d, const void *s, size_t count)
-{
- int i;
- if (d<s) {
- for (i=0; i<count; i++)
- ((char *) d)[i] = ((char *) s)[i];
- } else
- for (i=0; i<count; i++)
- ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
-}
-
-static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
-{
- fast_memmove(dst, src, size);
- return dst;
-}
-
-#else
+ /*
+ * Anyone who'd like to write asm functions for other CPUs?
+ * (Why are these functions better than those from include/asm/string.h?)
+ */
static __inline__ void *mymemmove(void *d, const void *s, size_t count)
{
memmove(dst, src, size);
}
-#endif /* !sun4 */
-
#endif /* !i386 */
-#endif /* !m68k */
+#endif
#endif /* _VIDEO_FBCON_H */
#ifdef CONFIG_MDA_CONSOLE
extern void mdacon_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_LTPC
+extern void ltpc_setup(char *str, int *ints);
+#endif
#if defined(CONFIG_SYSVIPC)
extern void ipc_init(void);
char *cur = str;
int i=1;
- while (cur && isdigit(*cur) && i <= 10) {
+ while (cur && (*cur=='-' || isdigit(*cur)) && i <= 10) {
ints[i++] = simple_strtol(cur,NULL,0);
if ((cur = strchr(cur,',')) != NULL)
cur++;
#endif
#ifdef CONFIG_MACMOUSE
{ "adb_buttons=", adb_mouse_setup },
+#endif
+#ifdef CONFIG_LTPC
+ { "ltpc=", ltpc_setup },
#endif
{ 0, 0 }
};
* Inside AppleTalk (2nd Ed).
* Fixes:
* Jaume Grau - flush caches on AARP_PROBE
+ * Rob Newberry - Added proxy AARP and AARP proc fs,
+ * moved probing from DDP module.
*
*/
#include <net/psnap.h>
#include <linux/atalk.h>
#include <linux/init.h>
+#include <linux/proc_fs.h>
int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
/* These first two are only used for unresolved entries */
unsigned long last_sent; /* Last time we xmitted the aarp request */
struct sk_buff_head packet_queue; /* Queue of frames wait for resolution */
+ int status; /* Used for proxy AARP */
unsigned long expires_at; /* Entry expiry time */
struct at_addr target_addr; /* DDP Address */
struct device *dev; /* Device to use */
struct aarp_entry *next; /* Next entry in chain */
};
-
/*
- * Hashed list of resolved and unresolved entries
+ * Hashed list of resolved, unresolved and proxy entries
*/
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
static int unresolved_count=0;
/*
}
/*
- * Send probe frames. Called from atif_probe_device.
+ * Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
*/
void aarp_send_probe(struct device *dev, struct at_addr *us)
aarp_expire_timer(&resolved[ct]);
aarp_kick(&unresolved[ct]);
aarp_expire_timer(&unresolved[ct]);
+ aarp_expire_timer(&proxies[ct]);
}
del_timer(&aarp_timer);
if(unresolved_count==0)
{
aarp_expire_device(&resolved[ct],ptr);
aarp_expire_device(&unresolved[ct],ptr);
+ aarp_expire_device(&proxies[ct],ptr);
}
}
return NOTIFY_DONE;
return list;
}
+void aarp_proxy_remove(struct device *dev, struct at_addr *sa)
+{
+ struct aarp_entry *a;
+ int hash;
+
+ hash = sa->s_node % (AARP_HASH_SIZE-1);
+ a = aarp_find_entry(proxies[hash], dev, sa);
+ if (a)
+ {
+ a->expires_at = 0;
+
+ }
+}
+
+struct at_addr* aarp_proxy_find(struct device *dev, struct at_addr *sa)
+{
+ struct aarp_entry *a;
+ int hash;
+
+ hash = sa->s_node % (AARP_HASH_SIZE-1);
+ a = aarp_find_entry(proxies[hash], dev, sa);
+ if (a != NULL)
+ return sa;
+
+ return NULL;
+}
+
+
+/*
+ * Probe a Phase 1 device or a device that requires its Net:Node to
+ * be set via an ioctl.
+ */
+void aarp_send_probe_phase1(struct atalk_iface *iface)
+{
+ struct ifreq atreq;
+ struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
+
+ sa->sat_addr.s_node = iface->address.s_node;
+ sa->sat_addr.s_net = ntohs(iface->address.s_net);
+
+ /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+ if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
+ {
+ (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+ if((iface->address.s_net != htons(sa->sat_addr.s_net))
+ || (iface->address.s_node != sa->sat_addr.s_node))
+ iface->status |= ATIF_PROBE_FAIL;
+
+ iface->address.s_net = htons(sa->sat_addr.s_net);
+ iface->address.s_node = sa->sat_addr.s_node;
+ }
+
+ return;
+}
+
+
+void aarp_probe_network(struct atalk_iface *atif)
+{
+ if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+ aarp_send_probe_phase1(atif);
+ else
+ {
+ unsigned int count;
+ for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+ {
+ aarp_send_probe(atif->dev, &atif->address);
+
+ /*
+ * Defer 1/10th
+ */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+
+ if (atif->status & ATIF_PROBE_FAIL)
+ break;
+ }
+ }
+}
+
+int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
+{
+ struct aarp_entry *entry;
+ unsigned int count;
+ int hash;
+
+ /*
+ * we don't currently support LocalTalk or PPP for proxy AARP;
+ * if someone wants to try and add it, have fun
+ */
+ if (atif->dev->type == ARPHRD_LOCALTLK)
+ return (-EPROTONOSUPPORT);
+
+ if (atif->dev->type == ARPHRD_PPP)
+ return (-EPROTONOSUPPORT);
+
+ /*
+ * create a new AARP entry with the flags set to be published --
+ * we need this one to hang around even if it's in use
+ */
+ entry = aarp_alloc();
+ if (entry == NULL)
+ return (-ENOMEM);
+
+ entry->expires_at = -1;
+ entry->status = ATIF_PROBE;
+ entry->target_addr.s_node = sa->s_node;
+ entry->target_addr.s_net = sa->s_net;
+ entry->dev = atif->dev;
+
+ hash = sa->s_node % (AARP_HASH_SIZE-1);
+ entry->next = proxies[hash];
+ proxies[hash] = entry;
+
+ for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+ {
+ aarp_send_probe(atif->dev, sa);
+
+ /*
+ * Defer 1/10th
+ */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+
+ if (entry->status & ATIF_PROBE_FAIL)
+ break;
+ }
+
+ /*
+ * FIX ME: I think we need exclusive access to the status flags,
+ * in case some one fails the probe while we're removing
+ * the probe flag.
+ */
+ if (entry->status & ATIF_PROBE_FAIL)
+ {
+ /* free the entry */
+ entry->expires_at = 0;
+
+ /* return network full */
+ return (-EADDRINUSE);
+ }
+ else
+ {
+ /* clear the probing flag */
+ entry->status &= ~ATIF_PROBE;
+ }
+
+ return 1;
+}
+
+
/*
* Send a DDP frame
*/
{
struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
struct aarp_entry *a;
- struct at_addr sa, *ma;
+ struct at_addr sa, *ma, da;
unsigned long flags;
int hash;
struct atalk_iface *ifa;
kfree_skb(skb);
return 1;
}
- }
+ }
+ /*
+ * Check for replies of proxy AARP entries
+ */
+
+ /*
+ * FIX ME: do we need a cli() here?
+ * aarp_find_entry does one on its own, between saving and restoring flags, so
+ * I don't think it is necessary, but I could be wrong -- it's happened before
+ */
+ da.s_node = ea->pa_dst_node;
+ da.s_net = ea->pa_dst_net;
+ a = aarp_find_entry(proxies[hash], dev, &da);
+ if (a != NULL)
+ if (a->status & ATIF_PROBE)
+ {
+ a->status |= ATIF_PROBE_FAIL;
+
+ /*
+ * we do not respond to probe or request packets for
+ * this address while we are probing this address
+ */
+ restore_flags(flags);
+ kfree_skb(skb);
+ return 1;
+ }
+
switch(ea->function)
{
case AARP_REPLY:
* Find the entry
*/
- cli();
+ cli(); /* FIX ME: is this cli() necessary? aarp_find_entry does one on its own... */
if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
break;
/*
* If it is my address set ma to my address and reply. We can treat probe and
* request the same. Probe simply means we shouldn't cache the querying host,
* as in a probe they are proposing an address not using one.
+ *
+ * Support for proxy-AARP added. We check if the address is one
+ * of our proxies before we toss the packet out.
*/
- ma=&ifa->address;
sa.s_node=ea->pa_dst_node;
sa.s_net=ea->pa_dst_net;
-
+
+ /*
+ * see if we have a matching proxy
+ */
+ ma = aarp_proxy_find(dev, &sa);
+ if (!ma)
+ {
+ ma=&ifa->address;
+ }
+ else
+ {
+ /*
+ * we need to make a copy of the entry
+ */
+ da.s_node = sa.s_node;
+ da.s_net = da.s_net;
+ ma = &da;
+ }
+
if(ea->function==AARP_PROBE)
{
/* A probe implies someone trying to get an
{
aarp_expire_device(&resolved[ct], dev);
aarp_expire_device(&unresolved[ct], dev);
+ aarp_expire_device(&proxies[ct], dev);
}
return;
}
+/*
+ * Called from proc fs
+ */
+int aarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ /* we should dump all our AARP entries */
+ struct aarp_entry *entry;
+ int len, ct;
+
+ len = sprintf(buffer,
+ "%-10.10s ""%-10.10s""%-18.18s""%12.12s""%12.12s"" xmit_count status\n",
+ "address","device","hw addr","last_sent", "expires");
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+ {
+ for (entry = resolved[ct]; entry; entry = entry->next)
+ {
+ len+= sprintf(buffer+len,"%6u:%-3u ",
+ (unsigned int)ntohs(entry->target_addr.s_net),
+ (unsigned int)(entry->target_addr.s_node));
+ len+= sprintf(buffer+len,"%-10.10s",
+ entry->dev->name);
+ len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ (int)(entry->hwaddr[0] & 0x000000FF),
+ (int)(entry->hwaddr[1] & 0x000000FF),
+ (int)(entry->hwaddr[2] & 0x000000FF),
+ (int)(entry->hwaddr[3] & 0x000000FF),
+ (int)(entry->hwaddr[4] & 0x000000FF),
+ (int)(entry->hwaddr[5] & 0x000000FF));
+ len+= sprintf(buffer+len,"%12lu ""%12lu ",
+ (unsigned long)entry->last_sent,
+ (unsigned long)entry->expires_at);
+ len+=sprintf(buffer+len,"%10u",
+ (unsigned int)entry->xmit_count);
+
+ len+=sprintf(buffer+len," resolved\n");
+ }
+ }
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+ {
+ for (entry = unresolved[ct]; entry; entry = entry->next)
+ {
+ len+= sprintf(buffer+len,"%6u:%-3u ",
+ (unsigned int)ntohs(entry->target_addr.s_net),
+ (unsigned int)(entry->target_addr.s_node));
+ len+= sprintf(buffer+len,"%-10.10s",
+ entry->dev->name);
+ len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ (int)(entry->hwaddr[0] & 0x000000FF),
+ (int)(entry->hwaddr[1] & 0x000000FF),
+ (int)(entry->hwaddr[2] & 0x000000FF),
+ (int)(entry->hwaddr[3] & 0x000000FF),
+ (int)(entry->hwaddr[4] & 0x000000FF),
+ (int)(entry->hwaddr[5] & 0x000000FF));
+ len+= sprintf(buffer+len,"%12lu ""%12lu ",
+ (unsigned long)entry->last_sent,
+ (unsigned long)entry->expires_at);
+ len+=sprintf(buffer+len,"%10u",
+ (unsigned int)entry->xmit_count);
+ len+=sprintf(buffer+len," unresolved\n");
+ }
+ }
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+ {
+ for (entry = proxies[ct]; entry; entry = entry->next)
+ {
+ len+= sprintf(buffer+len,"%6u:%-3u ",
+ (unsigned int)ntohs(entry->target_addr.s_net),
+ (unsigned int)(entry->target_addr.s_node));
+ len+= sprintf(buffer+len,"%-10.10s",
+ entry->dev->name);
+ len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ (int)(entry->hwaddr[0] & 0x000000FF),
+ (int)(entry->hwaddr[1] & 0x000000FF),
+ (int)(entry->hwaddr[2] & 0x000000FF),
+ (int)(entry->hwaddr[3] & 0x000000FF),
+ (int)(entry->hwaddr[4] & 0x000000FF),
+ (int)(entry->hwaddr[5] & 0x000000FF));
+ len+= sprintf(buffer+len,"%12lu ""%12lu ",
+ (unsigned long)entry->last_sent,
+ (unsigned long)entry->expires_at);
+ len+=sprintf(buffer+len,"%10u",
+ (unsigned int)entry->xmit_count);
+ len+=sprintf(buffer+len," proxy\n");
+ }
+ }
+
+
+ return len;
+}
+
#ifdef MODULE
/*
* General module cleanup. Called from cleanup_module() in ddp.c.
}
#endif /* MODULE */
+
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry proc_aarp_entries=
+{
+ PROC_NET_AT_AARP, 4, "aarp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ aarp_get_info
+};
+
+void aarp_register_proc_fs(void)
+{
+ proc_net_register(&proc_aarp_entries);
+}
+
+void aarp_unregister_proc_fs(void)
+{
+ proc_net_unregister(PROC_NET_AT_AARP);
+}
+
+#endif
+
#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
* driver file. (ipddp.c & ipddp.h)
* Jay Schulist : Made work as module with
* AppleTalk drivers, cleaned it.
+ * Rob Newberry : Added proxy AARP and AARP proc fs,
+ * moved probing to AARP module.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+extern void aarp_register_proc_fs(void);
+extern void aarp_unregister_proc_fs(void);
+#endif
+
+extern void aarp_probe_network(struct atalk_iface *atif);
+extern int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa);
+extern void aarp_proxy_remove(struct device *dev, struct at_addr *sa);
+
+
#undef APPLETALK_DEBUG
#ifdef APPLETALK_DEBUG
return (iface);
}
-/*
- * Probe a Phase 1 device or a device that requires its Net:Node to
- * be set via an ioctl.
- */
-void atif_send_probe_phase1(struct atalk_iface *iface)
-{
- struct ifreq atreq;
- struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
-
- sa->sat_addr.s_node = iface->address.s_node;
- sa->sat_addr.s_net = ntohs(iface->address.s_net);
-
- /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
- if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
- {
- (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
- if((iface->address.s_net != htons(sa->sat_addr.s_net))
- || (iface->address.s_node != sa->sat_addr.s_node))
- iface->status |= ATIF_PROBE_FAIL;
-
- iface->address.s_net = htons(sa->sat_addr.s_net);
- iface->address.s_node = sa->sat_addr.s_node;
- }
-
- return;
-}
/*
* Perform phase 2 AARP probing on our tentative address.
int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
int probe_net=ntohs(atif->address.s_net);
int probe_node=atif->address.s_node;
- int ct, netct, nodect;
+ int netct, nodect;
/*
* Offset the network we start probing with.
/*
* Probe a proposed address.
*/
+ aarp_probe_network(atif);
- if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
- atif_send_probe_phase1(atif);
- else
- {
- for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++)
- {
- aarp_send_probe(atif->dev, &atif->address);
- /*
- * Defer 1/10th
- */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/10);
- if(atif->status & ATIF_PROBE_FAIL)
- break;
- }
- }
if(!(atif->status & ATIF_PROBE_FAIL))
return (0);
}
return (-EADDRINUSE); /* Network is full... */
}
+
+/*
+ * Perform AARP probing for a proxy address
+ */
+static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* proxy_addr)
+{
+ int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
+ int probe_net=ntohs(atif->address.s_net); // we probe the interface's network
+ int probe_node=ATADDR_ANYNODE; // we'll take anything
+ int netct, nodect;
+
+ /*
+ * Offset the network we start probing with.
+ */
+
+ if(probe_net == ATADDR_ANYNET)
+ {
+ if(!netrange)
+ probe_net = ntohs(atif->nets.nr_firstnet);
+ else
+ probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+ }
+
+ if(probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies&0xFF;
+
+ /*
+ * Scan the networks.
+ */
+
+ for(netct = 0; netct <= netrange; netct++)
+ {
+ /*
+ * Sweep the available nodes from a given start.
+ */
+
+ proxy_addr->s_net = htons(probe_net);
+ for(nodect = 0; nodect < 256; nodect++)
+ {
+ proxy_addr->s_node = ((nodect+probe_node) & 0xFF);
+ if((proxy_addr->s_node>0) && (proxy_addr->s_node<254))
+ {
+ /*
+ * Tell AARP to probe a proposed address.
+ */
+ int probe_result = aarp_proxy_probe_network(atif, proxy_addr);
+
+ if (probe_result == 0)
+ return 0;
+
+ if (probe_result != -EADDRINUSE)
+ return probe_result;
+ }
+ }
+ probe_net++;
+ if(probe_net > ntohs(atif->nets.nr_lastnet))
+ probe_net = ntohs(atif->nets.nr_firstnet);
+ }
+
+ return (-EADDRINUSE); /* Network is full... */
+}
+
+
struct at_addr *atalk_find_dev_addr(struct device *dev)
{
struct atalk_iface *iface=dev->atalk_ptr;
*/
static struct atalk_route *atrtr_find(struct at_addr *target)
{
+ /*
+ * we must search through all routes unless we find a
+ * host route, because some host routes might overlap
+ * network routes
+ */
struct atalk_route *r;
-
+ struct atalk_route *net_route = NULL;
+
for(r=atalk_router_list; r != NULL; r=r->next)
{
if(!(r->flags & RTF_UP))
continue;
if(r->target.s_net == target->s_net)
{
- if(!(r->flags&RTF_HOST)
- || r->target.s_node == target->s_node)
- return (r);
+ if (r->flags & RTF_HOST)
+ {
+ /*
+ * if this host route is for the target,
+ * the we're done
+ */
+ if (r->target.s_node == target->s_node)
+ return (r);
+ }
+ else
+ {
+ /*
+ * this route will work if there isn't a
+ * direct host route, so cache it
+ */
+ net_route = r;
+ }
}
}
+
+ /*
+ * if we found a network route but not a direct host
+ * route, then return it
+ */
+ if (net_route != NULL)
+ return (net_route);
if(atrtr_default.dev)
return (&atrtr_default);
int ct;
int limit;
struct rtentry rtdef;
+ int add_route;
if(copy_from_user(&atreq,arg,sizeof(atreq)))
return (-EFAULT);
nr=(struct netrange *)&sa->sat_zero[0];
+ add_route = 1;
+
+ /*
+ * if this is a point-to-point iface, and we already have an
+ * iface for this AppleTalk address, then we should not add a route
+ */
+ if (dev->flags & IFF_POINTOPOINT && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node))
+ {
+ printk(KERN_DEBUG "AppleTalk: point-to-point interface added with existing address\n");
+ add_route = 0;
+ }
+
/*
* Phase 1 is fine on LocalTalk but we don't do
* EtherTalk phase 1. Anyone wanting to add it go ahead.
* error and atalkd will try another.
*/
- if(!(dev->flags & IFF_LOOPBACK) && atif_probe_device(atif) < 0)
+ if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0)
{
atif_drop_device(dev);
return (-EADDRINUSE);
rtdef.rt_flags = RTF_UP;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_node = ATADDR_ANYNODE;
- if(dev->flags & IFF_LOOPBACK)
+ if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
rtdef.rt_flags |= RTF_HOST;
/*
printk(KERN_WARNING "Too many routes/iface.\n");
return (-EINVAL);
}
- for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
- {
- sa->sat_addr.s_net = htons(ct);
- atrtr_create(&rtdef, dev);
- }
+ if (add_route)
+ for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
+ {
+ sa->sat_addr.s_net = htons(ct);
+ atrtr_create(&rtdef, dev);
+ }
}
dev_mc_add(dev, aarp_mcast, 6, 1);
return (0);
return (-EINVAL);
atalk_dev_down(dev);
break;
+
+ case SIOCSARP:
+ if(!suser())
+ return (-EPERM);
+ if(sa->sat_family != AF_APPLETALK)
+ return (-EINVAL);
+
+ /*
+ * for now, we only support proxy AARP on ELAP;
+ * we should be able to do it for LocalTalk, too.
+ */
+ if(dev->type != ARPHRD_ETHER)
+ return (-EPROTONOSUPPORT);
+
+ /*
+ * atif points to the current interface on this network;
+ * we aren't concerned about its current status (at least for now),
+ * but it has all the settings about the network we're going
+ * to probe. consequently, it must exist.
+ */
+ if (!atif)
+ return (-EADDRNOTAVAIL);
+
+ nr=(struct netrange *)&(atif->nets);
+ /*
+ * Phase 1 is fine on Localtalk but we don't do
+ * Ethertalk phase 1. Anyone wanting to add it go ahead.
+ */
+ if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+ return (-EPROTONOSUPPORT);
+
+ if(sa->sat_addr.s_node == ATADDR_BCAST
+ || sa->sat_addr.s_node == 254)
+ return (-EINVAL);
+
+ /*
+ * Check if the chosen address is used. If so we
+ * error and ATCP will try another.
+ */
+ if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+ return (-EADDRINUSE);
+
+ /*
+ * We now have an address on the local network, and the AARP
+ * code will defend it for us until we take it down.
+ * We don't set up any routes right now, because ATCP will
+ * install them manually via SIOCADDRT.
+ */
+ break;
+
+ case SIOCDARP:
+ if(!suser())
+ return (-EPERM);
+ if(sa->sat_family != AF_APPLETALK)
+ return (-EINVAL);
+
+ /*
+ * give to aarp module to remove proxy entry
+ */
+ aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+
+ return (0);
}
if(copy_to_user(arg, &atreq, sizeof(atreq)))
static int atrtr_ioctl(unsigned int cmd, void *arg)
{
struct rtentry rt;
+ struct device *dev = NULL;
if(copy_from_user(&rt, arg, sizeof(rt)))
return (-EFAULT);
return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
case SIOCADDRT:
- return (atrtr_create(&rt, NULL));
+ /* FIX ME: the name of the device is still in user space, isn't it? */
+ if (rt.rt_dev != NULL)
+ if ((dev = dev_get(rt.rt_dev)) == NULL)
+ return -(ENODEV);
+
+ return (atrtr_create(&rt, dev));
default:
return (-EINVAL);
case SOCK_DGRAM:
sock->ops = &atalk_dgram_ops;
break;
-
+
+ case SOCK_STREAM:
+ /*
+ * TO DO: if you want to implement ADSP, here's the place to start
+ */
+ /*
+ sock->ops = &atalk_stream_ops;
+ break;
+ */
default:
sk_free((void *)sk);
return (-ESOCKTNOSUPPORT);
*/
if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
{
+ /*
+ * FIX ME:
+ * Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network?
+ */
+ if (dev->type == ARPHRD_PPP)
+ printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
+
kfree_skb(skb);
return (0);
}
case SIOCGIFBRDADDR:
case SIOCATALKDIFADDR:
case SIOCDIFADDR:
+ case SIOCSARP: /* proxy AARP */
+ case SIOCDARP: /* proxy AARP */
return (atif_ioctl(cmd,(void *)arg));
/*
proc_net_register(&proc_appletalk);
proc_net_register(&proc_atalk_route);
proc_net_register(&proc_atalk_iface);
+
+ aarp_register_proc_fs();
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SYSCTL
proc_net_unregister(PROC_NET_ATALK);
proc_net_unregister(PROC_NET_AT_ROUTE);
proc_net_unregister(PROC_NET_ATIF);
+
+ aarp_unregister_proc_fs();
#endif /* CONFIG_PROC_FS */
aarp_cleanup_module(); /* General aarp clean-up. */
return 1;
}
+#else /* INET */
+
+int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ return -AX25_HEADER_LEN;
+}
+
+int ax25_rebuild_header(struct sk_buff *skb)
+{
+ return 1;
+}
+
#endif
#endif
extern void destroy_EII_client(struct datalink_proto *);
extern void destroy_8023_client(struct datalink_proto *);
+#ifdef CONFIG_PROC_FS
struct proc_dir_entry ipx_procinfo = {
PROC_NET_IPX, 3, "ipx", S_IFREG | S_IRUGO,
1, 0, 0, 0, &proc_net_inode_operations, ipx_get_info
PROC_NET_IPX_ROUTE, 9, "ipx_route", S_IFREG | S_IRUGO,
1, 0, 0, 0, &proc_net_inode_operations, ipx_rt_get_info
};
+#endif
static unsigned char ipx_8022_type = 0xE0;
static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
#include <linux/types.h>
#include <linux/net.h>
#include <linux/in.h>
+#include <net/sock.h>
+#include <net/dst.h>
+#include <net/checksum.h>
+#include <net/pkt_sched.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
#include <linux/trdevice.h>
#include <linux/ioport.h>
#include <net/neighbour.h>
#ifdef CONFIG_INET
#include <linux/ip.h>
-#include <linux/etherdevice.h>
-#include <linux/fddidevice.h>
#include <net/protocol.h>
#include <net/arp.h>
#include <net/ip.h>
#include <net/route.h>
#include <net/scm.h>
#include <net/inet_common.h>
-#include <net/pkt_sched.h>
#include <linux/inet.h>
#include <linux/mroute.h>
#include <linux/igmp.h>
extern struct net_proto_family inet_family_ops;
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
+#endif
+
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
#include <linux/in6.h>
#include <linux/icmpv6.h>
extern int tcp_tw_death_row_slot;
#endif
-#endif
#include <linux/rtnetlink.h>
EXPORT_SYMBOL(icmp_send);
EXPORT_SYMBOL(ip_options_compile);
EXPORT_SYMBOL(arp_send);
-#ifdef CONFIG_SHAPER_MODULE
-EXPORT_SYMBOL(arp_broken_ops);
-#endif
EXPORT_SYMBOL(ip_id_count);
EXPORT_SYMBOL(ip_send_check);
EXPORT_SYMBOL(ip_fragment);
EXPORT_SYMBOL(inet_dgram_ops);
EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(__release_sock);
+EXPORT_SYMBOL(arp_find);
+EXPORT_SYMBOL(ip_rcv);
+EXPORT_SYMBOL(arp_rcv);
/* needed for ip_gre -cw */
EXPORT_SYMBOL(ip_statistics);
EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_close);
EXPORT_SYMBOL(dev_mc_add);
-EXPORT_SYMBOL(arp_find);
EXPORT_SYMBOL(n_tty_ioctl);
EXPORT_SYMBOL(tty_register_ldisc);
EXPORT_SYMBOL(kill_fasync);
-EXPORT_SYMBOL(ip_rcv);
-EXPORT_SYMBOL(arp_rcv);
EXPORT_SYMBOL(dev_mc_delete);
EXPORT_SYMBOL(if_port_text);
EXPORT_SYMBOL(ltalk_setup);
#endif
-#ifdef CONFIG_DLCI_MODULE
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-EXPORT_SYMBOL(dlci_ioctl_hook);
-#endif
/* Packet scheduler modules want these. */
EXPORT_SYMBOL(qdisc_destroy);