The module will be called isp16.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-Preload dcache
-CONFIG_DCACHE_PRELOAD
- Preloading will create dcache entries when a directory is scanned
- (e.g. because the ls command was used) for the *first* time. This
- should speed up successive lookups of information about files in
- that directory, but can also consume large amounts of memory.
-
- Please report speedups (or slowdowns due to the memory usage if they
- occur) to schoebel@informatik.uni-stuttgart.de .
-
- If unsure, say N.
-
Quota support
CONFIG_QUOTA
If you say Y here, you will be able to set per user limits for disk
ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
support is only useful for multi user systems. If unsure, say N.
-Online mirror support
-CONFIG_OMIRR
- omirr is a package for _symmetric_ mirroring of files over the
- Internet. In contrast to rdist, the online mirror daemon (omirrd) is
- running all the time and transfers any changes on the file system as
- soon as possible to all other servers. Symmetric means that all
- servers have equal rights in changing a file: the last changer of a
- file will win. This is the same behaviour as multiple processes
- operating on a global file system. In effect, omirr can do the same
- as NFS mounts, but will have better performance since the data is
- stored on local disks. In contrast to a cache filesystem which has a
- dedicated master copy, broken connections and/or servers are no
- problem for continuing work on the remaining ones, because there is
- no master copy. Every computer that wants to participate in the
- mirroring needs to run the daemon omirrd, contained in the omirr
- package which is available via FTP (user: anonymous) from
- ftp://ftp.isa.de/pub/home/luik. You must say Y if you want to use
- in.omirrd, but you should (but need not) say N if you don't (for
- performance reasons).
-
- Note that this is experimental code; use at your own risk.
-
-Filename translation support
-CONFIG_TRANS_NAMES
- This is a useful feature if you have a pool of diskless Linux
- clients which mount their root filesystems from a central
- server. Depending on their hostnames, the clients can then see
- different versions of certain files, which keeps maintenance at a
- minimum when used for configuration files. The kernel running on the
- clients should have this option enabled. If you don't administer a
- pool of Linux clients, say N here, otherwise read on:
-
- When you say Y here, filenames, directory names etc become
- context-sensitive. If you have a file named
- "/etc/config#host=banana#", it will appear (by default) as
- hardlinked to "/etc/config" on host "banana", while on host "mango"
- another file "/etc/config#host=mango#" will appear as having been
- hardlinked to "/etc/config".
- This default behaviour can be changed by setting the _first_
- environment variable NAMETRANS to a colon-separated list of suffixes
- which are tried in the specified order. For example, in
-
- 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...'
-
- the command will see the same files as if it had been executed on
- host "mango" with a diskless kernel.
-
- Using NAMETRANS supersedes _all_ default translations. Thus
- translations can be completely switched off with an empty list,
- e.g.
-
- 'env - NAMETRANS= "`env`" command ...'
-
- Note that some system utilities like tar, dump, restore should be
- used with translation switched off, in order to avoid doubled space
- in archive files and when extracting from them. Also, make sure that
- nfsd, mountd (and similar ones like samba daemons) run without
- translation, in order to avoid doubled (or even wrong) translation
- at the server and at the client.
-
- You can automatically force the creation of context-dependent
- filenames if there exists a template filename like
- "/etc/mtab#host=CREATE#". As soon as a process running on "mango"
- tries to create a file "/etc/mtab", the version
- "/etc/mtab#host=mango#" is created instead (which appears in turn as
- hardlinked to "/etc/mtab"). Note that if you want to make
- "/etc/fstab" context-dependent, you should execute "touch
- /etc/mtab#host=CREATE#" and "touch /etc/mtab.tmp#host=CREATE#",
- because mount, umount and others running on different hosts would
- otherwise try to create one shared /etc/mtab which would result in a
- clash. Also one should execute "touch /etc/nologin#host=CREATE#" to
- prevent global side effects from shutdown resp. runlevel.
-
- Please read Documentation/transname.txt if you intend to say Y here.
-
-Restrict translation to gid
-CONFIG_TRANS_RESTRICT
- If you say Y here, default filename translations are carried out
- only if the parent directory of the context-sensitive file belongs
- to a specific group id (gid). Trying to translate names everywhere
- will decrease performance of file openings. Normally translations
- are used only in system configuration files but not in ordinary user
- file space. So you should change the gid of directories containing
- context-dependent files to some special group like "adm" (group id
- 4) and enable this option. As a result, users will not notice any
- performance degradation resulting from filename translation.
-
- Note that translations resulting from the first environment variable
- "NAMETRANS=..." are always carried out regardless of the gid of
- directories.
-
- Beware: before turning on this option make sure that all directories
- containing context-dependent files belong to the special group, or
- system initialization may fail. If unsure, select N.
-
-Group id (gid) for translation restriction
-CONFIG_TRANS_GID
- Default name translations will be carried out only inside directories
- belonging to the group id (gid) that you specify here.
- Default is 4 (group "adm").
-
-Nodename (hostname) translation
-CONFIG_TR_NODENAME
- Enables translation of name suffixes like in
- "/etc/config#host=banana#". The syntax is
- <filename>#host=<hostname>#. The hostname can be queried with the
- command "uname -n". Normally this option is used heavily when
- translation is enabled. If unsure, say Y.
-
-Kernelname translation
-CONFIG_TR_KERNNAME
- Enables translation of name suffixes like in
- "/etc/config#kname=default#". The string is hard compiled into the
- kernel by the following option. Useful if your kernel does not know
- the hostname at boot time, and there is no way to tell the hostname
- by lilo or bootp. Please avoid using this option and prefer
- "Nodename (hostname) translation" (CONFIG_TR_NODENAME) wherever
- possible. When mounting the root over NFS, the own hostname must be
- known at boot time anyway; this option is just for special use.
- Note that the default translations are tried in the order as
- occurring in the configuration, that is 1) host 2) kname 3) ktype 4)
- machine 5) system. If unsure, say Y.
-
-String for kernelname translation
-CONFIG_KERNNAME
- Enter the string you want to compile into the kernel. The string
- will be used as context in context-dependent files like
- "/etc/config#kname=<string>#".
-
-Kerneltype translation
-CONFIG_TR_KERNTYPE
- Enables translation of name suffixes like in
- "/etc/config#ktype=default#". The syntax is
- <filename>#ktype=<string>#. The string is hard compiled in the
- kernel by the following option. Use if you want to create different
- kernels with different behaviour. For example, use the string
- "default" on your server, and use "diskless" on all your diskless
- clients (and perhaps "dataless" on dataless clients). This way you
- can avoid dozens of "config#host=<something># with same contents and
- you have no effort when new machines are added. If unsure, say Y.
-
-String for kerneltype translation
-CONFIG_KERNTYPE
- Enter the string you want to compile into the kernel. The string
- will be used as context in context-dependent files like
- "/etc/config#ktype=default#". If your kernel is to be used on a
- server, you probably can use "default" here. If your kernel is
- intended for a diskless client, you probably should enter "diskless"
- here.
-
-Machine type translation
-CONFIG_TR_MACHINE
- Enables translation of name suffixes like in
- "/etc/config#machine=i486#". The syntax is
- <filename>#machine=<id>#. The machine types can be queried with the
- command "uname -m". Normally used only on multi-architecture
- installations. If unsure, say Y.
-
-System name translation
-CONFIG_TR_SYSNAME
- Enables translation of name suffixes like in
- "/etc/config#system=Linux#". The syntax is
- <filename>#system=<id>#. The system name can be queried with the
- command "uname -s". Currently only supported by Linux, but hopefully
- other operating systems will pick up the idea of context-dependent
- translations. If unsure, say Y.
-
Minix fs support
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about
W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
S: Maintained
+IP FIREWALL
+P: Paul Russell
+M: Paul.Russell@rustcorp.com.au
+W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S: Maintained
+
IPX/SPX NETWORK LAYER
P: Jay Schulist
M: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
JOYSTICK DRIVER
P: Vojtech Pavlik
M: vojtech@atrey.karlin.mff.cuni.cz
+W: http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
L: linux-joystick@atrey.karlin.mff.cuni.cz
S: Maintained
L: linux-net@vger.rutgers.edu
S: Supported
+SPX NETWORK LAYER
+P: Jay Schulist
+M: Jay.Schulist@spacs.k12.wi.us
+L: linux-net@vger.rutgers.edu
+S: Supported
+
STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
P: Greg Ungerer
M: support@stallion.oz.au
rm -f core `find . -name '.*.flags' -print`
rm -f vmlinux System.map
rm -f .tmp*
- rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash
+ rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
+ rm -f drivers/char/conmakehash
rm -f drivers/sound/bin2hex drivers/sound/hex2hex
if [ -d modules ]; then \
rm -f core `find modules/ -type f -print`; \
mask_IO_APIC_irq(irq);
}
-/*
- * Enter and exit the irq handler context..
- */
-static inline void enter_ioapic_irq(int cpu)
-{
- hardirq_enter(cpu);
- while (test_bit(0,&global_irq_lock)) barrier();
-}
-
-static inline void exit_ioapic_irq(int cpu)
-{
- hardirq_exit(cpu);
- release_irqlock(cpu);
-}
-
static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
{
irq_desc_t *desc = irq_desc + irq;
if (!action)
return;
- enter_ioapic_irq(cpu);
+ irq_enter(cpu, irq);
/*
* Edge triggered interrupts need to remember
desc->status &= IRQ_DISABLED;
spin_unlock(&irq_controller_lock);
- exit_ioapic_irq(cpu);
+ irq_exit(cpu, irq);
}
static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
if (!action)
return;
- enter_ioapic_irq(cpu);
+ irq_enter(cpu, irq);
handle_IRQ_event(irq, regs);
unmask_IO_APIC_irq(irq);
spin_unlock(&irq_controller_lock);
- exit_ioapic_irq(cpu);
+ irq_exit(cpu, irq);
}
/*
void * addr;
struct vm_struct * area;
- if (phys_addr < virt_to_phys(high_memory))
+ /*
+ * Don't remap the low PCI/ISA area, it's always mapped..
+ */
+ if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000)
return phys_to_virt(phys_addr);
+
+ /*
+ * Don't allow anybody to remap normal RAM that we're using..
+ */
+ if (phys_addr < virt_to_phys(high_memory))
+ return NULL;
+
+ /*
+ * Mappings have to be page-aligned
+ */
if (phys_addr & ~PAGE_MASK)
return NULL;
size = PAGE_ALIGN(size);
+
+ /*
+ * Don't allow mappings that wrap..
+ */
if (!size || size > phys_addr + size)
return NULL;
+
+ /*
+ * Ok, go for it..
+ */
area = get_vm_area(size);
if (!area)
return NULL;
return p;
}
-static inline void scrolldelta(int lines)
+static void scrolldelta(int lines)
{
int currcons = fg_console;
a ^= 0x80;
if (_intensity == 2)
a ^= 0x08;
+ if (hi_font_mask == 0x100)
+ a <<= 1;
return a;
}
#else
sw->con_invert_region(vc_cons[currcons].d, p, count);
#ifndef VT_BUF_VRAM_ONLY
else {
- int col = can_do_color;
u16 *q = p;
int cnt = count;
- while (cnt--) {
- u16 a = *q;
- if (col)
+ if (!can_do_color) {
+ while (cnt--) *q++ ^= 0x0800;
+ } else if (hi_font_mask == 0x100) {
+ while (cnt--) {
+ u16 a = *q;
+ a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+ *q++ = a;
+ }
+ } else {
+ while (cnt--) {
+ u16 a = *q;
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
- else
- a ^= 0x0800;
- *q++ = a;
+ *q++ = a;
+ }
}
}
#endif
int i = scr_readw((u16 *) pos);
u32 type = cursor_type;
+ if (! (type & 0x10)) return;
if (softcursor_original != -1) return;
softcursor_original = i;
- if (! (type & 0x10)) return;
i |= ((type >> 8) & 0xff00 );
i ^= ((type) & 0xff00 );
if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
static void hide_cursor(int currcons)
{
+ if (currcons == sel_cons)
+ clear_selection();
if (softcursor_original != -1) {
scr_writew(softcursor_original,(u16 *) pos);
if (DO_UPDATE)
if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
return;
if (deccm) {
+ if (currcons == sel_cons)
+ clear_selection();
add_softcursor(currcons);
if ((cursor_type & 0x0f) != 1)
sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
}
lock = 1;
- clear_selection();
-
hide_cursor(currcons);
if (fg_console != new_console) {
display = vc_cons[new_console].d->vc_display_fg;
sw = conswitchp;
cons_num = currcons;
display_fg = &master_display_fg;
+ vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+ vc_cons[currcons].d->vc_uni_pagedir = 0;
hi_font_mask = 0;
complement_mask = 0;
sw->con_init(vc_cons[currcons].d, 1);
vt_cons[currcons] = NULL;
return -ENOMEM;
}
+ con_set_default_unimap(currcons);
screenbuf = (unsigned short *) q;
kmalloced = 1;
screenbuf_size = video_screen_size;
/* DEC screen alignment test. kludge :-) */
video_erase_char =
(video_erase_char & 0xff00) | 'E';
- /* Arno:
- * Doesn't work, because csi_J(c,2)
- * calls con_clear and doesn't print
- * the erase char.. FIXME
- */
csi_J(currcons, 2);
video_erase_char =
(video_erase_char & 0xff00) | ' ';
+ do_update_region(currcons, origin, screenbuf_size/2);
}
return;
case ESsetG0:
if (IS_FG)
hide_cursor(currcons);
- /* clear the selection */
- if (currcons == sel_cons)
- clear_selection();
-
disable_bh(CONSOLE_BH);
while (!tty->stopped && count) {
enable_bh(CONSOLE_BH);
if (vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(tc);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(0xfffd);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
/* One reason for the -4 can be that we just
did a clear_unimap();
static void console_bh(void)
{
if (want_console >= 0) {
- if (want_console != fg_console) {
- clear_selection();
+ if (want_console != fg_console && vc_cons_allocated(want_console)) {
hide_cursor(fg_console);
save_screen();
change_console(want_console);
/* entering graphics mode? */
if (nopowersave) {
- save_screen();
hide_cursor(currcons);
+ save_screen();
sw->con_blank(vc_cons[currcons].d, -1);
console_blanked = fg_console + 1;
set_origin(currcons);
currcons = fg_console;
console_blanked = 0;
+#ifdef CONFIG_APM
+ apm_display_unblank();
+#endif
if (sw->con_blank(vc_cons[currcons].d, 0))
/* Low-level driver cannot restore -> do it ourselves */
update_screen(fg_console);
* /Jes
*/
-#define max_font_size 32768
+#define max_font_size 65536
int con_font_op(int currcons, struct console_font_op *op)
{
int rc = -EINVAL;
- int size, set;
- u8 *temp;
+ int size = max_font_size, set;
+ u8 *temp = NULL;
struct console_font_op old_op;
if (vt_cons[currcons]->vc_mode != KD_TEXT)
goto quit;
- memcpy(&old_op, &op, sizeof(op));
+ memcpy(&old_op, op, sizeof(old_op));
if (op->op == KD_FONT_OP_SET) {
+ if (!op->data)
+ return -EINVAL;
if (op->charcount > 512)
goto quit;
if (!op->height) { /* Need to guess font height [compat] */
int h, i;
u8 *charmap = op->data, tmp;
+
+ /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+ so that we can get rid of this soon */
+ if (op->flags & KD_FONT_FLAG_NEW)
+ goto quit;
rc = -EFAULT;
for (h = 32; h > 0; h--)
for (i = 0; i < op->charcount; i++) {
if (size > max_font_size)
return -ENOSPC;
set = 1;
- } else if (op->op == KD_FONT_OP_GET) {
- size = max_font_size;
+ } else if (op->op == KD_FONT_OP_GET)
set = 0;
- } else
+ else
return sw->con_font_op(vc_cons[currcons].d, op);
- temp = kmalloc(size, GFP_KERNEL);
- if (!temp)
- return -ENOMEM;
- if (set && copy_from_user(temp, op->data, size)) {
- rc = -EFAULT;
- goto quit2;
+ if (op->data) {
+ temp = kmalloc(size, GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+ if (set && copy_from_user(temp, op->data, size)) {
+ rc = -EFAULT;
+ goto quit;
+ }
+ op->data = temp;
}
- op->data = temp;
rc = sw->con_font_op(vc_cons[currcons].d, op);
op->data = old_op.data;
if (!rc && !set) {
int c = (op->width+7)/8 * 32 * op->charcount;
- if (op->width > old_op.width ||
- op->height > old_op.height ||
- op->charcount > old_op.charcount)
+
+ if (op->data && op->charcount > old_op.charcount)
rc = -ENOSPC;
- else if (copy_to_user(old_op.data, op->data, c))
+ if (op->flags & KD_FONT_FLAG_NEW) {
+ if (op->width > old_op.width ||
+ op->height > old_op.height)
+ rc = -ENOSPC;
+ } else {
+ if (op->width != 8)
+ rc = -EIO;
+ else if ((old_op.height && op->height > old_op.height) ||
+ op->height > 32)
+ rc = -ENOSPC;
+ }
+ if (!rc && op->data && copy_to_user(op->data, temp, c))
rc = -EFAULT;
}
-quit2: kfree_s(temp, size);
-quit: return rc;
+quit: if (temp)
+ kfree_s(temp, size);
+ return rc;
}
/*
set_cursor(currcons);
}
+u16 vcs_scr_readw(int currcons, u16 *org)
+{
+ if (org == pos && softcursor_original != -1)
+ return softcursor_original;
+ return scr_readw(org);
+}
+
+void vcs_scr_writew(int currcons, u16 val, u16 *org)
+{
+ scr_writew(val, org);
+ if (org == pos) {
+ softcursor_original = -1;
+ add_softcursor(currcons);
+ }
+}
+
/*
* Visible symbols for modules
* to font positions.
*
* aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
*/
#include <linux/kd.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/consolemap.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
#define MAX_GLYPH 512 /* Max possible glyph value */
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+static int inv_translate;
+
+struct uni_pagedir {
+ u16 **uni_pgdir[32];
+ unsigned long refcount;
+ unsigned long sum;
+ unsigned char *inverse_translations[4];
+ int readonly;
+};
-static void set_inverse_transl(int i)
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
{
int j, glyph;
- unsigned short *p = translations[i];
- unsigned char *q = inverse_translations[i];
+ unsigned short *t = translations[i];
+ unsigned char *q;
+
+ if (!p) return;
+ q = p->inverse_translations[i];
if (!q) {
- /* slightly messy to avoid calling kmalloc too early */
- q = inverse_translations[i] = ((i == LAT1_MAP)
- ? inv_norm_transl
- : (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL));
- if (!q)
- return;
+ q = p->inverse_translations[i] = (unsigned char *)
+ kmalloc(MAX_GLYPH, GFP_KERNEL);
+ if (!q) return;
}
- for (j=0; j<MAX_GLYPH; j++)
- q[j] = 0;
+ memset(q, 0, MAX_GLYPH);
- for (j=0; j<E_TABSZ; j++) {
- glyph = conv_uni_to_pc(p[j]);
+ for (j = 0; j < E_TABSZ; j++) {
+ glyph = conv_uni_to_pc(conp, t[j]);
if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
/* prefer '-' above SHY etc. */
q[glyph] = j;
unsigned short *set_translate(int m)
{
- if (!inverse_translations[m])
- set_inverse_transl(m);
- inv_translate = inverse_translations[m];
+ inv_translate = m;
return translations[m];
}
* was active, or using Unicode.
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
-unsigned char inverse_translate(int glyph) {
- if ( glyph < 0 || glyph >= MAX_GLYPH )
+unsigned char inverse_translate(struct vc_data *conp, int glyph)
+{
+ struct uni_pagedir *p;
+
+ if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
+ else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
+ !p->inverse_translations[inv_translate])
+ return glyph;
else
- return ((inv_translate && inv_translate[glyph])
- ? inv_translate[glyph]
- : (unsigned char)(glyph & 0xff));
+ return p->inverse_translations[inv_translate][glyph];
+}
+
+static void update_user_maps(void)
+{
+ int i;
+ struct uni_pagedir *p, *q = NULL;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (p && p != q) {
+ set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+ q = p;
+ }
+ }
}
/*
p[i] = UNI_DIRECT_BASE | uc;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
for (i=0; i<E_TABSZ ; i++)
{
- ch = conv_uni_to_pc(p[i]);
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
__put_user((ch & ~0xff) ? 0 : ch, arg+i);
}
return 0;
p[i] = us;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
extern u8 dfont_unicount[]; /* Defined in console_defmap.c */
extern u16 dfont_unitable[];
-int hashtable_contents_valid = 0; /* Use ASCII-only mode for bootup */
+static void con_release_unimap(struct uni_pagedir *p)
+{
+ u16 **p1;
+ int i, j;
+
+ if (p == dflt) dflt = NULL;
+ for (i = 0; i < 32; i++) {
+ if ((p1 = p->uni_pgdir[i]) != NULL) {
+ for (j = 0; j < 32; j++)
+ if (p1[j])
+ kfree(p1[j]);
+ kfree(p1);
+ }
+ p->uni_pgdir[i] = NULL;
+ }
+ for (i = 0; i < 4; i++)
+ if (p->inverse_translations[i]) {
+ kfree(p->inverse_translations[i]);
+ p->inverse_translations[i] = NULL;
+ }
+}
-static u16 **uni_pagedir[32] =
+void con_free_unimap(int con)
{
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (!p) return;
+ *conp->vc_uni_pagedir_loc = 0;
+ if (--p->refcount) return;
+ con_release_unimap(p);
+ kfree(p);
+}
+
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+ int i, j, k;
+ struct uni_pagedir *q;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (!q || q == p || q->sum != p->sum)
+ continue;
+ for (j = 0; j < 32; j++) {
+ u16 **p1, **q1;
+ p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+ if (!p1 && !q1)
+ continue;
+ if (!p1 || !q1)
+ break;
+ for (k = 0; k < 32; k++) {
+ if (!p1[k] && !q1[k])
+ continue;
+ if (!p1[k] || !q1[k])
+ break;
+ if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+ break;
+ }
+ if (k < 32)
+ break;
+ }
+ if (j == 32) {
+ q->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ con_release_unimap(p);
+ kfree(p);
+ return 1;
+ }
+ }
+ return 0;
+}
static int
-con_insert_unipair(u_short unicode, u_short fontpos)
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
{
- int i, n;
- u16 **p1, *p2;
-
- if ( !(p1 = uni_pagedir[n = unicode >> 11]) )
- {
- p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
- if ( !p1 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 32 ; i++ )
- p1[i] = NULL;
- }
-
- if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) )
- {
- p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
- if ( !p2 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 64 ; i++ )
- p2[i] = 0xffff; /* No glyph for this character (yet) */
- }
-
- p2[unicode & 0x3f] = fontpos;
-
- return 0;
+ int i, n;
+ u16 **p1, *p2;
+
+ if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+ p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+ if (!p1) return -ENOMEM;
+ for (i = 0; i < 32; i++)
+ p1[i] = NULL;
+ }
+
+ if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+ p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+ if (!p2) return -ENOMEM;
+ memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+ }
+
+ p2[unicode & 0x3f] = fontpos;
+
+ p->sum += (fontpos << 20) + unicode;
+
+ return 0;
}
-
+
/* ui is a leftover from using a hashtable, but might be used again */
-void
-con_clear_unimap(struct unimapinit *ui)
+int con_clear_unimap(int con, struct unimapinit *ui)
{
- int i, j;
- u16 **p1;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
- for ( i = 0 ; i < 32 ; i++ )
- {
- if ( (p1 = uni_pagedir[i]) != NULL )
- {
- for ( j = 0 ; j < 32 ; j++ )
- {
- if ( p1[j] )
- kfree(p1[j]);
- }
- kfree(p1);
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p && p->readonly) return -EIO;
+ if (!p || --p->refcount) {
+ q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!q) {
+ if (p) p->refcount++;
+ return -ENOMEM;
+ }
+ memset(q, 0, sizeof(*q));
+ q->refcount=1;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ } else {
+ if (p == dflt) dflt = NULL;
+ p->refcount++;
+ p->sum = 0;
+ con_release_unimap(p);
}
- uni_pagedir[i] = NULL;
- }
-
- hashtable_contents_valid = 1;
+ return 0;
}
int
-con_set_unimap(ushort ct, struct unipair *list)
+con_set_unimap(int con, ushort ct, struct unipair *list)
{
- int err = 0, err1, i;
-
- while( ct-- )
- {
- unsigned short unicode, fontpos;
- __get_user(unicode, &list->unicode);
- __get_user(fontpos, &list->fontpos);
- if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 )
- err = err1;
- list++;
- }
-
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ int err = 0, err1, i;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p->readonly) return -EIO;
+
+ if (!ct) return 0;
+
+ if (p->refcount > 1) {
+ int j, k;
+ u16 **p1, *p2, l;
+
+ err1 = con_clear_unimap(con, NULL);
+ if (err1) return err1;
+
+ q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0, l = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = p1[j]))
+ for (k = 0; k < 64; k++, l++)
+ if (p2[k] != 0xffff) {
+ err1 = con_insert_unipair(q, l, p2[k]);
+ if (err1) {
+ p->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)p;
+ con_release_unimap(q);
+ kfree(q);
+ return err1;
+ }
+ }
+ p = q;
+ } else if (p == dflt)
+ dflt = NULL;
+
+ while (ct--) {
+ unsigned short unicode, fontpos;
+ __get_user(unicode, &list->unicode);
+ __get_user(fontpos, &list->fontpos);
+ if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+ err = err1;
+ list++;
+ }
+
+ if (con_unify_unimap(conp, p))
+ return err;
+
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
- return err;
+ return err;
}
/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
with. This routine is executed at sys_setup time, and when the
PIO_FONTRESET ioctl is called. */
-void
-con_set_default_unimap(void)
+int
+con_set_default_unimap(int con)
{
- int i, j;
- u16 *p;
-
- /* The default font is always 256 characters */
-
- con_clear_unimap(NULL);
+ int i, j, err = 0, err1;
+ u16 *q;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ if (dflt) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p == dflt)
+ return 0;
+ dflt->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+ if (p && --p->refcount) {
+ con_release_unimap(p);
+ kfree(p);
+ }
+ return 0;
+ }
+
+ /* The default font is always 256 characters */
- p = dfont_unitable;
- for ( i = 0 ; i < 256 ; i++ )
- for ( j = dfont_unicount[i] ; j ; j-- )
- con_insert_unipair(*(p++), i);
+ err = con_clear_unimap(con,NULL);
+ if (err) return err;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ q = dfont_unitable;
+
+ for (i = 0; i < 256; i++)
+ for (j = dfont_unicount[i]; j; j--) {
+ err1 = con_insert_unipair(p, *(q++), i);
+ if (err1)
+ err = err1;
+ }
+
+ if (con_unify_unimap(conp, p)) {
+ dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ return err;
+ }
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
+ dflt = p;
+ return err;
}
int
-con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
+con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list)
+{
int i, j, k, ect;
u16 **p1, *p2;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
ect = 0;
- if (hashtable_contents_valid)
- {
- for ( i = 0 ; i < 32 ; i++ )
- if ( (p1 = uni_pagedir[i]) != NULL )
- for ( j = 0 ; j < 32 ; j++ )
- if ( (p2 = *(p1++)) != NULL )
- for ( k = 0 ; k < 64 ; k++ )
- {
- if ( *p2 < MAX_GLYPH && ect++ < ct )
- {
- __put_user((u_short)((i<<11)+(j<<6)+k),
- &list->unicode);
- __put_user((u_short) *p2, &list->fontpos);
- list++;
- }
- p2++;
- }
- }
+ if (*conp->vc_uni_pagedir_loc) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = *(p1++)))
+ for (k = 0; k < 64; k++) {
+ if (*p2 < MAX_GLYPH && ect++ < ct) {
+ __put_user((u_short)((i<<11)+(j<<6)+k),
+ &list->unicode);
+ __put_user((u_short) *p2,
+ &list->fontpos);
+ list++;
+ }
+ p2++;
+ }
+ }
__put_user(ect, uct);
return ((ect <= ct) ? 0 : -ENOMEM);
}
+void con_protect_unimap(int con, int rdonly)
+{
+ struct uni_pagedir *p = (struct uni_pagedir *)
+ *vc_cons[con].d->vc_uni_pagedir_loc;
+
+ if (p) p->readonly = rdonly;
+}
+
int
-conv_uni_to_pc(long ucs)
+conv_uni_to_pc(struct vc_data *conp, long ucs)
{
- int h;
- u16 **p1, *p2;
-
- /* Only 16-bit codes supported at this time */
- if (ucs > 0xffff)
- ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
- else if (ucs < 0x20 || ucs >= 0xfffe)
- return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
- return -2; /* Zero-width space */
- /*
- * UNI_DIRECT_BASE indicates the start of the region in the User Zone
- * which always has a 1:1 mapping to the currently loaded font. The
- * UNI_DIRECT_MASK indicates the bit span of the region.
- */
- else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE )
- return ucs & UNI_DIRECT_MASK;
+ int h;
+ u16 **p1, *p2;
+ struct uni_pagedir *p;
- if (!hashtable_contents_valid)
- return -3;
+ /* Only 16-bit codes supported at this time */
+ if (ucs > 0xffff)
+ ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
+ else if (ucs < 0x20 || ucs >= 0xfffe)
+ return -1; /* Not a printable character */
+ else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+ return -2; /* Zero-width space */
+ /*
+ * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+ * which always has a 1:1 mapping to the currently loaded font. The
+ * UNI_DIRECT_MASK indicates the bit span of the region.
+ */
+ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+ return ucs & UNI_DIRECT_MASK;
- if ( (p1 = uni_pagedir[ucs >> 11]) &&
- (p2 = p1[(ucs >> 6) & 0x1f]) &&
- (h = p2[ucs & 0x3f]) < MAX_GLYPH )
- return h;
+ if (!*conp->vc_uni_pagedir_loc)
+ return -3;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+ (p2 = p1[(ucs >> 6) & 0x1f]) &&
+ (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+ return h;
- return -4; /* not found */
+ return -4; /* not found */
}
/*
__initfunc(void
console_map_init(void))
{
- con_set_default_unimap();
+ int i;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+ con_set_default_unimap(i);
}
#elif defined(__sparc__)
/* Should never get here, all fb drivers should have their own
mmap routines */
+#elif defined(__i386__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
#else
#warning What do we have to do here??
#endif
if (first) {
first = 0;
- take_over_console(&fb_con, 0, MAX_NR_CONSOLES-1, 1);
+ take_over_console(&fb_con, 12, MAX_NR_CONSOLES-1, 1);
}
return 0;
static unsigned char
sel_pos(int n)
{
- return inverse_translate(screen_glyph(sel_cons, n));
+ return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n));
}
/* remove the current selection highlight, if any,
* [minor: N]
*
* /dev/vcsaN: idem, but including attributes, and prefixed with
- * the 4 bytes lines,columns,x,y (as screendump used to give)
+ * the 4 bytes lines,columns,x,y (as screendump used to give).
+ * Attribute/character pair is in native endianity.
* [minor: N+128]
*
* This replaces screendump and part of selection, so that the system
* - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
+#include <linux/config.h>
+
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#undef addr
#define HEADER_SIZE 4
-static unsigned short
-func_scr_readw(unsigned short *org)
-{
-return scr_readw( org );
-}
-
-static void
-func_scr_writew(unsigned short val, unsigned short *org)
-{
-scr_writew( val, org );
-}
-
static int
vcs_size(struct inode *inode)
{
return file->f_pos;
}
-#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
+#define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
static ssize_t
vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh( CONSOLE_BH );
+ disable_bh(CONSOLE_BH);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
if (!attr) {
org = screen_pos(currcons, p, viewed);
while (count-- > 0)
- put_user(func_scr_readw(org++) & 0xff, buf++);
+ put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
org = screen_pos(currcons, p/2, viewed);
if ((p & 1) && count > 0)
#ifdef __BIG_ENDIAN
- { count--; put_user(func_scr_readw(org++) & 0xff, buf++); }
+ { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); }
#else
- { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
+ { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); }
#endif
}
while (count > 1) {
- put_user(func_scr_readw(org++), (unsigned short *) buf);
+ put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf);
buf += 2;
count -= 2;
}
if (count > 0)
#ifdef __BIG_ENDIAN
- put_user(func_scr_readw(org) >> 8, buf++);
+ put_user(vcs_scr_readw(currcons, org) >> 8, buf++);
#else
- put_user(func_scr_readw(org) & 0xff, buf++);
+ put_user(vcs_scr_readw(currcons, org) & 0xff, buf++);
#endif
}
read = buf - buf0;
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh( CONSOLE_BH );
+ disable_bh(CONSOLE_BH);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
unsigned char c;
count--;
get_user(c, (const unsigned char*)buf++);
- func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
org++;
}
} else {
count--;
get_user(c,buf++);
#ifdef __BIG_ENDIAN
- func_scr_writew(c |
- (func_scr_readw(org) & 0xff00), org);
+ vcs_scr_writew(currcons, c |
+ (vcs_scr_readw(currcons, org) & 0xff00), org);
#else
- func_scr_writew((c << 8) |
- (func_scr_readw(org) & 0xff), org);
+ vcs_scr_writew(currcons, (c << 8) |
+ (vcs_scr_readw(currcons, org) & 0xff), org);
#endif
org++;
}
while (count > 1) {
unsigned short w;
get_user(w, (const unsigned short *) buf);
- func_scr_writew(w, org++);
+ vcs_scr_writew(currcons, w, org++);
buf += 2;
count -= 2;
}
unsigned char c;
get_user(c, (const unsigned char*)buf++);
#ifdef __BIG_ENDIAN
- func_scr_writew((func_scr_readw(org) & 0xff) | (c << 8), org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
#else
- func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
#endif
}
}
}
/*
- * Generates sound of some count for some number of clock ticks
- * [count = 1193180 / frequency]
+ * Generates sound of some frequency for some number of clock ticks
*
* If freq is 0, will turn off sound, else will turn it on for that time.
* If msec is 0, will return immediately, else will sleep for msec time, then
* turn sound off.
*
- * We use the BEEP_TIMER vector since we're using the same method to
- * generate sound, and we'll overwrite any beep in progress. That may
- * be something to fix later, if we like.
- *
* We also return immediately, which is what was implied within the X
* comments - KDMKTONE doesn't put the process to sleep.
*/
-/* FIXME: This should go to arch-dependent code */
+
+#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__)
+
static void
kd_nosound(unsigned long ignored)
{
return;
}
+#else
+
+void
+_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+
+#endif
+
void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
op.data = cfdarg.chardata;
return con_font_op(fg_console, &op);
case GIO_FONTX: {
- if (!cfdarg.chardata)
- return 0;
op.op = KD_FONT_OP_GET;
op.flags = 0;
op.width = 8;
case PIO_UNIMAP:
if (!perm)
return -EPERM;
- return con_set_unimap(tmp.entry_ct, tmp.entries);
+ return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
case GIO_UNIMAP:
- return con_get_unimap(tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+ return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
}
return 0;
}
#else
{
struct console_font_op op;
- op.op = KD_FONT_SET_DEFAULT;
+ op.op = KD_FONT_OP_SET_DEFAULT;
op.data = NULL;
i = con_font_op(fg_console, &op);
if (i) return i;
- con_set_default_unimap();
+ con_set_default_unimap(fg_console);
return 0;
}
#endif
return -EFAULT;
if (!perm && op.op != KD_FONT_OP_GET)
return -EPERM;
+ op.flags |= KD_FONT_FLAG_NEW;
i = con_font_op(console, &op);
if (i) return i;
if (copy_to_user((void *) arg, &op, sizeof(op)))
return -EPERM;
i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
if (i) return -EFAULT;
- con_clear_unimap(&ui);
+ con_clear_unimap(fg_console, &ui);
return 0;
}
{
unsigned char old_vc_mode;
- if ((new_console == fg_console) || (vt_dont_switch))
- return;
- if (!vc_cons_allocated(new_console))
- return;
last_console = fg_console;
/*
int len = 0;
const char *str;
+ page[0] = '\0';
+
if ((str = pp->probe_info.class_name) != NULL)
len += sprintf (page+len, "CLASS:%s;\n", str);
*start = 0;
*eof = 1;
- return strlen (page);
+ return len;
}
static inline void destroy_proc_entry(struct proc_dir_entry *root,
dev->tbusy = 0;
}
+ lp->stats.tx_bytes += skb->len;
+
if (el3_debug > 4) {
printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
dev->name, skb->len, inw(ioaddr + EL3_STATUS));
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
+ lp->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
source drivers/acorn/net/Config.in
fi
fi
- if [ "$CONFIG_PMAC" = "y" ]; then
- bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
+ if [ "$CONFIG_PPC" = "y" ]; then
+ bool 'MACE (Power Mac ethernet) support' CONFIG_MACE
+ bool 'BMAC (G3 ethernet) support' CONFIG_BMAC
+ fi
+ if [ "$CONFIG_APUS" = "y" ]; then
+ tristate 'Ariadne support' CONFIG_ARIADNE
+ tristate 'A2065 support' CONFIG_A2065
+ tristate 'Hydra support' CONFIG_HYDRA
fi
if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
endif
endif
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ETHERH),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
+
ifeq ($(CONFIG_NE2K_PCI),y)
L_OBJS += ne2k-pci.o
CONFIG_8390_BUILTIN = y
L_OBJS += mace.o
endif
+ifeq ($(CONFIG_BMAC),y)
+L_OBJS += bmac.o
+endif
+
ifeq ($(CONFIG_VENDOR_SANGOMA),y)
LX_OBJS += sdladrv.o
L_OBJS += sdlamain.o
extern int pamsnet_probe(struct device *);
extern int tlan_probe(struct device *);
extern int mace_probe(struct device *);
+extern int bmac_probe(struct device *);
extern int cs89x0_probe(struct device *dev);
extern int ethertap_probe(struct device *dev);
extern int ether1_probe (struct device *dev);
struct devprobe ppc_probes[] __initdata = {
#ifdef CONFIG_MACE
{mace_probe, 0},
+#endif
+#ifdef CONFIG_BMAC
+ {bmac_probe, 0},
#endif
{NULL, 0},
};
--- /dev/null
+/*
+ * Network device driver for the BMAC ethernet controller on
+ * Apple Powermacs. Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include "bmac.h"
+
+#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define ENET_CRCPOLY 0x04c11db7
+
+/* a bunch of constants for the "Heathrow" interrupt controller.
+ These really should be in an include file somewhere */
+#define IoBaseHeathrow ((unsigned *)0xf3000000)
+#define HeathrowFCR 0x0038 /* FCR offset from Heathrow Base Address */
+#define fcrEnetEnabledBits 0x60000000 /* mask to enable Enet Xcvr/Controller */
+#define fcrResetEnetCell 0x80000000 /* mask used to reset Enet cell */
+#define fcrClearResetEnetCell 0x7fffffff /* mask used to clear reset Enet cell */
+#define fcrDisableEnet 0x1fffffff /* mask to disable Enet Xcvr/Controller */
+
+#define N_RX_RING 64
+#define N_TX_RING 32
+#define MAX_TX_ACTIVE 1
+#define ETHERCRC 4
+#define ETHERMINPACKET 64
+#define ETHERMTU 1500
+#define RX_BUFLEN (ETHERMTU + 14 + ETHERCRC + 2)
+#define TX_TIMEOUT HZ /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR 0x80
+
+#define XXDEBUG(args)
+
+struct bmac_data {
+/* volatile struct bmac *bmac; */
+ struct sk_buff_head *queue;
+ volatile struct dbdma_regs *tx_dma;
+ int tx_dma_intr;
+ volatile struct dbdma_regs *rx_dma;
+ int rx_dma_intr;
+ volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */
+ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */
+ struct sk_buff *rx_bufs[N_RX_RING];
+ int rx_fill;
+ int rx_empty;
+ struct sk_buff *tx_bufs[N_TX_RING];
+ char *tx_double[N_TX_RING]; /* yuck--double buffering */
+ int tx_fill;
+ int tx_empty;
+ unsigned char tx_fullup;
+ struct net_device_stats stats;
+ struct timer_list tx_timeout;
+ int timeout_active;
+ int reset_and_enabled;
+ int rx_allocated;
+ int tx_allocated;
+ unsigned short hash_use_count[64];
+ unsigned short hash_table_mask[4];
+};
+
+typedef struct bmac_reg_entry {
+ char *name;
+ unsigned short reg_offset;
+} bmac_reg_entry_t;
+
+#define N_REG_ENTRIES 30
+
+bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
+ {"MEMADD", MEMADD},
+ {"MEMDATAHI", MEMDATAHI},
+ {"MEMDATALO", MEMDATALO},
+ {"TXPNTR", TXPNTR},
+ {"RXPNTR", RXPNTR},
+ {"IPG1", IPG1},
+ {"IPG2", IPG2},
+ {"ALIMIT", ALIMIT},
+ {"SLOT", SLOT},
+ {"PALEN", PALEN},
+ {"PAPAT", PAPAT},
+ {"TXSFD", TXSFD},
+ {"JAM", JAM},
+ {"TXMAX", TXMAX},
+ {"TXMIN", TXMIN},
+ {"PAREG", PAREG},
+ {"DCNT", DCNT},
+ {"NCCNT", NCCNT},
+ {"NTCNT", NTCNT},
+ {"EXCNT", EXCNT},
+ {"LTCNT", LTCNT},
+ {"TXSM", TXSM},
+ {"RXCFG", RXCFG},
+ {"RXMAX", RXMAX},
+ {"RXMIN", RXMIN},
+ {"FRCNT", FRCNT},
+ {"AECNT", AECNT},
+ {"FECNT", FECNT},
+ {"RXSM", RXSM},
+ {"RXCV", RXCV}
+};
+
+struct device *bmac_devs = NULL;
+
+#if 0
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN];
+#endif
+
+/*
+ * Number of bytes of private data per BMAC: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES (sizeof(struct bmac_data) \
+ + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+ + sizeof(struct sk_buff_head))
+
+static unsigned char bitrev(unsigned char b);
+static int bmac_open(struct device *dev);
+static int bmac_close(struct device *dev);
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bmac_stats(struct device *dev);
+static void bmac_set_multicast(struct device *dev);
+static int bmac_reset_and_enable(struct device *dev, int enable);
+static void bmac_start_chip(struct device *dev);
+static int bmac_init_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static void bmac_reset_chip(struct device *dev);
+static int bmac_set_address(struct device *dev, void *addr);
+static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_set_timeout(struct device *dev);
+static void bmac_tx_timeout(unsigned long data);
+static void bmac_reset_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
+static int bmac_output(struct sk_buff *skb, struct device *dev);
+static void bmac_start(struct device *dev);
+
+#define DBDMA_SET(x) ( ((x) | (x) << 16) )
+#define DBDMA_CLEAR(x) ( (x) << 16)
+
+static __inline__ void
+dbdma_st32(volatile unsigned long *a, unsigned long x)
+{
+ __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+ return;
+}
+
+static __inline__ unsigned long
+dbdma_ld32(volatile unsigned long *a)
+{
+ unsigned long swap;
+ __asm__ volatile ("lwbrx %0,0,%1" : "=r" (swap) : "r" (a));
+ return swap;
+}
+
+void
+dbdma_stop(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+ eieio();
+
+ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
+ eieio();
+}
+
+static void
+dbdma_continue(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
+ eieio();
+}
+
+static void
+dbdma_reset(volatile struct dbdma_regs *dmap)
+{
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
+ eieio();
+ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+}
+
+static void
+dbdma_setcmd(volatile struct dbdma_cmd *cp,
+ unsigned short cmd, unsigned count, unsigned long addr,
+ unsigned long cmd_dep)
+{
+ out_le16(&cp->command, cmd);
+ out_le16(&cp->req_count, count);
+ out_le32(&cp->phy_addr, addr);
+ out_le32(&cp->cmd_dep, cmd_dep);
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->res_count, 0);
+}
+
+static __inline__
+void bmwrite(struct device *dev, unsigned long reg_offset, unsigned data )
+{
+ out_le16((void *)dev->base_addr + reg_offset, data);
+}
+
+
+static __inline__
+volatile unsigned short bmread(struct device *dev, unsigned long reg_offset )
+{
+ return in_le16((void *)dev->base_addr + reg_offset);
+}
+
+static void
+bmac_reset_chip(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ volatile unsigned *heathrowFCR;
+ unsigned int fcrValue;
+
+ dbdma_reset(rd);
+ dbdma_reset(td);
+
+ heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+
+ fcrValue = in_le32(heathrowFCR);
+
+ fcrValue &= fcrDisableEnet; /* clear out Xvr and Controller Bit */
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue |= fcrResetEnetCell; /* set bit to reset them */
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue &= fcrDisableEnet;
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ fcrValue |= fcrEnetEnabledBits;
+ out_le32(heathrowFCR, fcrValue);
+ udelay(50000);
+
+ out_le32(heathrowFCR, fcrValue);
+}
+
+static void
+bmac_init_registers(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile unsigned short regValue;
+ unsigned short *pWord16;
+ int i;
+
+/* XXDEBUG(("bmac: enter init_registers\n")); */
+
+ bmwrite(dev, TXRST, TxResetBit);
+
+ do {
+ regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
+ } while (regValue & TxResetBit);
+
+ bmwrite(dev, RXRST, RxResetValue);
+ bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);
+ bmwrite(dev, RSEED, (unsigned short)0x1968);
+
+ regValue = bmread(dev, XIFC);
+ regValue |= TxOutputEnable;
+ bmwrite(dev, XIFC, regValue);
+
+ bmread(dev, PAREG);
+
+ /* set collision counters to 0 */
+ bmwrite(dev, NCCNT, 0);
+ bmwrite(dev, NTCNT, 0);
+ bmwrite(dev, EXCNT, 0);
+ bmwrite(dev, LTCNT, 0);
+
+ /* set rx counters to 0 */
+ bmwrite(dev, FRCNT, 0);
+ bmwrite(dev, LECNT, 0);
+ bmwrite(dev, AECNT, 0);
+ bmwrite(dev, FECNT, 0);
+ bmwrite(dev, RXCV, 0);
+
+ /* set tx fifo information */
+ bmwrite(dev, TXTH, 4); /* 4 octets before tx starts */
+
+ bmwrite(dev, TXFIFOCSR, 0); /* first disable txFIFO */
+ bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
+
+ /* set rx fifo information */
+ bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+
+ //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */
+ bmread(dev, STATUS); /* read it just to clear it */
+
+ bmwrite(dev, INTDISABLE, EnableNormal);
+
+ /* zero out the chip Hash Filter registers */
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+ bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+
+ pWord16 = (unsigned short *)dev->dev_addr;
+ bmwrite(dev, MADD0, *pWord16++);
+ bmwrite(dev, MADD1, *pWord16++);
+ bmwrite(dev, MADD2, *pWord16);
+
+
+ bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
+
+ return;
+}
+
+#if 0
+static void
+bmac_disable_interrupts(struct device *dev)
+{
+ bmwrite(dev, INTDISABLE, DisableAll);
+}
+
+static void
+bmac_enable_interrupts(struct device *dev)
+{
+ bmwrite(dev, INTDISABLE, EnableNormal);
+}
+#endif
+
+
+static void
+bmac_start_chip(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ unsigned short oldConfig;
+
+ /* enable rx dma channel */
+ dbdma_continue(rd);
+
+ /* turn on rx plus any other bits already on (promiscuous possibly) */
+ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+
+ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+}
+
+static int
+bmac_init_chip(struct device *dev)
+{
+ bmac_init_registers(dev);
+ return 1;
+}
+
+static int bmac_set_address(struct device *dev, void *addr)
+{
+ unsigned char *p = addr;
+ unsigned short *pWord16;
+ unsigned long flags;
+ int i;
+
+ XXDEBUG(("bmac: enter set_address\n"));
+ save_flags(flags); cli();
+
+ for (i = 0; i < 6; ++i) {
+ dev->dev_addr[i] = p[i];
+ }
+ /* load up the hardware address */
+ pWord16 = (unsigned short *)dev->dev_addr;
+ bmwrite(dev, MADD0, *pWord16++);
+ bmwrite(dev, MADD1, *pWord16++);
+ bmwrite(dev, MADD2, *pWord16);
+
+ restore_flags(flags);
+ XXDEBUG(("bmac: exit set_address\n"));
+ return 0;
+}
+
+static inline void bmac_set_timeout(struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (bp->timeout_active)
+ del_timer(&bp->tx_timeout);
+ bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+ bp->tx_timeout.function = bmac_tx_timeout;
+ bp->tx_timeout.data = (unsigned long) dev;
+ add_timer(&bp->tx_timeout);
+ bp->timeout_active = 1;
+ restore_flags(flags);
+}
+
+static void
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp,
+ char *doubleBuf)
+{
+ void *vaddr, *page_break;
+ unsigned long baddr;
+ unsigned long len;
+
+ len = skb->len;
+ vaddr = skb->data;
+ baddr = virt_to_bus(vaddr);
+ page_break = round_page(vaddr);
+ if (trunc_page(vaddr) != trunc_page(vaddr+len) &&
+ (unsigned long)round_page(baddr) != virt_to_bus(page_break)) {
+ baddr = virt_to_bus(doubleBuf);
+ XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len));
+ } else
+ flush_page_to_ram((unsigned long)vaddr);
+
+ dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
+}
+
+static void
+bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp)
+{
+ dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static unsigned char
+bitrev(unsigned char b)
+{
+ int d = 0, i;
+
+ for (i = 0; i < 8; ++i, b >>= 1)
+ d = (d << 1) | (b & 1);
+ return d;
+}
+
+
+static int
+bmac_init_tx_ring(struct bmac_data *bp)
+{
+ int i;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ char *addr;
+
+ if (!bp->tx_allocated) {
+ /* zero out tx cmds, alloc space for double buffering */
+ addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA);
+ for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr;
+ bp->tx_allocated = 1;
+ }
+ memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
+
+ bp->tx_empty = 0;
+ bp->tx_fill = 0;
+ bp->tx_fullup = 0;
+
+ /* put a branch at the end of the tx command list */
+ dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
+ (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
+
+ /* reset tx dma */
+ dbdma_reset(td);
+ out_le32(&td->wait_sel, 0x00200020);
+ out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
+
+ return 1;
+
+}
+
+static int
+bmac_init_rx_ring(struct bmac_data *bp)
+{
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ int i;
+
+ /* initialize list of sk_buffs for receiving and set up recv dma */
+ if (!bp->rx_allocated) {
+ for (i = 0; i < N_RX_RING; i++) {
+ bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+ skb_reserve(bp->rx_bufs[i], 2);
+ }
+ bp->rx_allocated = 1;
+ }
+
+ memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd));
+ for (i = 0; i < N_RX_RING; i++)
+ bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+
+ bp->rx_empty = 0;
+ bp->rx_fill = i;
+
+ /* Put a branch back to the beginning of the receive command list */
+ dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
+ (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
+
+ /* start rx dma */
+ dbdma_reset(rd);
+ out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
+
+ return 1;
+}
+
+
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ int i;
+
+ /* see if there's a free slot in the tx ring */
+/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
+/* bp->tx_empty, bp->tx_fill)); */
+ i = bp->tx_fill + 1;
+ if (i >= N_TX_RING) i = 0;
+ if (i == bp->tx_empty) {
+ dev->tbusy = 1;
+ bp->tx_fullup = 1;
+ XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
+ return -1; /* can't take it at the moment */
+ }
+
+ dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
+
+ bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]);
+
+ bp->tx_bufs[bp->tx_fill] = skb;
+ bp->tx_fill = i;
+
+ dbdma_continue(td);
+
+ return 0;
+}
+
+static int rxintcount = 0;
+
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_cmd *cp;
+ int i, nb, stat;
+ struct sk_buff *skb;
+ unsigned int residual;
+ int last;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ if (++rxintcount < 10) {
+ XXDEBUG(("bmac_rxdma_intr\n"));
+ }
+
+ last = -1;
+ i = bp->rx_empty;
+
+ while (1) {
+ cp = &bp->rx_cmds[i];
+ stat = ld_le16(&cp->xfer_status);
+ residual = ld_le16(&cp->res_count);
+ if ((stat & ACTIVE) == 0) break;
+ nb = RX_BUFLEN - residual - 2;
+ if (nb < (ETHERMINPACKET - ETHERCRC)) {
+ skb = NULL;
+ bp->stats.rx_length_errors++;
+ bp->stats.rx_errors++;
+ } else skb = bp->rx_bufs[i];
+ if (skb != NULL) {
+ nb -= ETHERCRC;
+ skb_put(skb, nb);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+ skb_reserve(bp->rx_bufs[i], 2);
+ bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+ ++bp->stats.rx_packets;
+ } else {
+ ++bp->stats.rx_dropped;
+ }
+ st_le16(&cp->res_count, 0);
+ st_le16(&cp->xfer_status, 0);
+ last = i;
+ if (++i >= N_RX_RING) i = 0;
+ }
+
+ if (last != -1) {
+ bp->rx_fill = last;
+ bp->rx_empty = i;
+ }
+
+ restore_flags(flags);
+
+ dbdma_continue(rd);
+
+ if (rxintcount < 10) {
+ XXDEBUG(("bmac_rxdma_intr done\n"));
+ }
+}
+
+static int txintcount = 0;
+
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_cmd *cp;
+ int stat;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ if (txintcount++ < 10) {
+ XXDEBUG(("bmac_txdma_intr\n"));
+ }
+
+/* del_timer(&bp->tx_timeout); */
+/* bp->timeout_active = 0; */
+
+ while (1) {
+ cp = &bp->tx_cmds[bp->tx_empty];
+ stat = ld_le16(&cp->xfer_status);
+ if (txintcount < 10) {
+ XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
+ }
+ if (!(stat & ACTIVE)) break;
+
+ if (bp->tx_bufs[bp->tx_empty]) {
+ ++bp->stats.tx_packets;
+ dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+ }
+ bp->tx_bufs[bp->tx_empty] = NULL;
+ bp->tx_fullup = 0;
+ dev->tbusy = 0;
+/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
+/* i, bp->tx_fill)); */
+ mark_bh(NET_BH);
+ if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
+ if (bp->tx_empty == bp->tx_fill) break;
+ }
+
+ restore_flags(flags);
+
+ if (txintcount < 10) {
+ XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
+ }
+
+ bmac_start(dev);
+}
+
+static struct net_device_stats *bmac_stats(struct device *dev)
+{
+ struct bmac_data *p = (struct bmac_data *) dev->priv;
+
+ return &p->stats;
+}
+
+#if 0
+/* Real fast bit-reversal algorithm, 6-bit values */
+static int reverse6[64] = {
+ 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
+ 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
+ 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
+ 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
+ 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
+ 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
+ 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
+ 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
+};
+
+static unsigned int
+crc416(unsigned int curval, unsigned short nxtval)
+{
+ register unsigned int counter, cur = curval, next = nxtval;
+ register int high_crc_set, low_data_set;
+
+ /* Swap bytes */
+ next = ((next & 0x00FF) << 8) | (next >> 8);
+
+ /* Compute bit-by-bit */
+ for (counter = 0; counter < 16; ++counter) {
+ /* is high CRC bit set? */
+ if ((cur & 0x80000000) == 0) high_crc_set = 0;
+ else high_crc_set = 1;
+
+ cur = cur << 1;
+
+ if ((next & 0x0001) == 0) low_data_set = 0;
+ else low_data_set = 1;
+
+ next = next >> 1;
+
+ /* do the XOR */
+ if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
+ }
+ return cur;
+}
+
+static unsigned int
+bmac_crc(unsigned short *address)
+{
+ unsigned int newcrc;
+
+ XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+ newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */
+ newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */
+ newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */
+
+ return(newcrc);
+}
+
+/*
+ * Add requested mcast addr to BMac's hash table filter.
+ *
+ */
+
+static void
+bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+{
+ unsigned int crc;
+ unsigned short mask;
+
+ if (!(*addr
+ crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */
+ if (bp->hash_use_count[crc]++) return; /* This bit is already set */
+ mask = crc % 16;
+ mask = (unsigned char)1 << mask;
+ bp->hash_use_count[crc/16] |= mask;
+ }
+
+ static void
+ bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+ {
+ unsigned int crc;
+ unsigned char mask;
+
+ /* Now, delete the address from the filter copy, as indicated */
+ crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */
+ if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
+ if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
+ mask = crc % 16;
+ mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
+ bp->hash_table_mask[crc/16] &= mask;
+ }
+
+/*
+ * Sync the adapter with the software copy of the multicast mask
+ * (logical address filter).
+ */
+
+ static void
+ bmac_rx_off(struct device *dev)
+ {
+ unsigned short rx_cfg;
+
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg &= ~RxMACEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ do {
+ rx_cfg = bmread(dev, RXCFG);
+ } while (rx_cfg & RxMACEnable);
+ }
+
+ unsigned short
+ bmac_rx_on(struct device *dev, int hash_enable, int promisc_enable)
+ {
+ unsigned short rx_cfg;
+
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxMACEnable;
+ if (hash_enable) rx_cfg |= RxHashFilterEnable;
+ else rx_cfg &= ~RxHashFilterEnable;
+ if (promisc_enable) rx_cfg |= RxPromiscEnable;
+ else rx_cfg &= ~RxPromiscEnable;
+ bmwrite(dev, RXRST, RxResetValue);
+ bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+ bmwrite(dev, RXCFG, rx_cfg );
+ return rx_cfg;
+ }
+
+ static void
+ bmac_update_hash_table_mask(struct device *dev, struct bmac_data *bp)
+ {
+ bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+ }
+
+#if 0
+ static void
+ bmac_add_multi(struct device *dev,
+ struct bmac_data *bp, unsigned char *addr)
+ {
+/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
+ bmac_addhash(bp, addr);
+ bmac_rx_off(dev);
+ bmac_update_hash_table_mask(dev, bp);
+ bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
+ }
+
+ static void
+ bmac_remove_multi(struct device *dev,
+ struct bmac_data *bp, unsigned char *addr)
+ {
+ bmac_removehash(bp, addr);
+ bmac_rx_off(dev);
+ bmac_update_hash_table_mask(dev, bp);
+ bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+ }
+#endif
+
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+ static void bmac_set_multicast(struct device *dev)
+ {
+ struct dev_mc_list *dmi;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ int num_addrs = dev->mc_count;
+ unsigned short rx_cfg;
+ int i;
+
+ XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
+
+ if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
+ bmac_update_hash_table_mask(dev, bp);
+ rx_cfg = bmac_rx_on(dev, 1, 0);
+ XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
+ } else if if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxPromiscEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ rx_cfg = bmac_rx_on(dev, 0, 1);
+ XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
+ } else {
+ for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+ for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
+ if (num_addrs == 0) {
+ rx_cfg = bmac_rx_on(dev, 0, 0);
+ XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
+ } else {
+ for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next)
+ bmac_addhash(bp, dmi->dmi_addr);
+ bmac_update_hash_table_mask(dev, bp);
+ rx_cfg = bmac_rx_on(dev, 1, 0);
+ XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
+ }
+ }
+/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
+ }
+#endif
+
+/* The version of set_multicast below was lifted from sunhme.c */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+ static void bmac_set_multicast(struct device *dev)
+ {
+ struct dev_mc_list *dmi = dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ unsigned short rx_cfg;
+ u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+ /* Let the transmits drain. */
+/* while(dev->tbusy) schedule(); */
+
+ /* Lock out others. */
+/* set_bit(0, (void *) &dev->tbusy); */
+
+ if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ bmwrite(dev, BHASH0, 0xffff);
+ bmwrite(dev, BHASH1, 0xffff);
+ bmwrite(dev, BHASH2, 0xffff);
+ bmwrite(dev, BHASH3, 0xffff);
+ } else if(dev->flags & IFF_PROMISC) {
+ rx_cfg = bmread(dev, RXCFG);
+ rx_cfg |= RxPromiscEnable;
+ bmwrite(dev, RXCFG, rx_cfg);
+ } else {
+ u16 hash_table[4];
+
+ for(i = 0; i < 4; i++) hash_table[i] = 0;
+
+ for(i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ if(!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffffU;
+ for(byte = 0; byte < 6; byte++) {
+ for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+ if(test)
+ crc = crc ^ poly;
+ }
+ }
+ crc >>= 26;
+ hash_table[crc >> 4] |= 1 << (crc & 0xf);
+ }
+ bmwrite(dev, BHASH0, hash_table[0]);
+ bmwrite(dev, BHASH1, hash_table[1]);
+ bmwrite(dev, BHASH2, hash_table[2]);
+ bmwrite(dev, BHASH3, hash_table[3]);
+ }
+
+ /* Let us get going again. */
+/* dev->tbusy = 0; */
+ }
+
+
+ static int miscintcount = 0;
+
+ static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct device *dev = (struct device *) dev_id;
+ struct bmac_data *bp = (struct bmac_data *)dev->priv;
+ unsigned int status = bmread(dev, STATUS);
+ if (miscintcount++ < 10) {
+ XXDEBUG(("bmac_misc_intr\n"));
+ }
+/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+/* bmac_txdma_intr_inner(irq, dev_id, regs); */
+/* if (status & FrameReceived) bp->stats.rx_dropped++; */
+ if (status & RxErrorMask) bp->stats.rx_errors++;
+ if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
+ if (status & RxLenCntExp) bp->stats.rx_length_errors++;
+ if (status & RxOverFlow) bp->stats.rx_over_errors++;
+ if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
+
+/* if (status & FrameSent) bp->stats.tx_dropped++; */
+ if (status & TxErrorMask) bp->stats.tx_errors++;
+ if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
+ if (status & TxNormalCollExp) bp->stats.collisions++;
+ }
+
+/*
+ * Procedure for reading EEPROM
+ */
+#define SROMAddressLength 5
+#define DataInOn 0x0008
+#define DataInOff 0x0000
+#define Clk 0x0002
+#define ChipSelect 0x0001
+#define SDIShiftCount 3
+#define SD0ShiftCount 2
+#define DelayValue 1000 /* number of microseconds */
+#define SROMStartOffset 10 /* this is in words */
+#define SROMReadCount 3 /* number of words to read from SROM */
+#define SROMAddressBits 6
+#define EnetAddressOffset 20
+
+ static unsigned char
+ bmac_clock_out_bit(struct device *dev)
+ {
+ unsigned short data;
+ unsigned short val;
+
+ bmwrite(dev, SROMCSR, ChipSelect | Clk);
+ udelay(DelayValue);
+
+ data = bmread(dev, SROMCSR);
+ udelay(DelayValue);
+ val = (data >> SD0ShiftCount) & 1;
+
+ bmwrite(dev, SROMCSR, ChipSelect);
+ udelay(DelayValue);
+
+ return val;
+ }
+
+ static void
+ bmac_clock_in_bit(struct device *dev, unsigned int val)
+ {
+ unsigned short data;
+
+ if (val != 0 && val != 1) return;
+
+ data = (val << SDIShiftCount);
+ bmwrite(dev, SROMCSR, data | ChipSelect );
+ udelay(DelayValue);
+
+ bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
+ udelay(DelayValue);
+
+ bmwrite(dev, SROMCSR, data | ChipSelect);
+ udelay(DelayValue);
+ }
+
+ static void
+ reset_and_select_srom(struct device *dev)
+ {
+ /* first reset */
+ bmwrite(dev, SROMCSR, 0);
+ udelay(DelayValue);
+
+ /* send it the read command (110) */
+ bmac_clock_in_bit(dev, 1);
+ bmac_clock_in_bit(dev, 1);
+ bmac_clock_in_bit(dev, 0);
+ }
+
+ static unsigned short
+ read_srom(struct device *dev, unsigned int addr, unsigned int addr_len)
+ {
+ unsigned short data, val;
+ int i;
+
+ /* send out the address we want to read from */
+ for (i = 0; i < addr_len; i++) {
+ val = addr >> (addr_len-i-1);
+ bmac_clock_in_bit(dev, val & 1);
+ }
+
+ /* Now read in the 16-bit data */
+ data = 0;
+ for (i = 0; i < 16; i++) {
+ val = bmac_clock_out_bit(dev);
+ data <<= 1;
+ data |= val;
+ }
+ bmwrite(dev, SROMCSR, 0);
+
+ return data;
+ }
+
+/*
+ * It looks like Cogent and SMC use different methods for calculating
+ * checksums. What a pain..
+ */
+
+ static int
+ bmac_verify_checksum(struct device *dev)
+ {
+ unsigned short data, storedCS;
+
+ reset_and_select_srom(dev);
+ data = read_srom(dev, 3, SROMAddressBits);
+ storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
+
+ return 0;
+ }
+
+
+ static void
+ bmac_get_station_address(struct device *dev, unsigned char *ea)
+ {
+ int i;
+ unsigned short data;
+
+ for (i = 0; i < 6; i++)
+ {
+ reset_and_select_srom(dev);
+ data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+ ea[2*i] = bitrev(data & 0x0ff);
+ ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+ }
+ }
+
+ static int bmac_reset_and_enable(struct device *dev, int enable)
+ {
+ struct bmac_data *bp = dev->priv;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ bp->reset_and_enabled = 0;
+ bmac_reset_chip(dev);
+ if (enable) {
+ if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
+ if (!bmac_init_chip(dev)) return 0;
+ bmac_start_chip(dev);
+ bmwrite(dev, INTDISABLE, EnableNormal);
+ bp->reset_and_enabled = 1;
+/* { */
+/* unsigned char random_packet[100]; */
+/* unsigned int i; */
+/* struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */
+/* unsigned char *data = skb_put(skb, sizeof(random_packet)); */
+/* XXDEBUG(("transmitting random packet\n")); */
+/* for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */
+/* bmac_transmit_packet(skb, dev); */
+/* XXDEBUG(("done transmitting random packet\n")); */
+/* } */
+ }
+ restore_flags(flags);
+ return 1;
+ }
+
+ int
+ bmac_probe(struct device *dev)
+ {
+ int j, rev;
+ struct bmac_data *bp;
+ struct device_node *bmacs;
+ unsigned char *addr;
+
+ bmacs = find_devices("bmac");
+ if (bmacs == NULL) return ENODEV;
+
+ bmac_devs = dev; /* KLUDGE!! */
+
+ if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
+ printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
+ bmacs->full_name);
+ return EINVAL;
+ }
+
+ if (dev == NULL) {
+ dev = init_etherdev(NULL, PRIV_BYTES);
+ bmac_devs = dev; /*KLUDGE!!*/
+ } else {
+ /* XXX this doesn't look right (but it's never used :-) */
+ dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+ if (dev->priv == 0) return -ENOMEM;
+ }
+
+ dev->base_addr = bmacs->addrs[0].address;
+ dev->irq = bmacs->intrs[0].line;
+
+ bmwrite(dev, INTDISABLE, DisableAll);
+
+ if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+ if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+ dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
+ return -EAGAIN;
+ }
+ if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+ dev)) {
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
+ return -EAGAIN;
+ }
+
+ addr = get_property(bmacs, "mac-address", NULL);
+ if (addr == NULL) {
+ addr = get_property(bmacs, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
+ dev->base_addr);
+ return -EAGAIN;
+ }
+ }
+
+ printk(KERN_INFO "%s: BMAC at", dev->name);
+ rev = addr[0] == 0 && addr[1] == 0xA0;
+ for (j = 0; j < 6; ++j) {
+ dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ }
+ XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+ printk("\n");
+
+ dev->open = bmac_open;
+ dev->stop = bmac_close;
+ dev->hard_start_xmit = bmac_output;
+ dev->get_stats = bmac_stats;
+ dev->set_multicast_list = bmac_set_multicast;
+ dev->set_mac_address = bmac_set_address;
+
+ bmac_get_station_address(dev, addr);
+ if (bmac_verify_checksum(dev) != 0) return EINVAL;
+
+ ether_setup(dev);
+
+ bp = (struct bmac_data *) dev->priv;
+ memset(bp, 0, sizeof(struct bmac_data));
+ bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address;
+ bp->tx_dma_intr = bmacs->intrs[1].line;
+ bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address;
+ bp->rx_dma_intr = bmacs->intrs[2].line;
+
+ bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
+ bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
+
+ bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
+ skb_queue_head_init(bp->queue);
+
+ memset(&bp->stats, 0, sizeof(bp->stats));
+ memset((char *) bp->tx_cmds, 0,
+ (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+/* init_timer(&bp->tx_timeout); */
+/* bp->timeout_active = 0; */
+
+ if (!bmac_reset_and_enable(dev, 0)) return EINVAL;
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_BMAC, 4, "bmac",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ bmac_proc_info
+ });
+#endif
+
+ return 0;
+ }
+
+ static int bmac_open(struct device *dev)
+ {
+/* XXDEBUG(("bmac: enter open\n")); */
+ /* reset the chip */
+ bmac_reset_and_enable(dev, 1);
+
+ dev->flags |= IFF_UP | IFF_RUNNING;
+
+ return 0;
+ }
+
+ static int bmac_close(struct device *dev)
+ {
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ unsigned short config;
+ int i;
+
+ dev->flags &= ~(IFF_UP | IFF_RUNNING);
+
+ /* disable rx and tx */
+ config = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+
+ config = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+
+ bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+
+ /* disable rx and tx dma */
+ st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
+ st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
+
+ /* free some skb's */
+ XXDEBUG(("bmac: free rx bufs\n"));
+ for (i=0; i<N_RX_RING; i++) {
+ if (bp->rx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->rx_bufs[i]);
+ bp->rx_bufs[i] = NULL;
+ }
+ }
+ bp->rx_allocated = 0;
+ XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */
+ if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]);
+ XXDEBUG(("bmac: free tx bufs\n"));
+ for (i = 0; i<N_TX_RING; i++) {
+ if (bp->tx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->tx_bufs[i]);
+ bp->tx_bufs[i] = NULL;
+ }
+ }
+ bp->tx_allocated = 0;
+ bp->reset_and_enabled = 0;
+ XXDEBUG(("bmac: all bufs freed\n"));
+
+ return 0;
+ }
+
+ static void
+ bmac_start(struct device *dev)
+ {
+ struct bmac_data *bp = dev->priv;
+ int i;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ while (1) {
+ i = bp->tx_fill + 1;
+ if (i >= N_TX_RING) i = 0;
+ if (i == bp->tx_empty) break;
+ skb = skb_dequeue(bp->queue);
+ if (skb == NULL) break;
+ bmac_transmit_packet(skb, dev);
+ }
+ restore_flags(flags);
+ }
+
+ static int
+ bmac_output(struct sk_buff *skb, struct device *dev)
+ {
+ struct bmac_data *bp = dev->priv;
+ skb_queue_tail(bp->queue, skb);
+ bmac_start(dev);
+ return 0;
+ }
+
+ static void bmac_tx_timeout(unsigned long data)
+ {
+ struct device *dev = (struct device *) data;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
+ volatile struct dbdma_regs *td = bp->tx_dma;
+ volatile struct dbdma_regs *rd = bp->rx_dma;
+ volatile struct dbdma_cmd *cp;
+ unsigned long flags;
+ unsigned short config, oldConfig;
+ int i;
+
+ XXDEBUG(("bmac: tx_timeout called\n"));
+ save_flags(flags); cli();
+ bp->timeout_active = 0;
+
+ /* update various counters */
+/* bmac_handle_misc_intrs(bp, 0); */
+
+ cp = &bp->tx_cmds[bp->tx_empty];
+/* XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
+/* ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, */
+/* mb->pr, mb->xmtfs, mb->fifofc)); */
+
+ /* turn off both tx and rx and reset the chip */
+ config = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+ config = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+ out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+ printk(KERN_ERR "bmac: transmit timeout - resetting\n");
+ bmac_reset_chip(dev);
+
+ /* restart rx dma */
+ cp = bus_to_virt(ld_le32(&rd->cmdptr));
+ out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+ out_le16(&cp->xfer_status, 0);
+ out_le32(&rd->cmdptr, virt_to_bus(cp));
+ out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
+
+ /* fix up the transmit side */
+ XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
+ bp->tx_empty, bp->tx_fill, bp->tx_fullup));
+ i = bp->tx_empty;
+ ++bp->stats.tx_errors;
+ if (i != bp->tx_fill) {
+ dev_kfree_skb(bp->tx_bufs[i]);
+ bp->tx_bufs[i] = NULL;
+ if (++i >= N_TX_RING) i = 0;
+ bp->tx_empty = i;
+ }
+ bp->tx_fullup = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+ if (i != bp->tx_fill) {
+ cp = &bp->tx_cmds[i];
+ out_le16(&cp->xfer_status, 0);
+ out_le16(&cp->command, OUTPUT_LAST);
+ out_le32(&td->cmdptr, virt_to_bus(cp));
+ out_le32(&td->control, DBDMA_SET(RUN));
+/* bmac_set_timeout(dev); */
+ XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
+ }
+
+ /* turn it back on */
+ oldConfig = bmread(dev, RXCFG);
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
+ restore_flags(flags);
+ }
+
+#if 0
+ static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+ {
+ int i,*ip;
+
+ for (i=0;i< count;i++)
+ {
+ ip = (int*)(cp+i);
+
+ printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+ ld_le32(ip+0),
+ ld_le32(ip+1),
+ ld_le32(ip+2),
+ ld_le32(ip+3));
+ }
+
+ }
+#endif
+
+ static int
+ bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy)
+ {
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ int i;
+
+ if (bmac_devs == NULL) return (-ENOSYS);
+
+ len += sprintf(buffer, "BMAC counters & registers\n");
+
+ for (i = 0; i<N_REG_ENTRIES; i++) {
+ len += sprintf(buffer + len, "%s: %#08x\n",
+ reg_entries[i].name,
+ bmread(bmac_devs, reg_entries[i].reg_offset));
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset+length) break;
+ }
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return len;
+ }
--- /dev/null
+/*
+ * mace.h - definitions for the registers in the "Big Mac"
+ * Ethernet controller found in PowerMac G3 models.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal"
+ * (HME) controller. See sunhme.h
+ */
+
+
+/* register offsets */
+
+/* global status and control */
+#define XIFC 0x000 /* low-level interface control */
+# define TxOutputEnable 0x0001 /* output driver enable */
+# define XIFLoopback 0x0002 /* Loopback-mode XIF enable */
+# define MIILoopback 0x0004 /* Loopback-mode MII enable */
+# define MIILoopbackBits 0x0006
+# define MIIBuffDisable 0x0008 /* MII receive buffer disable */
+# define SQETestEnable 0x0010 /* SQE test enable */
+# define SQETimeWindow 0x03e0 /* SQE time window */
+# define XIFLanceMode 0x0010 /* Lance mode enable */
+# define XIFLanceIPG0 0x03e0 /* Lance mode IPG0 */
+#define TXFIFOCSR 0x100 /* transmit FIFO control */
+# define TxFIFOEnable 0x0001
+#define TXTH 0x110 /* transmit threshold */
+# define TxThreshold 0x0004
+#define RXFIFOCSR 0x120 /* receive FIFO control */
+# define RxFIFOEnable 0x0001
+#define MEMADD 0x130 /* memory address, unknown function */
+#define MEMDATAHI 0x140 /* memory data high, presently unused in driver */
+#define MEMDATALO 0x150 /* memory data low, presently unused in driver */
+#define XCVRIF 0x160 /* transceiver interface control */
+# define COLActiveLow 0x0002
+# define SerialMode 0x0004
+# define ClkBit 0x0008
+# define LinkStatus 0x0100
+#define CHIPID 0x170 /* chip ID */
+#define MIFCSR 0x180 /* ??? */
+#define SROMCSR 0x190 /* SROM control */
+# define ChipSelect 0x0001
+# define Clk 0x0002
+#define TXPNTR 0x1a0 /* transmit pointer */
+#define RXPNTR 0x1b0 /* receive pointer */
+#define STATUS 0x200 /* status--reading this clears it */
+#define INTDISABLE 0x210 /* interrupt enable/disable control */
+/* bits below are the same in both STATUS and INTDISABLE registers */
+# define FrameReceived 0x00000001 /* Received a frame */
+# define RxFrameCntExp 0x00000002 /* Receive frame counter expired */
+# define RxAlignCntExp 0x00000004 /* Align-error counter expired */
+# define RxCRCCntExp 0x00000008 /* CRC-error counter expired */
+# define RxLenCntExp 0x00000010 /* Length-error counter expired */
+# define RxOverFlow 0x00000020 /* Receive FIFO overflow */
+# define RxCodeViolation 0x00000040 /* Code-violation counter expired */
+# define SQETestError 0x00000080 /* Test error in XIF for SQE */
+# define FrameSent 0x00000100 /* Transmitted a frame */
+# define TxUnderrun 0x00000200 /* Transmit FIFO underrun */
+# define TxMaxSizeError 0x00000400 /* Max-packet size error */
+# define TxNormalCollExp 0x00000800 /* Normal-collision counter expired */
+# define TxExcessCollExp 0x00001000 /* Excess-collision counter expired */
+# define TxLateCollExp 0x00002000 /* Late-collision counter expired */
+# define TxNetworkCollExp 0x00004000 /* First-collision counter expired */
+# define TxDeferTimerExp 0x00008000 /* Defer-timer expired */
+# define RxFIFOToHost 0x00010000 /* Data moved from FIFO to host */
+# define RxNoDescriptors 0x00020000 /* No more receive descriptors */
+# define RxDMAError 0x00040000 /* Error during receive DMA */
+# define RxDMALateErr 0x00080000 /* Receive DMA, data late */
+# define RxParityErr 0x00100000 /* Parity error during receive DMA */
+# define RxTagError 0x00200000 /* Tag error during receive DMA */
+# define TxEOPError 0x00400000 /* Tx descriptor did not have EOP set */
+# define MIFIntrEvent 0x00800000 /* MIF is signaling an interrupt */
+# define TxHostToFIFO 0x01000000 /* Data moved from host to FIFO */
+# define TxFIFOAllSent 0x02000000 /* Transmitted all packets in FIFO */
+# define TxDMAError 0x04000000 /* Error during transmit DMA */
+# define TxDMALateError 0x08000000 /* Late error during transmit DMA */
+# define TxParityError 0x10000000 /* Parity error during transmit DMA */
+# define TxTagError 0x20000000 /* Tag error during transmit DMA */
+# define PIOError 0x40000000 /* PIO access got an error */
+# define PIOParityError 0x80000000 /* PIO access got a parity error */
+# define DisableAll 0xffffffff
+# define EnableAll 0x00000000
+/* # define NormalIntEvents ~(FrameReceived | FrameSent | TxUnderrun) */
+# define EnableNormal ~(FrameReceived | FrameSent)
+# define EnableErrors (FrameReceived | FrameSent)
+# define RxErrorMask (RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \
+ RxLenCntExp | RxOverFlow | RxCodeViolation)
+# define TxErrorMask (TxUnderrun | TxMaxSizeError | TxExcessCollExp | \
+ TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp)
+
+/* transmit control */
+#define TXRST 0x420 /* transmit reset */
+# define TxResetBit 0x0001
+#define TXCFG 0x430 /* transmit configuration control*/
+# define TxMACEnable 0x0001 /* output driver enable */
+# define TxSlowMode 0x0020 /* enable slow mode */
+# define TxIgnoreColl 0x0040 /* ignore transmit collisions */
+# define TxNoFCS 0x0080 /* do not emit FCS */
+# define TxNoBackoff 0x0100 /* no backoff in case of collisions */
+# define TxFullDuplex 0x0200 /* enable full-duplex */
+# define TxNeverGiveUp 0x0400 /* don't give up on transmits */
+#define IPG1 0x440 /* Inter-packet gap 1 */
+#define IPG2 0x450 /* Inter-packet gap 2 */
+#define ALIMIT 0x460 /* Transmit attempt limit */
+#define SLOT 0x470 /* Transmit slot time */
+#define PALEN 0x480 /* Size of transmit preamble */
+#define PAPAT 0x490 /* Pattern for transmit preamble */
+#define TXSFD 0x4a0 /* Transmit frame delimiter */
+#define JAM 0x4b0 /* Jam size */
+#define TXMAX 0x4c0 /* Transmit max pkt size */
+#define TXMIN 0x4d0 /* Transmit min pkt size */
+#define PAREG 0x4e0 /* Count of transmit peak attempts */
+#define DCNT 0x4f0 /* Transmit defer timer */
+#define NCCNT 0x500 /* Transmit normal-collision counter */
+#define NTCNT 0x510 /* Transmit first-collision counter */
+#define EXCNT 0x520 /* Transmit excess-collision counter */
+#define LTCNT 0x530 /* Transmit late-collision counter */
+#define RSEED 0x540 /* Transmit random number seed */
+#define TXSM 0x550 /* Transmit state machine */
+
+/* receive control */
+#define RXRST 0x620 /* receive reset */
+# define RxResetValue 0x0000
+#define RXCFG 0x630 /* receive configuration control */
+# define RxMACEnable 0x0001 /* receiver overall enable */
+# define RxCFGReserved 0x0004
+# define RxPadStripEnab 0x0020 /* enable pad byte stripping */
+# define RxPromiscEnable 0x0040 /* turn on promiscuous mode */
+# define RxNoErrCheck 0x0080 /* disable receive error checking */
+# define RxCRCNoStrip 0x0100 /* disable auto-CRC-stripping */
+# define RxRejectOwnPackets 0x0200 /* don't receive our own packets */
+# define RxGrpPromisck 0x0400 /* enable group promiscuous mode */
+# define RxHashFilterEnable 0x0800 /* enable hash filter */
+# define RxAddrFilterEnable 0x1000 /* enable address filter */
+#define RXMAX 0x640 /* Max receive packet size */
+#define RXMIN 0x650 /* Min receive packet size */
+#define MADD2 0x660 /* our enet address, high part */
+#define MADD1 0x670 /* our enet address, middle part */
+#define MADD0 0x680 /* our enet address, low part */
+#define FRCNT 0x690 /* receive frame counter */
+#define LECNT 0x6a0 /* Receive excess length error counter */
+#define AECNT 0x6b0 /* Receive misaligned error counter */
+#define FECNT 0x6c0 /* Receive CRC error counter */
+#define RXSM 0x6d0 /* Receive state machine */
+#define RXCV 0x6e0 /* Receive code violation */
+
+#define BHASH3 0x700 /* multicast hash register */
+#define BHASH2 0x710 /* multicast hash register */
+#define BHASH1 0x720 /* multicast hash register */
+#define BHASH0 0x730 /* multicast hash register */
+
+#define AFR2 0x740 /* address filtering setup? */
+#define AFR1 0x750 /* address filtering setup? */
+#define AFR0 0x760 /* address filtering setup? */
+#define AFCR 0x770 /* address filter compare register? */
+# define EnableAllCompares 0x0fff
+
+/* bits in XIFC */
--- /dev/null
+/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/*
+ Derived from code:
+
+ Written 1993-94 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ TODO:
+
+ The block output routines may be wrong for non Dayna
+ cards
+
+ Reading MAC addresses
+*/
+
+static const char *version =
+ "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom);
+
+static int ns8390_open(struct device *dev);
+static void ns8390_no_reset(struct device *dev);
+static int ns8390_close_card(struct device *dev);
+
+static void interlan_reset(struct device *dev);
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void dayna_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void sane_block_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
+
+\f
+#define WD_START_PG 0x00 /* First page of TX buffer */
+#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
+#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
+
+
+#define DAYNA_MAC_BASE 0xf0007
+#define DAYNA_8390_BASE 0x80000 /* 3 */
+#define DAYNA_8390_MEM 0x00000
+#define DAYNA_MEMSIZE 0x04000 /* First word of each long ! */
+
+#define APPLE_8390_BASE 0xE0000
+#define APPLE_8390_MEM 0xD0000
+#define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */
+
+#define KINETICS_8390_BASE 0x80003
+#define KINETICS_8390_MEM 0x00000
+#define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */
+
+static int test_8390(volatile char *ptr, int scale)
+{
+ int regd;
+ int v;
+
+ if(nubus_hwreg_present(&ptr[0x00])==0)
+ return -EIO;
+ if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+ return -EIO;
+ if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+ return -EIO;
+ ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
+ regd=ptr[0x0D<<scale];
+ ptr[0x0D<<scale]=0xFF;
+ ptr[0x00]=E8390_NODMA+E8390_PAGE0;
+ v=ptr[0x0D<<scale];
+ if(ptr[0x0D<<scale]!=0)
+ {
+ ptr[0x0D<<scale]=regd;
+ return -ENODEV;
+ }
+/* printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
+ return 0;
+}
+/*
+ * Identify the species of NS8390 card/driver we need
+ */
+
+#define NS8390_DAYNA 1
+#define NS8390_INTERLAN 2
+#define NS8390_KINETICS 3
+#define NS8390_APPLE 4
+#define NS8390_FARALLON 5
+#define NS8390_ASANTE 6
+
+int ns8390_ident(struct nubus_type *nb)
+{
+ /* It appears anything with a software type of 0 is an apple
+ compatible - even if the hardware matches others */
+
+ if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
+ return NS8390_APPLE;
+
+ /* Dayna ex Kinetics board */
+ if(nb->DrHW==0x0103)
+ return NS8390_DAYNA;
+
+ /* Asante board */
+ if(nb->DrHW==0x0104)
+ return NS8390_ASANTE;
+ if(nb->DrHW==0x0100)
+ return NS8390_INTERLAN;
+ if(nb->DrHW==0x0106)
+ return NS8390_KINETICS;
+ if(nb->DrSW==0x010C)
+ return NS8390_FARALLON;
+ return -1;
+}
+
+/*
+ * Probe for 8390 cards.
+ * The ns8390_probe1() routine initializes the card and fills the
+ * station address field. On entry base_addr is set, irq is set
+ * (These come from the nubus probe code). dev->mem_start points
+ * at the memory ring, dev->mem_end gives the end of it.
+ */
+
+int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+{
+ struct device *dev;
+ volatile unsigned short *i;
+ volatile unsigned char *p;
+ int plen;
+ int id;
+
+ if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
+ return -ENODEV;
+ /* Ok so it is an ethernet network device */
+ if((id=ns8390_ident(match))==-1)
+ {
+ printk("Ethernet but type unknown %d\n",match->DrHW);
+ return -ENODEV;
+ }
+ dev = init_etherdev(0, 0);
+ if(dev==NULL)
+ return -ENOMEM;
+
+ /*
+ * Dayna specific init
+ */
+ if(id==NS8390_DAYNA)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
+ dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+
+ printk("daynaport: testing board: ");
+
+ printk("memory - ");
+
+ i=(void *)dev->mem_start;
+ memset((void *)i,0xAA, DAYNA_MEMSIZE);
+ while(i<(volatile unsigned short *)dev->mem_end)
+ {
+ if(*i!=0xAAAA)
+ goto membad;
+ *i=0x5555;
+ if(*i!=0x5555)
+ goto membad;
+ i+=2; /* Skip a word */
+ }
+
+ printk("controller - ");
+
+ p=(void *)dev->base_addr;
+ plen=0;
+
+ while(plen<0x3FF00)
+ {
+ if(test_8390(p,0)==0)
+ break;
+ if(test_8390(p,1)==0)
+ break;
+ if(test_8390(p,2)==0)
+ break;
+ if(test_8390(p,3)==0)
+ break;
+ plen++;
+ p++;
+ }
+ if(plen==0x3FF00)
+ goto membad;
+ printk("OK\n");
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
+ return 0;
+ }
+ /* Apple, Farallon, Asante */
+ if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+ dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ printk("apple/clone: testing board: ");
+
+ printk("memory - ");
+
+ i=(void *)dev->mem_start;
+ memset((void *)i,0xAA, DAYNA_MEMSIZE);
+ while(i<(volatile unsigned short *)dev->mem_end)
+ {
+ if(*i!=0xAAAA)
+ goto membad;
+ *i=0x5555;
+ if(*i!=0x5555)
+ goto membad;
+ i+=2; /* Skip a word */
+ }
+ printk("OK\n");
+
+ if(id==NS8390_FARALLON)
+ {
+ if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+ return 0;
+ }
+ else
+ {
+ if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
+ return 0;
+ }
+ }
+ /* Interlan */
+ if(id==NS8390_INTERLAN)
+ {
+ /* As apple and asante */
+ dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+ dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+ return 0;
+ }
+ /* Kinetics */
+ if(id==NS8390_KINETICS)
+ {
+ dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
+ dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+ dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
+ dev->irq=slot;
+ if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+ return 0;
+ }
+ kfree(dev);
+ return -ENODEV;
+membad:
+ printk("failed.\n");
+ kfree(dev);
+ return -ENODEV;
+}
+
+int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff)
+{
+ static unsigned version_printed = 0;
+
+ static unsigned char fwrd4_offsets[16]={
+ 0, 4, 8, 12,
+ 16, 20, 24, 28,
+ 32, 36, 40, 44,
+ 48, 52, 56, 60
+ };
+ static unsigned char back4_offsets[16]={
+ 60, 56, 52, 48,
+ 44, 40, 36, 32,
+ 28, 24, 20, 16,
+ 12, 8, 4, 0
+ };
+
+ unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+
+ if (ei_debug && version_printed++ == 0)
+ printk(version);
+
+ /* Snarf the interrupt now. There's no point in waiting since we cannot
+ share a slot! and the board will usually be enabled. */
+ if (nubus_request_irq(dev->irq, dev, ei_interrupt))
+ {
+ printk (" unable to get nubus IRQ %d.\n", dev->irq);
+ return EAGAIN;
+ }
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev))
+ {
+ printk (" unable to get memory for dev->priv.\n");
+ nubus_free_irq(dev->irq);
+ return -ENOMEM;
+ }
+
+ /* OK, we are certain this is going to work. Setup the device. */
+
+ ei_status.name = model_name;
+ ei_status.word16 = word16;
+ ei_status.tx_start_page = WD_START_PG;
+ ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+ dev->rmem_end = dev->mem_end;
+
+ if(promoff==-1) /* Use nubus resources ? */
+ {
+ if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+ {
+ printk("mac_ns8390: MAC address not in resources!\n");
+ return -ENODEV;
+ }
+ }
+ else /* Pull it off the card */
+ {
+ int i=0;
+ int x=1;
+ /* These should go in the end I hope */
+ if(type==NS8390_DAYNA)
+ x=2;
+ if(type==NS8390_INTERLAN)
+ x=4;
+ while(i<6)
+ {
+ dev->dev_addr[i]=*prom;
+ prom+=x;
+ if(i)
+ printk(":");
+ printk("%02X",dev->dev_addr[i++]);
+ }
+ }
+
+ printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
+ model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+
+ switch(type)
+ {
+ case NS8390_DAYNA: /* Dayna card */
+ /* 16 bit, 4 word offsets */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &dayna_block_input;
+ ei_status.block_output = &dayna_block_output;
+ ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+ ei_status.reg_offset = fwrd4_offsets;
+ break;
+ case NS8390_APPLE: /* Apple/Asante/Farallon */
+ case NS8390_FARALLON:
+ case NS8390_ASANTE:
+ /* 16 bit card, register map is reversed */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ case NS8390_INTERLAN: /* Interlan */
+ /* 16 bit card, map is forward */
+ ei_status.reset_8390 = &interlan_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ case NS8390_KINETICS: /* Kinetics */
+ /* 8bit card, map is forward */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+ default:
+ panic("Detected a card I can't drive - whoops\n");
+ }
+ dev->open = &ns8390_open;
+ dev->stop = &ns8390_close_card;
+
+ NS8390_init(dev, 0);
+
+ return 0;
+}
+
+static int ns8390_open(struct device *dev)
+{
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void ns8390_no_reset(struct device *dev)
+{
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ if (ei_debug > 1) printk("reset not supported\n");
+ return;
+}
+
+static int ns8390_close_card(struct device *dev)
+{
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+ ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+struct nubus_device_specifier nubus_8390={
+ ns8390_probe,
+ NULL
+};
+
+
+/*
+ * Interlan Specific Code Starts Here
+ */
+
+static void interlan_reset(struct device *dev)
+{
+ unsigned char *target=nubus_slot_addr(dev->irq);
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ /* This write resets the card */
+ target[0xC0000]=0;
+ if (ei_debug > 1) printk("reset complete\n");
+ return;
+}
+
+/*
+ * Daynaport code (some is used by other drivers)
+ */
+
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+
+/* Block input and output are easy on shared memory ethercards, and trivial
+ on the Daynaport card where there is no choice of how to do it.
+ The only complications are that the ring buffer wraps.
+*/
+
+static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count)
+{
+ volatile unsigned short *ptr;
+ unsigned short *target=to;
+ from<<=1; /* word, skip overhead */
+ ptr=(unsigned short *)(dev->mem_start+from);
+ while(count>=2)
+ {
+ *target++=*ptr++; /* Copy and */
+ ptr++; /* Cruft and */
+ count-=2;
+ }
+ /*
+ * Trailing byte ?
+ */
+ if(count)
+ {
+ /* Big endian */
+ unsigned short v=*ptr;
+ *((char *)target)=v>>8;
+ }
+}
+
+static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count)
+{
+ volatile unsigned short *ptr;
+ const unsigned short *src=from;
+ to<<=1; /* word, skip overhead */
+ ptr=(unsigned short *)(dev->mem_start+to);
+ while(count>=2)
+ {
+ *ptr++=*src++; /* Copy and */
+ ptr++; /* Cruft and */
+ count-=2;
+ }
+ /*
+ * Trailing byte ?
+ */
+ if(count)
+ {
+ /* Big endian */
+ unsigned short v=*src;
+ *((char *)ptr)=v>>8;
+ }
+}
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+ dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+ /* Register endianism - fix here rather than 8390.c */
+ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+ unsigned long xfer_start = xfer_base+dev->mem_start;
+
+ /*
+ * Note the offset maths is done in card memory space which
+ * is word per long onto our space.
+ */
+
+ if (xfer_start + count > dev->rmem_end)
+ {
+ /* We must wrap the input move. */
+ int semi_count = dev->rmem_end - xfer_start;
+ dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+ count -= semi_count;
+ dayna_cpu_memcpy(dev, skb->data + semi_count,
+ dev->rmem_start - dev->mem_start, count);
+ }
+ else
+ {
+ dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+ }
+}
+
+static void dayna_block_output(struct device *dev, int count, const unsigned char *buf,
+ int start_page)
+{
+ long shmem = (start_page - WD_START_PG)<<8;
+
+ cpu_dayna_memcpy(dev, shmem, buf, count);
+}
+
+/*
+ * Cards with full width memory
+ */
+
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+ memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+ /* Register endianism - fix here rather than 8390.c */
+ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+ unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+ unsigned long xfer_start = xfer_base+dev->mem_start;
+
+ if (xfer_start + count > dev->rmem_end)
+ {
+ /* We must wrap the input move. */
+ int semi_count = dev->rmem_end - xfer_start;
+ memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
+ count -= semi_count;
+ memcpy(skb->data + semi_count,
+ (char *)dev->rmem_start, count);
+ }
+ else
+ {
+ memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
+ }
+}
+
+static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
+ int start_page)
+{
+ long shmem = (start_page - WD_START_PG)<<8;
+
+ memcpy((char *)dev->mem_start+shmem, buf, count);
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
+ * version-control: t
+ * tab-width: 4
+ * kept-new-versions: 5
+ * End:
+ */
dev->tbusy = 0;
}
+ lp->stats.tx_bytes += length;
+
if (net_debug > 5)
printk("eepro: exiting hardware_send_packet routine.\n");
return;
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += rcv_size;
}
else { /* Not sure will ever reach here,
I set the 595 to discard bad received frames */
* Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
* + Now compiles ok as a module again.
*
- * Changes by Paul Norton (pnorton@cts.com) :
+ * Changes by Paul Norton (p.norton@computer.org) :
* + moved the header manipulation code in tr_tx and tr_rx to
* net/802/tr.c. (July 12 1997)
+ * + add retry and timeout on open if cable disconnected. (May 5 1998)
* + lifted 2000 byte mtu limit. now depends on shared-RAM size.
* May 25 1998)
*/
DPRINTK("No signal detected for Auto Speed Detection.\n");
else if (open_error_code==0x11)
{
- ti->open_status=FAILURE;
- DPRINTK("Ring broken/disconnected.\n");
- wake_up(&ti->wait_for_reset);
+ if (ti->retry_count--)
+ DPRINTK("Ring broken/disconnected, retrying...\n");
+ else {
+ DPRINTK("Ring broken/disconnected, open failed.\n");
+ ti->open_status = FAILURE;
+ }
}
else DPRINTK("Unrecoverable error: error code = %04x.\n",
open_error_code);
#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6 /* number of open retries */
#define TR_ISA 1
#define TR_MCA 2
struct timer_list tr_timer;
unsigned char ring_speed;
__u32 func_addr;
+ unsigned int retry_count;
};
/* token ring adapter commands */
struct pci_dev *pdev = NULL;
if (lance_debug > 1)
printk("lance.c: PCI is present, checking for devices...\n");
- while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) {
- unsigned char pci_bus, pci_device_fn;
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
unsigned int pci_ioaddr;
unsigned short pci_command;
if ((fs & XMTSV) == 0) {
printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
fs, xcount, dstat);
+ return;
}
cp = mp->tx_cmds + NCMDS_TX * i;
stat = ld_le16(&cp->xfer_status);
if (frame_status & RS_FCSERR)
++mp->stats.rx_crc_errors;
} else {
- nb -= 8;
+ /* Mace feature AUTO_STRIP_RCV is on by default, dropping the
+ * FCS on frames with 802.3 headers. This means that Ethernet
+ * frames have 8 extra octets at the end, while 802.3 frames
+ * have only 4. We need to correctly account for this. */
+ if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
+ nb -= 4;
+ else /* Ethernet header; mace includes FCS */
+ nb -= 8;
skb_put(skb, nb);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
dev->hard_start_xmit = &myri_start_xmit;
dev->get_stats = &myri_get_stats;
dev->set_multicast_list = &myri_set_multicast;
- dev->irq = sdev->irqs[0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
-#ifdef __sparc_v9__
- if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = sdev->my_bus;
- if(request_irq(dev->irq, &myri_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "MyriCOM Ethernet", &dcookie)) {
- printk("MyriCOM: Cannot register interrupt handler.\n");
- return ENODEV;
- }
- } else
-#endif
if(request_irq(dev->irq, &myri_interrupt,
SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
printk("MyriCOM: Cannot register interrupt handler.\n");
/* Inform the upper layer for the arrival of a packet. */
rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
netif_rx(rcv->skb);
+ nl->enet_stats.rx_bytes += rcv->length.h;
nl->enet_stats.rx_packets++;
rcv->skb = NULL;
if (net_debug > 2)
&snd->nibble, snd->checksum))
return TIMEOUT;
+ nl->enet_stats.tx_bytes += snd->skb->len;
dev_kfree_skb(snd->skb);
nl->enet_stats.tx_packets++;
snd->state = PLIP_PK_DONE;
seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
{
int ioaddr = dev->base_addr;
+ struct net_local *lp = (struct net_local *)dev->priv;
if (dev->tbusy) {
/* If we get here, some higher level has decided we are broken.
hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
+ lp->stats.tx_bytes += length;
}
dev_kfree_skb (skb);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
}
} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
*/
dev->tbusy = 0;
}
+
+ p->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
return 0;
writeb(RX_OWN, rmdp->u.s.status);
p->stats.rx_packets++;
+ p->stats.rx_bytes += len;
p->rmdnum++;
lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
lp->cur_tx++;
+ lp->stats.tx_bytes += length;
if (sonic_debug > 2)
printk("sonic_send_packet: issueing Tx command\n");
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb); /* pass the packet to upper layers */
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
} else {
/* This should only happen, if we enable accepting broken packets. */
}
#endif
+#ifndef __sparc_v9__
static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *) dev_id;
dev->interrupt = 0;
HMD(("done\n"));
}
+#endif
static int happy_meal_open(struct device *dev)
{
int res;
HMD(("happy_meal_open: "));
+#ifndef __sparc_v9__
if(sparc_cpu_model == sun4c) {
if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
printk("happy meal: Can't order irq %d to go.\n", dev->irq);
return -EAGAIN;
}
- }
-#ifdef __sparc_v9__
- else if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
+ } else
+#else
#ifdef CONFIG_PCI
- if(hp->happy_flags & HFLAG_PCI) {
- if(request_irq(dev->irq, &pci_happy_meal_interrupt,
- SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
- HMD(("EAGAIN\n"));
- printk("happy_meal(PCI: Can't order irq %d to go.\n",
- dev->irq);
- return -EAGAIN;
- }
- goto v9_done;
- }
-#endif
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = hp->happy_sbus_dev->my_bus;
- if(request_irq(dev->irq, &happy_meal_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "HAPPY MEAL", &dcookie)) {
- HMD(("EAGAIN\n"));
- printk("happy_meal(SBUS): Can't order irq %d to go.\n",
- dev->irq);
+ if(hp->happy_flags & HFLAG_PCI) {
+ if(request_irq(dev->irq, &pci_happy_meal_interrupt,
+ SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(PCI: Can't order irq %s to go.\n",
+ __irq_itoa(dev->irq));
return -EAGAIN;
}
-#ifdef CONFIG_PCI
- v9_done:
+ } else
#endif
- }
#endif
- else {
- if(request_irq(dev->irq, &happy_meal_interrupt,
- SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
- HMD(("EAGAIN\n"));
- printk("happy meal: Can't order irq %d to go.\n", dev->irq);
- return -EAGAIN;
- }
+ if(request_irq(dev->irq, &happy_meal_interrupt,
+ SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
+ HMD(("EAGAIN\n"));
+ printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+ __irq_itoa(dev->irq));
+ return -EAGAIN;
}
HMD(("Init happy timer\n"));
init_timer(&hp->happy_timer);
dev->get_stats = &happy_meal_get_stats;
dev->set_multicast_list = &happy_meal_set_multicast;
- dev->irq = sdev->irqs[0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
ether_setup(dev);
#ifdef MODULE
-/* $Id: sunlance.c,v 1.75 1998/04/24 12:29:50 davem Exp $
+/* $Id: sunlance.c,v 1.79 1998/06/04 09:54:58 jj Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
last_dev = dev;
-#ifdef __sparc_v9__
- if (sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = lp->sbus;
- if(request_irq(dev->irq, &lance_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- lancestr, &dcookie)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
- }
-#else
- if (sparc_cpu_model == sun4d) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = dev;
- dcookie.bus_cookie = (void *)dev->base_addr;
- if(request_irq(dev->irq, &lance_interrupt,
- (SA_SHIRQ | SA_DCOOKIE),
- lancestr, &dcookie)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
- } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
+ if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
lancestr, (void *) dev)) {
- printk ("Lance: Can't get irq %d\n", dev->irq);
+ printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
return -EAGAIN;
}
-#endif
/* Stop the Lance */
ll->rap = LE_CSR0;
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
- dev->irq = (unsigned char) sdev->irqs [0].pri;
+ dev->irq = sdev->irqs[0];
dev->dma = 0;
ether_setup (dev);
if (idprom->id_machtype == (SM_SUN4|SM_4_330)) {
memset (&sdev, 0, sizeof(sdev));
sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR;
- sdev.irqs[0].pri = 6;
+ sdev.irqs[0] = 6;
return sparc_lance_init(dev, &sdev, 0, 0);
}
return ENODEV;
qe_devs[i]->hard_start_xmit = qe_start_xmit;
qe_devs[i]->get_stats = qe_get_stats;
qe_devs[i]->set_multicast_list = qe_set_multicast;
- qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri;
+ qe_devs[i]->irq = sdev->irqs[0];
qe_devs[i]->dma = 0;
ether_setup(qe_devs[i]);
}
* for it now.
*/
if(sparc_cpu_model == sun4c) {
- if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt,
+ if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk("QuadEther: Can't register QEC master irq handler.\n");
res = EAGAIN;
goto qec_free_devs;
}
- }
-#ifdef __sparc_v9__
- else if(sparc_cpu_model == sun4u) {
- struct devid_cookie dcookie;
-
- dcookie.real_dev_id = qecp;
- dcookie.imap = dcookie.iclr = 0;
- dcookie.pil = -1;
- dcookie.bus_cookie = sdev->my_bus;
- if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
- (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
- "QuadEther", &dcookie)) {
- printk("QuadEther: Can't register QEC master irq handler.\n");
- res = EAGAIN;
- goto qec_free_devs;
- }
- }
-#endif
- else {
- if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
+ } else {
+ if(request_irq(sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk("QuadEther: Can't register QEC master irq handler.\n");
res = EAGAIN;
unregister_netdev(root_qec_dev->qes[i]->dev);
kfree(root_qec_dev->qes[i]);
}
- free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev);
+ free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);
kfree(root_qec_dev);
root_qec_dev = next_qec;
}
static void
psa_write(u_long ioaddr,
u_short hacr,
- int o, /* Offset in psa */
+ int o, /* Offset in PSA */
u_char * b, /* Buffer in memory */
int n) /* Length of buffer */
{
* Get the type of encryption available.
*/
static inline int
-mmc_encr(u_long ioaddr) /* i/o port of the card */
+mmc_encr(u_long ioaddr) /* I/O port of the card */
{
int temp;
* I hope this one will be optimally inlined.
*/
static inline void
-fee_wait(u_long ioaddr, /* i/o port of the card */
+fee_wait(u_long ioaddr, /* I/O port of the card */
int delay, /* Base delay to wait for */
int number) /* Number of time to wait */
{
* Read bytes from the Frequency EEPROM (frequency select cards).
*/
static void
-fee_read(u_long ioaddr, /* i/o port of the card */
+fee_read(u_long ioaddr, /* I/O port of the card */
u_short o, /* destination offset */
u_short * b, /* data buffer */
int n) /* number of registers */
* Jean II
*/
static void
-fee_write(u_long ioaddr, /* i/o port of the card */
+fee_write(u_long ioaddr, /* I/O port of the card */
u_short o, /* destination offset */
u_short * b, /* data buffer */
int n) /* number of registers */
fee_wait(ioaddr, 10, 100);
/* Read the protected register. */
- printk("Protected 2 : %02X-%02X\n",
+ printk("Protected 2: %02X-%02X\n",
mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
#endif /* DOESNT_SEEM_TO_WORK */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
- /* Or use : */
+ /* or use: */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
#endif /* DOESNT_SEEM_TO_WORK */
/* Read the first transmit buffer */
obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
- /* Hack for reconfiguration... */
+ /* Hack for reconfiguration */
if(tx_status == 0xFFFF)
if(!wv_config_complete(dev, ioaddr, lp))
break; /* Not completed */
lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
}
- /* Hack for reconfiguration... */
+ /* Hack for reconfiguration */
if(tx_status == 0xFFFF)
continue;
static void
wv_psa_show(psa_t * p)
{
- printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
p->psa_io_base_addr_2,
printk(KERN_DEBUG "status: ");
printk("stat 0x%x[%s%s%s%s] ",
(scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
- (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "",
+ (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
(scb.scb_status & SCB_ST_FR) ? "frame received," : "",
- (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "",
- (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : "");
+ (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+ (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
printk("cus 0x%x[%s%s%s] ",
(scb.scb_status & SCB_ST_CUS) >> 8,
((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
printk(KERN_DEBUG "ru:");
/*
- * Not implemented yet...
+ * Not implemented yet
*/
printk("\n");
} /* wv_ru_show */
#endif
#ifdef DEBUG_BASIC_SHOW
- /* Now, let's go for the basic stuff */
+ /* Now, let's go for the basic stuff. */
printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
{
unsigned short freq;
- /* Ask the EEPROM to read the frequency from the first area */
- fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
- &freq, 1);
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
/* Print frequency */
printk(", 2.00, %ld", (freq >> 6) + 2400L);
return 0;
}
-#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */
/*------------------------------------------------------------------*/
/*
- * Frequency setting (for hardware able of it)
- * It's a bit complicated and you don't really want to look into it...
+ * Frequency setting (for hardware capable of it)
+ * It's a bit complicated and you don't really want to look into it.
* (called in wavelan_ioctl)
*/
static inline int
-wv_set_frequency(u_long ioaddr, /* i/o port of the card */
+wv_set_frequency(u_long ioaddr, /* I/O port of the card */
iw_freq * frequency)
{
const int BAND_NUM = 10; /* Number of bands */
/* Setting by frequency */
/* Theoretically, you may set any frequency between
* the two limits with a 0.5 MHz precision. In practice,
- * I don't want you to have trouble with local
- * regulations. */
+ * I don't want you to have trouble with local regulations.
+ */
if((frequency->e == 1) &&
(frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
{
u_short table[10]; /* Authorized frequency table */
/* Read the frequency table. */
- fee_read(ioaddr, 0x71 /* frequency table */,
- table, 10);
+ fee_read(ioaddr, 0x71, table, 10);
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "Frequency table: ");
unsigned short area_verify[16];
unsigned short dac_verify[2];
/* Corresponding gain (in the power adjust value table)
- * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
- * & WCIN062D.DOC, page 6.2.9 */
+ * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+ * and WCIN062D.DOC, page 6.2.9. */
unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
int power_band = 0; /* Selected band */
unsigned short power_adjust; /* Correct value */
- /* Search for the gain */
+ /* Search for the gain. */
power_band = 0;
while((freq > power_limit[power_band]) &&
(power_limit[++power_band] != 0))
;
/* Read the first area. */
- fee_read(ioaddr, 0x00,
- area, 16);
+ fee_read(ioaddr, 0x00, area, 16);
/* Read the DAC. */
- fee_read(ioaddr, 0x60,
- dac, 2);
+ fee_read(ioaddr, 0x60, dac, 2);
/* Read the new power adjust value. */
- fee_read(ioaddr, 0x6B - (power_band >> 1),
- &power_adjust, 1);
+ fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
if(power_band & 0x1)
power_adjust >>= 8;
else
fee_write(ioaddr, 0x60,
dac, 2);
- /* We now should verify here that the writing of the EEPROM was OK. */
+ /* We now should verify here that the writing of the EEPROM went OK. */
/* Reread the first area. */
- fee_read(ioaddr, 0x00,
- area_verify, 16);
+ fee_read(ioaddr, 0x00, area_verify, 16);
/* Reread the DAC. */
- fee_read(ioaddr, 0x60,
- dac_verify, 2);
+ fee_read(ioaddr, 0x60, dac_verify, 2);
/* Compare. */
if(memcmp(area, area_verify, 16 * 2) ||
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
fee_wait(ioaddr, 100, 100);
/* We must now download the power adjust value (gain) to
- * the synthesizers (from the EEPROM - area 7 - DAC) */
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait until the download is finished */
+ /* Wait for the download to finish. */
fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_IOCTL_INFO
/*------------------------------------------------------------------*/
/*
- * Give the list of available frequencies
+ * Give the list of available frequencies.
*/
static inline int
-wv_frequency_list(u_long ioaddr, /* i/o port of the card */
- iw_freq * list, /* List of frequency to fill */
+wv_frequency_list(u_long ioaddr, /* I/O port of the card */
+ iw_freq * list, /* List of frequencies to fill */
int max) /* Maximum number of frequencies */
{
u_short table[10]; /* Authorized frequency table */
long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */
int i; /* index in the table */
- /* Read the frequency table */
- fee_read(ioaddr, 0x71 /* frequency table */,
- table, 10);
+ /* Read the frequency table. */
+ fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
- /* Check all frequencies */
+ /* Check all frequencies. */
i = 0;
for(freq = 0; freq < 150; freq++)
/* Look in the table if the frequency is allowed */
/*------------------------------------------------------------------*/
/*
- * Perform ioctl: configuration and information
- * This is here that are treated the wireless extensions (iwconfig)
+ * Perform ioctl for configuration and information.
+ * It is here that the wireless extensions are treated (iwconfig).
*/
static int
wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif
- /* Disable interrupts & save flags */
+ /* Disable interrupts and save flags. */
x = wv_splhi();
/* Look what is the request */
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
- strcpy(wrq->u.name, "Wavelan");
+ strcpy(wrq->u.name, "WaveLAN");
break;
case SIOCSIWNWID:
/* Set NWID in WaveLAN. */
if(wrq->u.nwid.on)
{
- /* Set NWID in psa */
+ /* Set NWID in psa. */
psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
psa.psa_nwid_select = 0x01;
psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
- /* Set NWID in mmc */
+ /* Set NWID in mmc. */
m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
{
unsigned short freq;
- /* Ask the EEPROM to read the frequency from the first area */
- fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
- &freq, 1);
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
}
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
};
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(priv));
if(ret)
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n");
+ printk(KERN_DEBUG "SetSpy: set of new addresses is: \n");
for(i = 0; i < wrq->u.data.length; i++)
printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
#ifdef HISTOGRAM
case SIOCSIPHISTO:
- /* Verif if the user is root */
+ /* Verify that the user is root. */
if(!suser())
return -EPERM;
u_char stats[3]; /* signal level, noise level, signal quality */
/* Read signal level, silence level and signal quality bytes. */
- /* Note: in the PCMCIA hardware, these are part of the frame. It seems
+ /* Note: in the PCMCIA hardware, these are part of the frame. It seems
* that for the ISA hardware, it's nowhere to be found in the frame,
* so I'm obliged to do this (it has a side effect on /proc/net/wireless).
- * Any ideas? */
+ * Any ideas?
+ */
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
* The principle:
* Each block contains a transmit command, a NOP command,
* a transmit block descriptor and a buffer.
- * The CU reads the transmit block which points to the tbd,
- * reads the tbd and the content of the buffer.
- * When it has finished with it, it goes to the next command
+ * The CU read the transmit block which point to the tbd,
+ * read the tbd and the content of the buffer.
+ * When it has finish with it, it goes to the next command
* which in our case is the NOP. The NOP points on itself,
- * so the CU stops here.
+ * so the CU stop here.
* When we add the next block, we modify the previous nop
* to make it point on the new tx command.
- * Simple, isn't it?
+ * Simple, isn't it ?
*
* (called in wavelan_packet_xmit())
*/
/*------------------------------------------------------------------*/
/*
* This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
- * the packet. We also prevent reentrance. Then, we call the function
+ * In this routine, we check if the harware is ready to accept
+ * the packet. We also prevent reentrance. Then we call the function
* to send the packet.
*/
static int
/* Disable encryption */
psa.psa_encryption_select = 0;
- /* Set to standard values
+ /* Set to standard values:
* 0x04 for AT,
* 0x01 for MCA,
* 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
psa.psa_conf_status |= 1;
#ifdef USE_PSA_CONFIG
- /* Write the psa */
+ /* Write the psa. */
psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 4);
psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
/* The following code starts the modem of the 2.00 frequency
- * selectable cards at power on. It's not strictly needed for the
+ * selectable cards at power on. It's not strictly needed for the
* following boots.
* The original patch was by Joe Finney for the PCMCIA driver, but
* I've cleaned it up a bit and added documentation.
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
- * Original copyrigth follow. See wavelan.p.h for details.
+ * Original copyright follows. See wavelan.p.h for details.
*
- * This file contain the declarations of the Wavelan hardware. Note that
- * the Wavelan ISA include a i82586 controler (see definitions in
+ * This file contains the declarations for the WaveLAN hardware. Note that
+ * the WaveLAN ISA includes a i82586 controller (see definitions in
* file i82586.h).
*
- * The main difference between the ISA hardware and the pcmcia one is
- * the Ethernet Controler (i82586 instead of i82593).
- * The i82586 allow multiple transmit buffers. The PSA need to be accessed
+ * The main difference between the ISA hardware and the PCMCIA one is
+ * the Ethernet controller (i82586 instead of i82593).
+ * The i82586 allows multiple transmit buffers. The PSA needs to be accessed
* through the host interface.
*/
#ifndef _WAVELAN_H
#define _WAVELAN_H
-/* The detection of the wavelan card is made by reading the MAC
- * address from the card and checking it. If you have a non AT&T
- * product (OEM, like DEC RoamAbout, or Digital Ocean, Epson, ...),
- * you might need to modify this part to accomodate your hardware...
+/* Detection of the WaveLAN card is done by reading the MAC
+ * address from the card and checking it. If you have a non-AT&T
+ * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
+ * you might need to modify this part to accommodate your hardware.
*/
const char MAC_ADDRESSES[][3] =
{
- { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */
- { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */
- /* Add your card here and send me the patch ! */
+ { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */
+ { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */
+ /* Add your card here and send me the patch! */
};
#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */
unsigned short hu_command; /* Command register */
#define HACR_RESET 0x0001 /* Reset board */
#define HACR_CA 0x0002 /* Set Channel Attention for 82586 */
-#define HACR_16BITS 0x0004 /* 16 bits operation (0 => 8bits) */
+#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */
#define HACR_OUT0 0x0008 /* General purpose output pin 0 */
/* not used - must be 1 */
#define HACR_OUT1 0x0010 /* General purpose output pin 1 */
/************************** MEMORY LAYOUT **************************/
/*
- * Onboard 64k RAM layout.
+ * Onboard 64 k RAM layout.
* (Offsets from 0x0000.)
*/
-#define OFFSET_RU 0x0000 /* 75 % memory */
-#define OFFSET_CU 0xC000 /* 25 % memory */
+#define OFFSET_RU 0x0000 /* 75% memory */
+#define OFFSET_CU 0xC000 /* 25% memory */
#define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t))
#define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t))
#define OFFSET_SCP I82586_SCP_ADDR
unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */
#define PSA_UNIVERSAL 0 /* Universal (factory) */
#define PSA_LOCAL 1 /* Local */
- unsigned char psa_comp_number; /* [0x1D] Compatability Number: */
-#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */
-#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */
-#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */
-#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */
+ unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */
+#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */
+#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */
+#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */
+#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */
#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */
unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */
unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */
#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */
- unsigned char psa_subband; /* [0x20] Subband */
+ unsigned char psa_subband; /* [0x20] Subband */
#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */
-#define PSA_SUBBAND_2425 1 /* 2425 MHz */
-#define PSA_SUBBAND_2460 2 /* 2460 MHz */
-#define PSA_SUBBAND_2484 3 /* 2484 MHz */
-#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */
+#define PSA_SUBBAND_2425 1 /* 2425 MHz */
+#define PSA_SUBBAND_2460 2 /* 2460 MHz */
+#define PSA_SUBBAND_2484 3 /* 2484 MHz */
+#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */
unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */
- unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */
+ unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */
unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */
- unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */
- unsigned char psa_encryption_select; /* [0x26] Encryption On Off */
+ unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */
+ unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */
unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */
unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */
unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */
#define PSA_SIZE 64
-/* Calculate offset of a field in the above structure
- * Warning : only even addresses are used */
+/* Calculate offset of a field in the above structure.
+ * Warning: only even addresses are used. */
#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
/******************** MODEM MANAGEMENT INTERFACE ********************/
struct mmw_t
{
unsigned char mmw_encr_key[8]; /* encryption key */
- unsigned char mmw_encr_enable; /* enable/disable encryption */
-#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */
-#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */
+ unsigned char mmw_encr_enable; /* Enable or disable encryption. */
+#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */
+#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */
unsigned char mmw_unused0[1]; /* unused */
- unsigned char mmw_des_io_invert; /* Encryption option */
-#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */
-#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */
+ unsigned char mmw_des_io_invert; /* encryption option */
+#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */
+#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */
unsigned char mmw_unused1[5]; /* unused */
unsigned char mmw_loopt_sel; /* looptest selection */
-#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */
-#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */
-#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */
+#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */
+#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */
+#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */
#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */
#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */
#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */
#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */
unsigned char mmw_jabber_enable; /* jabber timer enable */
/* Abort transmissions > 200 ms */
- unsigned char mmw_freeze; /* freeze / unfreeeze signal level */
+ unsigned char mmw_freeze; /* freeze or unfreeze signal level */
/* 0 : signal level & qual updated for every new message, 1 : frozen */
unsigned char mmw_anten_sel; /* antenna selection */
#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */
unsigned char mmw_thr_pre_set; /* level threshold preset */
/* Discard all packet with signal < this value (4) */
unsigned char mmw_decay_prm; /* decay parameters */
- unsigned char mmw_decay_updat_prm; /* decay update parameterz */
+ unsigned char mmw_decay_updat_prm; /* decay update parameters */
unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */
/* Discard all packet with quality < this value (3) */
unsigned char mmw_netw_id_l; /* NWID low order byte */
/* 2.0 Hardware extension - frequency selection support */
unsigned char mmw_mode_select; /* for analog tests (set to 0) */
unsigned char mmw_unused3[1]; /* unused */
- unsigned char mmw_fee_ctrl; /* frequency eeprom control */
-#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */
-#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */
-#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */
+ unsigned char mmw_fee_ctrl; /* frequency EEPROM control */
+#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */
+#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */
+#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */
#define MMW_FEE_CTRL_READ 0x06 /* Read */
#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */
-#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */
-#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */
+#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */
+#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */
#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */
#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */
#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */
-#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */
-#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */
+#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */
+#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */
#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */
- /* Never issue this command (PRDS) : it's irreversible !!! */
+ /* Never issue the PRDS command: it's irreversible! */
- unsigned char mmw_fee_addr; /* EEprom address */
-#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */
+ unsigned char mmw_fee_addr; /* EEPROM address */
+#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */
#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */
#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */
#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */
#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */
#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */
- unsigned char mmw_fee_data_l; /* Write data to EEprom */
+ unsigned char mmw_fee_data_l; /* Write data to EEPROM. */
unsigned char mmw_fee_data_h; /* high octet */
unsigned char mmw_ext_ant; /* Setting for external antenna */
#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */
#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */
#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */
#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */
- unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */
+ unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */
unsigned char mmr_unused2[2]; /* unused */
- unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */
- unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */
- /* Warning : Read high order octet first !!! */
- unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */
- unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */
+ unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */
+ unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */
+ /* Warning: read high-order octet first! */
+ unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */
+ unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */
unsigned char mmr_thr_pre_set; /* level threshold preset */
#define MMR_THR_PRE_SET 0x3F /* level threshold preset */
#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */
unsigned char mmr_sgnl_qual; /* signal quality */
#define MMR_SGNL_QUAL 0x0F /* signal quality */
#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */
- unsigned char mmr_netw_id_l; /* NWID low order byte ??? */
+ unsigned char mmr_netw_id_l; /* NWID low order byte (?) */
unsigned char mmr_unused3[3]; /* unused */
/* 2.0 Hardware extension - frequency selection support */
- unsigned char mmr_fee_status; /* Status of frequency eeprom */
-#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */
+ unsigned char mmr_fee_status; /* Status of frequency EEPROM */
+#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */
#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */
-#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */
+#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */
unsigned char mmr_unused4[1]; /* unused */
- unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */
- unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */
+ unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */
+ unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */
};
#define MMR_SIZE 36
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
*
- * This file contain all definition and declarations necessary for the
- * wavelan isa driver. This file is a private header, so it should
- * be included only on wavelan.c !!!
+ * This file contains all definitions and declarations necessary for the
+ * WaveLAN ISA driver. This file is a private header, so it should
+ * be included only in wavelan.c!
*/
#ifndef WAVELAN_P_H
#define WAVELAN_P_H
-/************************** DOCUMENTATION **************************/
+/************************** DOCUMENTATION ***************************/
/*
- * This driver provide a Linux interface to the Wavelan ISA hardware
- * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/").
+ * This driver provides a Linux interface to the WaveLAN ISA hardware.
+ * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
* This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and
- * Aironet (Arlan). If you have one of those product, you will need to
- * make some changes below...
+ * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and
+ * Aironet (Arlan). If you have one of those products, you will need to
+ * make some changes below.
*
- * This driver is still a beta software. A lot of bugs have been corrected,
- * a lot of functionalities are implemented, the whole appear pretty stable,
- * but there is still some area of improvement (encryption, performance...).
+ * This driver is still beta software. A lot of bugs have been corrected,
+ * a lot of functionality is implemented, and the whole appears stable,
+ * but there is still room for improvement (encryption, performance).
*
- * To know how to use this driver, read the NET3 HOWTO.
- * If you want to exploit the many other fonctionalities, look comments
- * in the code...
+ * To learn how to use this driver, read the NET3 HOWTO.
+ * If you want to exploit the many other functionalities, read the comments
+ * in the code.
*
- * This driver is the result of the effort of many peoples (see below).
+ * This driver is the result of the effort of many people (see below).
*/
/* ------------------------ SPECIFIC NOTES ------------------------ */
/*
- * wavelan.o is darn too big
- * -------------------------
- * That's true ! There is a very simple way to reduce the driver
- * object by 33% (yes !). Comment out the following line :
+ * wavelan.o is too darned big
+ * ---------------------------
+ * That's true! There is a very simple way to reduce the driver
+ * object by 33%! Comment out the following line:
* #include <linux/wireless.h>
*
- * MAC address and hardware detection :
- * ----------------------------------
- * The detection code of the wavelan chech that the first 3
- * octets of the MAC address fit the company code. This type of
- * detection work well for AT&T cards (because the AT&T code is
+ * MAC address and hardware detection:
+ * -----------------------------------
+ * The detection code for the WaveLAN checks that the first three
+ * octets of the MAC address fit the company code. This type of
+ * detection works well for AT&T cards (because the AT&T code is
* hardcoded in wavelan.h), but of course will fail for other
- * manufacturer.
+ * manufacturers.
*
- * If you are sure that your card is derived from the wavelan,
- * here is the way to configure it :
+ * If you are sure that your card is derived from the WaveLAN,
+ * here is the way to configure it:
* 1) Get your MAC address
- * a) With your card utilities (wfreqsel, instconf, ...)
- * b) With the driver :
+ * a) With your card utilities (wfreqsel, instconf, etc.)
+ * b) With the driver:
* o compile the kernel with DEBUG_CONFIG_INFO enabled
* o Boot and look the card messages
* 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- * 3) Compile & verify
- * 4) Send me the MAC code - I will include it in the next version...
+ * 3) Compile and verify
+ * 4) Send me the MAC code. I will include it in the next version.
*
- * "CU Inactive" message at boot up :
+ * "CU Inactive" message at boot up:
* -----------------------------------
- * It seem that there is some weird timings problems with the
- * Intel microcontroler. In fact, this message is triggered by a
- * bad reading of the on board ram the first time we read the
- * control block. If you ignore this message, all is ok (but in
- * fact, currently, it reset the wavelan hardware).
+ * It seems that there is some weird timing problem with the
+ * Intel microcontroller. In fact, this message is triggered by a
+ * bad reading of the onboard RAM the first time we read the
+ * control block. If you ignore this message, all is OK (but in
+ * fact, currently, it resets the WaveLAN hardware).
*
- * To get rid of that problem, there is two solution. The first
+ * There are two ways to get rid of that problem. The first
* is to add a dummy read of the scb at the end of
- * wv_82586_config. The second is to add the timers
+ * wv_82586_config. The second is to add the timers
* wv_synchronous_cmd and wv_ack (the udelay just after the
- * waiting loops - seem that the controler is not totally ready
- * when it say it is !).
+ * waiting loops--it seems that the controller is not totally ready
+ * when it says it is).
*
* In the current code, I use the second solution (to be
* consistent with the original solution of Bruce Janson).
/* --------------------- WIRELESS EXTENSIONS --------------------- */
/*
- * This driver is the first one to support "wireless extensions".
- * This set of extensions provide you some way to control the wireless
- * caracteristics of the hardware in a standard way and support for
- * applications for taking advantage of it (like Mobile IP).
+ * This driver is the first to support "wireless extensions".
+ * This set of extensions provides a standard way to control the wireless
+ * characteristics of the hardware. Applications such as mobile IP may
+ * take advantage of it.
*
* You will need to enable the CONFIG_NET_RADIO define in the kernel
* configuration to enable the wireless extensions (this is the one
/* ---------------------------- FILES ---------------------------- */
/*
- * wavelan.c : The actual code for the driver - C functions
+ * wavelan.c: actual code for the driver: C functions
*
- * wavelan.p.h : Private header : local types / vars for the driver
+ * wavelan.p.h: private header: local types and variables for driver
*
- * wavelan.h : Description of the hardware interface & structs
+ * wavelan.h: description of the hardware interface and structs
*
- * i82586.h : Description if the Ethernet controler
+ * i82586.h: description of the Ethernet controller
*/
/* --------------------------- HISTORY --------------------------- */
/*
- * (Made with information in drivers headers. It may not be accurate,
- * and I garantee nothing except my best effort...)
+ * This is based on information in the drivers' headers. It may not be
+ * accurate, and I guarantee only my best effort.
*
- * The history of the Wavelan drivers is as complicated as history of
- * the Wavelan itself (NCR -> AT&T -> Lucent).
+ * The history of the WaveLAN drivers is as complicated as the history of
+ * the WaveLAN itself (NCR -> AT&T -> Lucent).
*
- * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * It all started with Anders Klemets <klemets@paul.rutgers.edu>
+ * writing a WaveLAN ISA driver for the Mach microkernel. Girish
* Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modify this for the Pcmcia hardware.
+ * Keith Moore modified this for the PCMCIA hardware.
*
- * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
- * and add specific Pcmcia support (there is currently no equivalent
- * of the PCMCIA package under BSD...).
+ * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
+ * and added specific PCMCIA support (there is currently no equivalent
+ * of the PCMCIA package under BSD).
*
- * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to freeBSD.
+ * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
*
- * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
*
- * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
* (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
* Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * 2.00 cards correctly (2.4 GHz with frequency selection).
* David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
- * Pcmcia package (+ bug corrections).
+ * PCMCIA package (and bug corrections).
*
* I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * patches to the PCMCIA driver. Later, I added code in the ISA driver
* for Wireless Extensions and full support of frequency selection
- * cards. Then, I've done the same to the Pcmcia driver + some
- * reorganisation. Finally, I came back to the ISA driver to
- * upgrade it at the same level as the Pcmcia one and reorganise
- * the code
+ * cards. Then, I did the same to the PCMCIA driver, and did some
+ * reorganisation. Finally, I came back to the ISA driver to
+ * upgrade it at the same level as the PCMCIA one and reorganise
+ * the code.
* Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed informations on the Wavelan hardware.
+ * much needed information on the WaveLAN hardware.
*/
-/* The original copyrights and litteratures mention others names and
- * credits. I don't know what there part in this development was...
+/* The original copyrights and literature mention others' names and
+ * credits. I don't know what their part in this development was.
*/
-/* By the way : for the copyright & legal stuff :
- * Almost everybody wrote code under GNU or BSD license (or alike),
- * and want that their original copyright remain somewhere in the
+/* By the way, for the copyright and legal stuff:
+ * almost everybody wrote code under the GNU or BSD license (or similar),
+ * and want their original copyright to remain somewhere in the
* code (for myself, I go with the GPL).
- * Nobody want to take responsibility for anything, except the fame...
+ * Nobody wants to take responsibility for anything, except the fame.
*/
/* --------------------------- CREDITS --------------------------- */
* Linux operating system.
* It is based on other device drivers and information
* either written or supplied by:
- * Ajay Bakre (bakre@paul.rutgers.edu),
- * Donald Becker (becker@cesdis.gsfc.nasa.gov),
- * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ * Ajay Bakre <bakre@paul.rutgers.edu>,
+ * Donald Becker <becker@cesdis.gsfc.nasa.gov>,
+ * Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
* Brent Elphick <belphick@uwaterloo.ca>,
- * Anders Klemets (klemets@it.kth.se),
- * Vladimir V. Kolpakov (w@stier.koenig.ru),
- * Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
- * Pauline Middelink (middelin@polyware.iaf.nl),
- * Robert Morris (rtm@das.harvard.edu),
- * Jean Tourrilhes (jt@hplb.hpl.hp.com),
- * Girish Welling (welling@paul.rutgers.edu),
+ * Anders Klemets <klemets@it.kth.se>,
+ * Vladimir V. Kolpakov <w@stier.koenig.ru>,
+ * Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
+ * Pauline Middelink <middelin@polyware.iaf.nl>,
+ * Robert Morris <rtm@das.harvard.edu>,
+ * Jean Tourrilhes <jt@hplb.hpl.hp.com>,
+ * Girish Welling <welling@paul.rutgers.edu>,
* Clark Woodworth <clark@hiway1.exit109.com>
- * Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ * Yongguang Zhang <ygz@isl.hrl.hac.com>
*
* Thanks go also to:
- * James Ashton (jaa101@syseng.anu.edu.au),
- * Alan Cox (iialan@iiit.swan.ac.uk),
- * Allan Creighton (allanc@cs.usyd.edu.au),
- * Matthew Geier (matthew@cs.usyd.edu.au),
- * Remo di Giovanni (remo@cs.usyd.edu.au),
- * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
- * Vipul Gupta (vgupta@cs.binghamton.edu),
- * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- * Tim Nicholson (tim@cs.usyd.edu.au),
- * Ian Parkin (ian@cs.usyd.edu.au),
- * John Rosenberg (johnr@cs.usyd.edu.au),
- * George Rossi (george@phm.gov.au),
- * Arthur Scott (arthur@cs.usyd.edu.au),
+ * James Ashton <jaa101@syseng.anu.edu.au>,
+ * Alan Cox <iialan@iiit.swan.ac.uk>,
+ * Allan Creighton <allanc@cs.usyd.edu.au>,
+ * Matthew Geier <matthew@cs.usyd.edu.au>,
+ * Remo di Giovanni <remo@cs.usyd.edu.au>,
+ * Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
+ * Vipul Gupta <vgupta@cs.binghamton.edu>,
+ * Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
+ * Tim Nicholson <tim@cs.usyd.edu.au>,
+ * Ian Parkin <ian@cs.usyd.edu.au>,
+ * John Rosenberg <johnr@cs.usyd.edu.au>,
+ * George Rossi <george@phm.gov.au>,
+ * Arthur Scott <arthur@cs.usyd.edu.au>,
* Stanislav Sinyagin <stas@isf.ru>
- * Peter Storey,
- * for their assistance and advice.
+ * and Peter Storey for their assistance and advice.
*
* Additional Credits:
*
- * My developpement has been done under Linux 2.0.x (Debian 1.1) with
+ * My development has been done under Linux 2.0.x (Debian 1.1) with
* an HP Vectra XP/60.
*
*/
/* ------------------------- IMPROVEMENTS ------------------------- */
/*
- * I proudly present :
+ * I proudly present:
*
- * Changes mades in first pre-release :
+ * Changes made in first pre-release:
* ----------------------------------
- * - Reorganisation of the code, function name change
- * - Creation of private header (wavelan.p.h)
- * - Reorganised debug messages
- * - More comments, history, ...
- * - mmc_init : configure the PSA if not done
- * - mmc_init : correct default value of level threshold for pcmcia
- * - mmc_init : 2.00 detection better code for 2.00 init
+ * - reorganisation of the code, function name change
+ * - creation of private header (wavelan.p.h)
+ * - reorganised debug messages
+ * - more comments, history, etc.
+ * - mmc_init: configure the PSA if not done
+ * - mmc_init: correct default value of level threshold for PCMCIA
+ * - mmc_init: 2.00 detection better code for 2.00 initialization
* - better info at startup
- * - irq setting (note : this setting is permanent...)
- * - Watchdog : change strategy (+ solve module removal problems)
- * - add wireless extensions (ioctl & get_wireless_stats)
+ * - IRQ setting (note: this setting is permanent)
+ * - watchdog: change strategy (and solve module removal problems)
+ * - add wireless extensions (ioctl and get_wireless_stats)
* get/set nwid/frequency on fly, info for /proc/net/wireless
- * - More wireless extension : SETSPY and GETSPY
- * - Make wireless extensions optional
- * - Private ioctl to set/get quality & level threshold, histogram
- * - Remove /proc/net/wavelan
- * - Supress useless stuff from lp (net_local)
+ * - more wireless extensions: SETSPY and GETSPY
+ * - make wireless extensions optional
+ * - private ioctl to set/get quality and level threshold, histogram
+ * - remove /proc/net/wavelan
+ * - suppress useless stuff from lp (net_local)
* - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- * - Add message level (debug stuff in /var/adm/debug & errors not
+ * - add message level (debug stuff in /var/adm/debug and errors not
* displayed at console and still in /var/adm/messages)
* - multi device support
- * - Start fixing the probe (init code)
- * - More inlines
+ * - start fixing the probe (init code)
+ * - more inlines
* - man page
- * - Lot of others minor details & cleanups
- *
- * Changes made in second pre-release :
- * ----------------------------------
- * - Cleanup init code (probe & module init)
- * - Better multi device support (module)
- * - name assignement (module)
+ * - many other minor details and cleanups
*
- * Changes made in third pre-release :
- * ---------------------------------
- * - Be more conservative on timers
- * - Preliminary support for multicast (I still lack some details...)
+ * Changes made in second pre-release:
+ * -----------------------------------
+ * - clean up init code (probe and module init)
+ * - better multiple device support (module)
+ * - name assignment (module)
*
- * Changes made in fourth pre-release :
+ * Changes made in third pre-release:
* ----------------------------------
+ * - be more conservative on timers
+ * - preliminary support for multicast (I still lack some details)
+ *
+ * Changes made in fourth pre-release:
+ * -----------------------------------
* - multicast (revisited and finished)
- * - Avoid reset in set_multicast_list (a really big hack)
- * if somebody could apply this code for other i82586 based driver...
- * - Share on board memory 75% RU / 25% CU (instead of 50/50)
+ * - avoid reset in set_multicast_list (a really big hack)
+ * if somebody could apply this code for other i82586 based drivers
+ * - share onboard memory 75% RU and 25% CU (instead of 50/50)
*
- * Changes made for release in 2.1.15 :
- * ----------------------------------
- * - Change the detection code for multi manufacturer code support
+ * Changes made for release in 2.1.15:
+ * -----------------------------------
+ * - change the detection code for multi manufacturer code support
*
- * Changes made for release in 2.1.17 :
- * ----------------------------------
- * - Update to wireless extensions changes
- * - Silly bug in card initial configuration (psa_conf_status)
- *
- * Changes made for release in 2.1.27 & 2.0.30 :
- * -------------------------------------------
- * - Small bug in debug code (probably not the last one...)
- * - Remove extern kerword for wavelan_probe()
- * - Level threshold is now a standard wireless extension (version 4 !)
+ * Changes made for release in 2.1.17:
+ * -----------------------------------
+ * - update to wireless extensions changes
+ * - silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made for release in 2.1.27 & 2.0.30:
+ * --------------------------------------------
+ * - small bug in debug code (probably not the last one...)
+ * - remove extern keyword for wavelan_probe()
+ * - level threshold is now a standard wireless extension (version 4 !)
* - modules parameters types (new module interface)
*
- * Changes made for release in 2.1.36 :
- * ----------------------------------
+ * Changes made for release in 2.1.36:
+ * -----------------------------------
* - byte count stats (courtesy of David Hinds)
- * - Remove dev_tint stuff (courtesy of David Hinds)
- * - Encryption setting from Brent Elphick (thanks a lot !)
+ * - remove dev_tint stuff (courtesy of David Hinds)
+ * - encryption setting from Brent Elphick (thanks a lot!)
* - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
*
- * Wishes & dreams :
- * ---------------
- * - Roaming
+ * Wishes & dreams:
+ * ----------------
+ * - roaming
*/
/***************************** INCLUDES *****************************/
#include <linux/wireless.h> /* Wireless extensions */
-/* Wavelan declarations */
+/* WaveLAN declarations */
#include "i82586.h"
#include "wavelan.h"
/****************************** DEBUG ******************************/
-#undef DEBUG_MODULE_TRACE /* Module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */
-#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */
+#undef DEBUG_MODULE_TRACE /* module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE /* calls to handler */
+#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */
#define DEBUG_INTERRUPT_ERROR /* problems */
-#undef DEBUG_CONFIG_TRACE /* Trace the config functions */
-#undef DEBUG_CONFIG_INFO /* What's going on... */
-#define DEBUG_CONFIG_ERRORS /* Errors on configuration */
-#undef DEBUG_TX_TRACE /* Transmission calls */
-#undef DEBUG_TX_INFO /* Header of the transmited packet */
+#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */
+#undef DEBUG_CONFIG_INFO /* what's going on */
+#define DEBUG_CONFIG_ERRORS /* errors on configuration */
+#undef DEBUG_TX_TRACE /* transmission calls */
+#undef DEBUG_TX_INFO /* header of the transmitted packet */
#define DEBUG_TX_ERROR /* unexpected conditions */
-#undef DEBUG_RX_TRACE /* Transmission calls */
-#undef DEBUG_RX_INFO /* Header of the transmited packet */
+#undef DEBUG_RX_TRACE /* transmission calls */
+#undef DEBUG_RX_INFO /* header of the transmitted packet */
#define DEBUG_RX_ERROR /* unexpected conditions */
-#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen */
-#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */
-#undef DEBUG_IOCTL_INFO /* Various debug info */
-#define DEBUG_IOCTL_ERROR /* What's going wrong */
-#define DEBUG_BASIC_SHOW /* Show basic startup info */
-#undef DEBUG_VERSION_SHOW /* Print version info */
-#undef DEBUG_PSA_SHOW /* Dump psa to screen */
-#undef DEBUG_MMC_SHOW /* Dump mmc to screen */
-#undef DEBUG_SHOW_UNUSED /* Show also unused fields */
-#undef DEBUG_I82586_SHOW /* Show i82586 status */
-#undef DEBUG_DEVICE_SHOW /* Show device parameters */
-
-/* Options : */
-#define USE_PSA_CONFIG /* Use info from the PSA */
-#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions */
-#undef STRUCT_CHECK /* Verify padding of structures */
-#undef PSA_CRC /* Check CRC in PSA */
-#undef OLDIES /* Old code (to redo) */
-#undef RECORD_SNR /* To redo */
-#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */
-#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */
-
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY /* Enable spying addresses */
-#undef HISTOGRAM /* Enable histogram of sig level... */
+#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen. */
+#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */
+#undef DEBUG_IOCTL_INFO /* various debugging info */
+#define DEBUG_IOCTL_ERROR /* what's going wrong */
+#define DEBUG_BASIC_SHOW /* Show basic startup info. */
+#undef DEBUG_VERSION_SHOW /* Print version info. */
+#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */
+#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */
+#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */
+#undef DEBUG_I82586_SHOW /* Show i82586 status. */
+#undef DEBUG_DEVICE_SHOW /* Show device parameters. */
+
+/* Options */
+#define USE_PSA_CONFIG /* Use info from the PSA. */
+#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions. */
+#undef STRUCT_CHECK /* Verify padding of structures. */
+#undef PSA_CRC /* Check CRC in PSA. */
+#undef OLDIES /* old code (to redo) */
+#undef RECORD_SNR /* to redo */
+#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */
+#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */
+
+#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */
+/* Warning: this stuff will slow down the driver. */
+#define WIRELESS_SPY /* Enable spying addresses. */
+#undef HISTOGRAM /* Enable histogram of signal level. */
#endif
/************************ CONSTANTS & MACROS ************************/
#endif
/* Watchdog temporisation */
-#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */
+#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */
/* Macro to get the number of elements in an array */
#define NELS(a) (sizeof(a) / sizeof(a[0]))
/*
* Static specific data for the interface.
*
- * For each network interface, Linux keep data in two structure. "device"
- * keep the generic data (same format for everybody) and "net_local" keep
- * the additional specific data.
+ * For each network interface, Linux keeps data in two structures: "device"
+ * keeps the generic data (same format for everybody) and "net_local" keeps
+ * additional specific data.
* Note that some of this specific data is in fact generic (en_stats, for
* example).
*/
struct net_local
{
- net_local * next; /* Linked list of the devices */
- device * dev; /* Reverse link... */
+ net_local * next; /* linked list of the devices */
+ device * dev; /* reverse link */
en_stats stats; /* Ethernet interface statistics */
- int nresets; /* Number of hw resets */
- u_char reconfig_82586; /* Need to reconfigure the controler */
- u_char promiscuous; /* Promiscuous mode */
- int mc_count; /* Number of multicast addresses */
- timer_list watchdog; /* To avoid blocking state */
- u_short hacr; /* Current host interface state */
+ int nresets; /* number of hardware resets */
+ u_char reconfig_82586; /* We need to reconfigure the controller. */
+ u_char promiscuous; /* promiscuous mode */
+ int mc_count; /* number of multicast addresses */
+ timer_list watchdog; /* to avoid blocking state */
+ u_short hacr; /* current host interface state */
int tx_n_in_use;
u_short rx_head;
u_short tx_first_in_use;
#ifdef WIRELESS_EXT
- iw_stats wstats; /* Wireless specific stats */
+ iw_stats wstats; /* Wireless-specific statistics */
#endif
#ifdef WIRELESS_SPY
- int spy_number; /* Number of addresses to spy */
- mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */
- iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */
+ int spy_number; /* number of addresses to spy */
+ mac_addr spy_address[IW_MAX_SPY]; /* the addresses to spy */
+ iw_qual spy_stat[IW_MAX_SPY]; /* statistics gathered */
#endif /* WIRELESS_SPY */
+
#ifdef HISTOGRAM
- int his_number; /* Number of intervals */
- u_char his_range[16]; /* Boundaries of interval ]n-1; n] */
- u_long his_sum[16]; /* Sum in interval */
+ int his_number; /* number of intervals */
+ u_char his_range[16]; /* boundaries of interval ]n-1; n] */
+ u_long his_sum[16]; /* sum in interval */
#endif /* HISTOGRAM */
};
/**************************** PROTOTYPES ****************************/
-/* ----------------------- MISC SUBROUTINES ------------------------ */
+/* ----------------------- MISC. SUBROUTINES ------------------------ */
static inline unsigned long /* flags */
wv_splhi(void); /* Disable interrupts */
static inline void
- wv_splx(unsigned long); /* ReEnable interrupts : flags */
+ wv_splx(unsigned long); /* Enable interrupts: flags */
static u_char
wv_irq_to_psa(int);
static int
wv_psa_to_irq(u_char);
/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
static inline u_short /* data */
- hasr_read(u_long); /* Read the host interface : base address */
+ hasr_read(u_long); /* Read the host interface: base address */
static inline void
- hacr_write(u_long, /* Write to host interface : base address */
+ hacr_write(u_long, /* Write to host interface: base address */
u_short), /* data */
hacr_write_slow(u_long,
u_short),
set_chan_attn(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_hacr_reset(u_long), /* ioaddr */
wv_16_off(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_16_on(u_long, /* ioaddr */
- u_short), /* hacr */
+ u_short), /* hacr */
wv_ints_off(device *),
wv_ints_on(device *);
/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
static void
- psa_read(u_long, /* Read the Parameter Storage Area */
+ psa_read(u_long, /* Read the Parameter Storage Area. */
u_short, /* hacr */
int, /* offset in PSA */
u_char *, /* buffer to fill */
int), /* size to read */
- psa_write(u_long, /* Write to the PSA */
+ psa_write(u_long, /* Write to the PSA. */
u_short, /* hacr */
- int, /* Offset in psa */
- u_char *, /* Buffer in memory */
- int); /* Length of buffer */
+ int, /* offset in PSA */
+ u_char *, /* buffer in memory */
+ int); /* length of buffer */
static inline void
- mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */
+ mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */
u_short,
u_char),
- mmc_write(u_long, /* Write n bytes to the MMC */
+ mmc_write(u_long, /* Write n bytes to the MMC. */
u_char,
u_char *,
int);
-static inline u_char /* Read 1 byte from the MMC */
+static inline u_char /* Read 1 byte from the MMC. */
mmc_in(u_long,
u_short);
static inline void
- mmc_read(u_long, /* Read n bytes from the MMC */
+ mmc_read(u_long, /* Read n bytes from the MMC. */
u_char,
u_char *,
int),
- fee_wait(u_long, /* Wait for frequency EEprom : base address */
- int, /* Base delay to wait for */
- int); /* Number of time to wait */
+ fee_wait(u_long, /* Wait for frequency EEPROM: base address */
+ int, /* base delay to wait for */
+ int); /* time to wait */
static void
- fee_read(u_long, /* Read the frequency EEprom : base address */
+ fee_read(u_long, /* Read the frequency EEPROM: base address */
u_short, /* destination offset */
u_short *, /* data buffer */
int); /* number of registers */
wavelan_set_multicast_list(device *);
/* ----------------------- PACKET RECEPTION ----------------------- */
static inline void
- wv_packet_read(device *, /* Read a packet from a frame */
+ wv_packet_read(device *, /* Read a packet from a frame. */
u_short,
int),
- wv_receive(device *); /* Read all packets waiting */
+ wv_receive(device *); /* Read all packets waiting. */
/* --------------------- PACKET TRANSMISSION --------------------- */
static inline void
- wv_packet_write(device *, /* Write a packet to the Tx buffer */
+ wv_packet_write(device *, /* Write a packet to the Tx buffer. */
void *,
short);
static int
- wavelan_packet_xmit(struct sk_buff *, /* Send a packet */
+ wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */
device *);
/* -------------------- HARDWARE CONFIGURATION -------------------- */
static inline int
- wv_mmc_init(device *), /* Initialize the modem */
- wv_ru_start(device *), /* Start the i82586 receiver unit */
- wv_cu_start(device *), /* Start the i82586 command unit */
- wv_82586_start(device *); /* Start the i82586 */
+ wv_mmc_init(device *), /* Initialize the modem. */
+ wv_ru_start(device *), /* Start the i82586 receiver unit. */
+ wv_cu_start(device *), /* Start the i82586 command unit. */
+ wv_82586_start(device *); /* Start the i82586. */
static void
- wv_82586_config(device *); /* Configure the i82586 */
+ wv_82586_config(device *); /* Configure the i82586. */
static inline void
wv_82586_stop(device *);
static int
- wv_hw_reset(device *), /* Reset the wavelan hardware */
+ wv_hw_reset(device *), /* Reset the WaveLAN hardware. */
wv_check_ioaddr(u_long, /* ioaddr */
u_char *); /* mac address (read) */
/* ---------------------- INTERRUPT HANDLING ---------------------- */
static void
- wavelan_interrupt(int, /* Interrupt handler */
+ wavelan_interrupt(int, /* interrupt handler */
void *,
struct pt_regs *);
static void
- wavelan_watchdog(u_long); /* Transmission watchdog */
+ wavelan_watchdog(u_long); /* transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
static int
- wavelan_open(device *), /* Open the device */
- wavelan_close(device *), /* Close the device */
- wavelan_config(device *); /* Configure one device */
+ wavelan_open(device *), /* Open the device. */
+ wavelan_close(device *), /* Close the device. */
+ wavelan_config(device *); /* Configure one device. */
extern int
- wavelan_probe(device *); /* See Space.c */
+ wavelan_probe(device *); /* See Space.c. */
/**************************** VARIABLES ****************************/
/*
- * This is the root of the linked list of wavelan drivers
+ * This is the root of the linked list of WaveLAN drivers
* It is use to verify that we don't reuse the same base address
- * for two differents drivers and to make the cleanup when
- * removing the module.
+ * for two different drivers and to clean up when removing the module.
*/
static net_local * wavelan_list = (net_local *) NULL;
/*
- * This table is used to translate the psa value to irq number
- * and vice versa...
+ * This table is used to translate the PSA value to IRQ number
+ * and vice versa.
*/
static u_char irqvals[] =
{
};
/*
- * Table of the available i/o address (base address) for wavelan
+ * Table of the available I/O addresses (base addresses) for WaveLAN
*/
static unsigned short iobase[] =
{
* controllers.
* Leave out the others too -- we will always use 0x390 and leave
* 0x300 for the Ethernet device.
- * Jean II : 0x3E0 is really fine as well...
+ * Jean II: 0x3E0 is fine as well.
*/
0x300, 0x390, 0x3E0, 0x3C0
#endif /* 0 */
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ * + Added command line option (rs:[y|n]) to reverse the scan order
+ * of PCI boards. The default is rs:y, which reverses the BIOS order
+ * while registering PCI boards. The default value rs:y generates
+ * the same order of all previous revisions of this driver.
+ * Pls. note that "BIOS order" might have been reversed itself
+ * after the 2.1.9x PCI modifications in the linux kernel.
+ * The rs value is ignored when the explicit list of addresses
+ * is used by the "eata=port0,port1,..." command line option.
+ * + Added command line option (et:[y|n]) to force use of extended
+ * translation (255 heads, 63 sectors) as disk geometry.
+ * The default is et:n, which uses the disk geometry returned
+ * by scsicam_bios_param. The default value et:n is compatible with
+ * all previous revisions of this driver.
+ *
* 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
* Increased busy timeout from 10 msec. to 200 msec. while
* processing interrupts.
* PM3222 - SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
* PM3224 - SmartRAID Adapter for PCI (PM3224W is 16-bit wide SCSI)
*
+ * The above list is just an indication: as a matter of fact all DPT
+ * boards using the EATA/DMA protocol are supported by this driver,
+ * since they use exactely the same programming interface.
+ *
* The DPT PM2001 provides only the EATA/PIO interface and hence is not
* supported by this driver.
*
*
* eh:y use new scsi code (linux 2.2 only);
* eh:n use old scsi code;
+ * et:y force use of extended translation (255 heads, 63 sectors);
+ * et:n use disk geometry detected by scsicam_bios_param;
+ * rs:y reverse scan order while detecting PCI boards;
+ * rs:n use BIOS order while detecting PCI boards;
* lc:y enables linked commands;
* lc:n disables linked commands;
* tc:y enables tagged commands;
* tm:3 use only ordered queue tags;
* mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
*
- * The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- * the list of detection probes could be:
- * "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
+ * The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n".
+ * An example using the list of detection probes could be:
+ * "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n".
*
* When loading as a module, parameters can be specified as well.
* The above example would be (use 1 in place of y and 0 in place of n):
*
* modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- * max_queue_depth=4 tag_mode=0 use_new_eh_code=0
+ * max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \
+ * ext_tran=0 rev_scan=1
*
* ----------------------------------------------------------------------------
* In this implementation, linked commands are designed to work with any DISK
* When the driver detects a batch including overlapping requests
* (a really rare event) strict serial (pid) order is enforced.
* ----------------------------------------------------------------------------
+ * The extended translation option (et:y) is useful when using large physical
+ * disks/arrays. It could also be useful when switching between Adaptec boards
+ * and DPT boards without reformatting the disk.
+ * When a boot disk is partitioned with extended translation, in order to
+ * be able to boot it with a DPT board is could be necessary to add to
+ * lilo.conf additional commands as in the following example:
+ *
+ * fix-table
+ * disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
+ *
+ * where the above geometry should be replaced with the one reported at
+ * power up by the DPT controller.
+ * ----------------------------------------------------------------------------
*
* The boards are named EATA0, EATA1,... according to the detection order.
*
MODULE_PARM(max_queue_depth, "i");
MODULE_PARM(tag_mode, "i");
MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
+MODULE_PARM(rev_scan, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
#undef DEBUG_RESET
#undef DEBUG_GENERATE_ERRORS
#undef DEBUG_GENERATE_ABORTS
+#undef DEBUG_GEOMETRY
#define MAX_ISA 4
#define MAX_VESA 0
static int setup_done = FALSE;
static int link_statistics = 0;
static int tag_mode = TAG_MIXED;
+static int ext_tran = FALSE;
+static int rev_scan = TRUE;
#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
static int tagged_comm = TRUE;
if (j == 0) {
printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
- printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
- driver_name, tag_type, YESNO(linked_comm),
- max_queue_depth, YESNO(use_new_eh_code));
+ printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n",
+ driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
+ YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran));
}
printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val;
else if (!strncmp(cur, "ls:", 3)) link_statistics = val;
else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val;
+ else if (!strncmp(cur, "et:", 3)) ext_tran = val;
+ else if (!strncmp(cur, "rs:", 3)) rev_scan = val;
if ((cur = strchr(cur, ','))) ++cur;
}
if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
continue;
- /* Reverse the returned address order */
- io_port[MAX_INT_PARAM + MAX_PCI - k] =
+ /* Order addresses according to rev_scan value */
+ io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
continue;
- /* Reverse the returned address order */
- io_port[MAX_INT_PARAM + MAX_PCI - k] =
+ /* Order addresses according to rev_scan value */
+ io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
#endif /* new_eh_code */
+int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+ int size = disk->capacity;
+
+ if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+ dkinfo[0] = 255;
+ dkinfo[1] = 63;
+ dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+ }
+
+#if defined (DEBUG_GEOMETRY)
+ printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+ dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+ return FALSE;
+}
+
static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
unsigned int rev) {
unsigned int i, j, k, y;
int eata2x_old_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *);
int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
+int eata2x_biosparam(Disk *, kdev_t, int *);
-#define EATA_VERSION "4.32.00"
+#define EATA_VERSION "4.33.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
eh_device_reset_handler: NULL, \
eh_bus_reset_handler: NULL, \
eh_host_reset_handler: eata2x_reset, \
- bios_param: scsicam_bios_param, \
+ bios_param: eata2x_biosparam, \
this_id: 7, \
unchecked_isa_dma: 1, \
use_clustering: ENABLE_CLUSTERING, \
queuecommand: eata2x_queuecommand, \
abort: eata2x_old_abort, \
reset: eata2x_old_reset, \
- bios_param: scsicam_bios_param, \
+ bios_param: eata2x_biosparam, \
this_id: 7, \
unchecked_isa_dma: 1, \
use_clustering: ENABLE_CLUSTERING \
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ * Added command line option (et:[y|n]) to use the existing
+ * translation (returned by scsicam_bios_param) as disk geometry.
+ * The default is et:n, which uses the disk geometry jumpered
+ * on the board.
+ * The default value et:n is compatible with all previous revisions
+ * of this driver.
+ *
* 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
* Increased busy timeout from 10 msec. to 200 msec. while
* processing interrupts.
*
* eh:y use new scsi code (linux 2.2 only);
* eh:n use old scsi code;
+ * et:y use disk geometry returned by scsicam_bios_param;
+ * et:n use disk geometry jumpered on the board;
* lc:y enables linked commands;
* lc:n disables linked commands;
* of:y enables old firmware support;
* of:n disables old firmware support;
* mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
*
- * The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- * of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
+ * The default value is: "u14-34f=lc:n,of:n,mq:8,et:n".
+ * An example using the list of detection probes could be:
+ * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n".
*
* When loading as a module, parameters can be specified as well.
* The above example would be (use 1 in place of y and 0 in place of n):
*
* modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- * max_queue_depth=4 use_new_eh_code=0
+ * max_queue_depth=4 use_new_eh_code=0 ext_tran=0
*
* ----------------------------------------------------------------------------
* In this implementation, linked commands are designed to work with any DISK
MODULE_PARM(link_statistics, "i");
MODULE_PARM(max_queue_depth, "i");
MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
#undef DEBUG_RESET
#undef DEBUG_GENERATE_ERRORS
#undef DEBUG_GENERATE_ABORTS
+#undef DEBUG_GEOMETRY
#define MAX_ISA 3
#define MAX_VESA 1
static int do_trace = FALSE;
static int setup_done = FALSE;
static int link_statistics = 0;
+static int ext_tran = FALSE;
#if defined(HAVE_OLD_UX4F_FIRMWARE)
static int have_old_firmware = TRUE;
if (j == 0) {
printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
- printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+ printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
- max_queue_depth, YESNO(use_new_eh_code));
+ max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
}
printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val;
else if (!strncmp(cur, "ls:", 3)) link_statistics = val;
else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val;
+ else if (!strncmp(cur, "et:", 3)) ext_tran = val;
if ((cur = strchr(cur, ','))) ++cur;
}
dkinfo[0] = HD(j)->heads;
dkinfo[1] = HD(j)->sectors;
dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
+
+ if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+ dkinfo[0] = 255;
+ dkinfo[1] = 63;
+ dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+ }
+
+#if defined (DEBUG_GEOMETRY)
+ printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+ dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
return FALSE;
}
#ifndef _U14_34F_H
#define _U14_34F_H
+#include <scsi/scsicam.h>
#include <linux/version.h>
int u14_34f_detect(Scsi_Host_Template *);
int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "4.32.00"
+#define U14_34F_VERSION "4.33.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
+ tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
if [ "$CONFIG_PPC" = "y" ]; then
bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
if [ "$CONFIG_FB_OF" = "y" ]; then
-# bool 'Apple "control" display support' CONFIG_FB_CONTROL
-# bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
+ bool 'Apple "control" display support' CONFIG_FB_CONTROL
+ bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
# bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
bool 'ATI Mach64 display support' CONFIG_FB_ATY
# bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
if [ "$ARCH" = "sparc64" ]; then
bool ' Creator/Creator3D support' CONFIG_FB_CREATOR
fi
- bool ' CGsix (GX,GXplus) support' CONFIG_FB_CGSIX
+ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+ bool ' BWtwo support' CONFIG_FB_BWTWO
+ bool ' CGthree support' CONFIG_FB_CGTHREE
+ if [ "$ARCH" = "sparc" ]; then
+ bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+ fi
fi
fi
if [ "$ARCH" = "sparc64" ]; then
if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
"$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
- "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
define_bool CONFIG_FBCON_MFB y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
"$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
"$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
- "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
define_bool CONFIG_FBCON_MFB m
fi
fi
if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
"$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
"$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
- "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
define_bool CONFIG_FBCON_CFB8 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
"$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
- "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" ]; then
define_bool CONFIG_FBCON_CFB8 m
fi
fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
- "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" ]; then
+ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
define_bool CONFIG_FBCON_CFB16 y
else
if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
"$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
- "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" ]; then
+ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
define_bool CONFIG_FBCON_CFB16 m
fi
fi
- if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_CLGEN" = "y" ]; then
define_bool CONFIG_FBCON_CFB24 y
else
- if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_CLGEN" = "m" ]; then
define_bool CONFIG_FBCON_CFB24 m
fi
fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
- "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
define_bool CONFIG_FBCON_CFB32 y
else
if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
- "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
define_bool CONFIG_FBCON_CFB32 m
fi
fi
fi
fi
fi
+ bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16
- bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+ fi
bool 'Select other fonts' CONFIG_FBCON_FONTS
if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
bool ' VGA 8x8 font' CONFIG_FONT_8x8
bool ' VGA 8x16 font' CONFIG_FONT_8x16
- bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ fi
bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
fi
bool ' VGA 8x8 font' CONFIG_FONT_8x8
bool ' VGA 8x16 font' CONFIG_FONT_8x16
bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16
- bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
- bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+ bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ fi
bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
else
define_bool CONFIG_FONT_8x8 y
define_bool CONFIG_FONT_8x16 y
if [ "$CONFIG_MAC" = "y" ]; then
- define_bool CONFIG_FONT_6x11 y
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ define_bool CONFIG_FONT_6x11 y
+ fi
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
define_bool CONFIG_FONT_PEARL_8x8 y
endif
ifeq ($(CONFIG_PROM_CONSOLE),y)
- L_OBJS += promcon.o
+ L_OBJS += promcon.o promcon_tbl.o
endif
ifeq ($(CONFIG_FB),y)
L_OBJS += fonts.o
OX_OBJS += fbcon.o fbcmap.o
-# fbgen is not compiled by default since nobody uses it yet
+# fbgen is not compiled by default since nobody uses it yet, except clgenfb
ifeq ($(CONFIG_FONT_8x8),y)
L_OBJS += font_8x8.o
endif
L_OBJS += atyfb.o
endif
+ifeq ($(CONFIG_FB_CONTROL),y)
+L_OBJS += controlfb.o
+endif
+
+ifeq ($(CONFIG_FB_PLATINUM),y)
+L_OBJS += platinumfb.o
+endif
+
ifeq ($(CONFIG_FB_CT65550),y)
L_OBJS += chipsfb.o
endif
endif
endif
+ifeq ($(CONFIG_FB_CLGEN),y)
+L_OBJS += clgenfb.o
+OX_OBJS += fbgen.o
+else
+ ifeq ($(CONFIG_FB_CLGEN),m)
+ M_OBJS += clgenfb.o
+ OX_OBJS += fbgen.o
+ endif
+endif
+
ifeq ($(CONFIG_FB_S3TRIO),y)
L_OBJS += S3triofb.o
else
M_OBJS += cgsixfb.o
endif
endif
+ ifeq ($(CONFIG_FB_BWTWO),y)
+ L_OBJS += bwtwofb.o
+ else
+ ifeq ($(CONFIG_FB_BWTWO),m)
+ M_OBJS += bwtwofb.o
+ endif
+ endif
+ ifeq ($(CONFIG_FB_CGTHREE),y)
+ L_OBJS += cgthreefb.o
+ else
+ ifeq ($(CONFIG_FB_CGTHREE),m)
+ M_OBJS += cgthreefb.o
+ endif
+ endif
+ ifeq ($(CONFIG_FB_TCX),y)
+ L_OBJS += tcxfb.o
+ else
+ ifeq ($(CONFIG_FB_TCX),m)
+ M_OBJS += tcxfb.o
+ endif
+ endif
else
ifeq ($(CONFIG_FB_SBUS),m)
M_OBJS += sbusfb.o
M_OBJS += cgsixfb.o
endif
endif
+ ifeq ($(CONFIG_FB_BWTWO),y)
+ M_OBJS += bwtwofb.o
+ else
+ ifeq ($(CONFIG_FB_BWTWO),m)
+ M_OBJS += bwtwofb.o
+ endif
+ endif
+ ifeq ($(CONFIG_FB_CGTHREE),y)
+ M_OBJS += cgthreefb.o
+ else
+ ifeq ($(CONFIG_FB_CGTHREE),m)
+ M_OBJS += cgthreefb.o
+ endif
+ endif
+ ifeq ($(CONFIG_FB_TCX),y)
+ M_OBJS += tcxfb.o
+ else
+ ifeq ($(CONFIG_FB_TCX),m)
+ M_OBJS += tcxfb.o
+ endif
+ endif
endif
endif
gspcore.c: gspcore.gsp
$(GSPA) $< > $*.hex
$(GSPH2C) $*.hex > gspcore.c
+
+promcon_tbl.c: prom.uni
+ ../char/conmakehash prom.uni | \
+ sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
+ -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
+
+promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
#define ATAFB_EXT
#define ATAFB_FALCON
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
/*
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
- * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1997-1998 Geert Uytterhoeven
* Copyright (C) 1998 Bernd Harries
* Copyright (C) 1998 Eddie C. Dost
*
TODO:
- - support arbitrary video modes
-
(ecd):
- - fix initialization and allocation of resources for cursor (and disp?).
-
- fix initialization of cursor timer.
- - add code to detect ramdac type on initialization.
-
- add code to support cursor on all cards and all ramdacs.
- make cursor parameters controllable via ioctl()s.
- - handle arbitrary fonts.
-
(Anyone to help with all this?)
******************************************************************************/
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
#endif
+
#include <asm/io.h>
+
#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include "fbcon.h"
#include "fbcon-cfb8.h"
#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
#include "fbcon-cfb32.h"
-#ifndef __powerpc__
-#define eieio() /* Enforce In-order Execution of I/O */
-#endif
-
-static int currcon = 0;
-static struct display fb_disp;
-
-static char atyfb_name[16] = "ATY Mach64";
-
-struct atyfb_par {
- union {
- /* this should contain chipset specific mode information */
- struct {
- int vmode;
- int cmode;
- } gx, gt, vt;
- } hw;
- u_int vxres; /* virtual screen size */
- u_int vyres;
- int xoffset; /* virtual screen position */
- int yoffset;
- int accel;
-};
-
+#define GUI_RESERVE 0x00001000
-/*
- * Video mode values.
- * These are supposed to be the same as the values that
- * Apple uses in MacOS.
- */
-#define VMODE_NVRAM 0 /* use value stored in nvram */
-#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */
-#define VMODE_512_384_60 2 /* 512x384, 60Hz */
-#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */
-#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */
-#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */
-#define VMODE_640_480_67 6 /* 640x480, 67Hz */
-#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */
-#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */
-#define VMODE_800_600_56 9 /* 800x600, 56Hz */
-#define VMODE_800_600_60 10 /* 800x600, 60Hz */
-#define VMODE_800_600_72 11 /* 800x600, 72Hz */
-#define VMODE_800_600_75 12 /* 800x600, 75Hz */
-#define VMODE_832_624_75 13 /* 832x624, 75Hz */
-#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */
-#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */
-#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */
-#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */
-#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */
-#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */
-#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */
-#define VMODE_MAX 20
-#define VMODE_CHOOSE 99 /* choose based on monitor sense */
+#define CLASS_GX 1
+#define CLASS_CT 2
+#define CLASS_VT 3
+#define CLASS_GT 4
-/*
- * Color mode values, used to select number of bits/pixel.
- */
-#define CMODE_NVRAM -1 /* use value stored in nvram */
-#define CMODE_8 0 /* 8 bits/pixel */
-#define CMODE_16 1 /* 16 (actually 15) bits/pixel */
-#define CMODE_32 2 /* 32 (actually 24) bits/pixel */
+#ifndef __powerpc__
+#define eieio() /* Enforce In-order Execution of I/O */
+#endif
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
-/*
- * Addresses in NVRAM where video mode and pixel size are stored.
- */
-#define NV_VMODE 0x140f
-#define NV_CMODE 0x1410
-#endif /* CONFIG_PMAC || CONFIG_CHRP */
+ /*
+ * Elements of the Hardware specific atyfb_par structure
+ */
-/*
- * Horizontal and vertical resolution for each mode.
- */
-static struct vmode_attr {
- int hres;
- int vres;
- int vfreq;
- int interlaced;
-} vmode_attrs[VMODE_MAX] = {
- {512, 384, 60, 1},
- {512, 384, 60},
- {640, 480, 50, 1},
- {640, 480, 60, 1},
- {640, 480, 60},
- {640, 480, 67},
- {640, 870, 75},
- {768, 576, 50, 1},
- {800, 600, 56},
- {800, 600, 60},
- {800, 600, 72},
- {800, 600, 75},
- {832, 624, 75},
- {1024, 768, 60},
- {1024, 768, 72},
- {1024, 768, 75},
- {1024, 768, 75},
- {1152, 870, 75},
- {1280, 960, 75},
- {1280, 1024, 75}
+struct crtc {
+ u32 vxres;
+ u32 vyres;
+ u32 xoffset;
+ u32 yoffset;
+ u32 bpp;
+ u32 h_tot_disp;
+ u32 h_sync_strt_wid;
+ u32 v_tot_disp;
+ u32 v_sync_strt_wid;
+ u32 off_pitch;
+ u32 gen_cntl;
+ u32 dp_pix_width; /* acceleration */
+ u32 dp_chain_mask; /* acceleration */
};
+struct pll_gx {
+ u8 m;
+ u8 n;
+};
-/*
- * We get a sense value from the monitor and use it to choose
- * what resolution to use. This structure maps sense values
- * to display mode values (which determine the resolution and
- * frequencies).
- */
-static struct mon_map {
- int sense;
- int vmode;
-} monitor_map [] = {
- {0x000, VMODE_1280_1024_75}, /* 21" RGB */
- {0x114, VMODE_640_870_75P}, /* Portrait Monochrome */
- {0x221, VMODE_512_384_60}, /* 12" RGB*/
- {0x331, VMODE_1280_1024_75}, /* 21" RGB (Radius) */
- {0x334, VMODE_1280_1024_75}, /* 21" mono (Radius) */
- {0x335, VMODE_1280_1024_75}, /* 21" mono */
- {0x40A, VMODE_640_480_60I}, /* NTSC */
- {0x51E, VMODE_640_870_75P}, /* Portrait RGB */
- {0x603, VMODE_832_624_75}, /* 12"-16" multiscan */
- {0x60b, VMODE_1024_768_70}, /* 13"-19" multiscan */
- {0x623, VMODE_1152_870_75}, /* 13"-21" multiscan */
- {0x62b, VMODE_640_480_67}, /* 13"/14" RGB */
- {0x700, VMODE_640_480_50I}, /* PAL */
- {0x714, VMODE_640_480_60I}, /* NTSC */
- {0x717, VMODE_800_600_75}, /* VGA */
- {0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */
- {0x730, VMODE_768_576_50I}, /* PAL (Alternate) */
- {0x73a, VMODE_1152_870_75}, /* 3rd party 19" */
- {0x73f, VMODE_640_480_67}, /* no sense lines connected at all */
- {-1, VMODE_640_480_60}, /* catch-all, must be last */
+struct pll_ct {
+ u8 pll_ref_div;
+ u8 pll_gen_cntl;
+ u8 mclk_fb_div;
+ u8 pll_vclk_cntl;
+ u8 vclk_post_div;
+ u8 vclk_fb_div;
+ u8 pll_ext_cntl;
+ u32 dsp_config; /* Mach64 GTB DSP */
+ u32 dsp_on_off; /* Mach64 GTB DSP */
};
-static int map_monitor_sense(int sense)
-{
- struct mon_map *map;
- for (map = monitor_map; map->sense >= 0; ++map)
- if (map->sense == sense)
- break;
- return map->vmode;
-}
+ /*
+ * The Hardware parameters for each card
+ */
+
+struct atyfb_par {
+ struct crtc crtc;
+ union {
+ struct pll_gx gx;
+ struct pll_ct ct;
+ } pll;
+ u32 accel_flags;
+};
struct aty_cmap_regs {
u8 windex;
u8 cntl;
};
-typedef struct aty_regvals {
- u32 offset[3]; /* first pixel address */
-
- u32 crtc_h_sync_strt_wid[3]; /* depth dependent */
- u32 crtc_gen_cntl[3];
- u32 mem_cntl[3];
-
- u32 crtc_h_tot_disp; /* mode dependent */
- u32 crtc_v_tot_disp;
- u32 crtc_v_sync_strt_wid;
- u32 crtc_off_pitch;
-
- u8 clock_val[2]; /* vals for 20 and 21 */
-} aty_regvals;
-
-struct rage_regvals {
- u32 h_total, h_sync_start, h_sync_width;
- u32 v_total, v_sync_start, v_sync_width;
- u32 h_sync_neg, v_sync_neg;
-};
-
struct pci_mmap_map {
unsigned long voff;
unsigned long poff;
#define DEFAULT_CURSOR_BLINK_RATE (20)
struct aty_cursor {
- int enable;
- int on;
- int vbl_cnt;
- int blink_rate;
- u32 offset;
- struct {
- u16 x, y;
- } pos, hot, size;
- u32 color[2];
- u8 bits[8][64];
- u8 mask[8][64];
- struct timer_list *timer;
+ int enable;
+ int on;
+ int vbl_cnt;
+ int blink_rate;
+ u32 offset;
+ struct {
+ u16 x, y;
+ } pos, hot, size;
+ u32 color[2];
+ u8 bits[8][64];
+ u8 mask[8][64];
+ struct timer_list *timer;
};
struct fb_info_aty {
unsigned long ati_regbase;
unsigned long frame_buffer_phys;
unsigned long frame_buffer;
+ struct display disp;
+ struct display_switch dispsw;
struct pci_mmap_map *mmap_map;
struct aty_cursor *cursor;
- u8 chip_class;
- u8 pixclock_lim_8; /* ps, <= 8 bpp */
- u8 pixclock_lim_hi; /* ps, > 8 bpp */
- u32 total_vram;
struct aty_cmap_regs *aty_cmap_regs;
struct { u8 red, green, blue, pad; } palette[256];
struct atyfb_par default_par;
struct atyfb_par current_par;
-};
-
-#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
-#endif
-
-static int aty_vram_reqd(const struct atyfb_par *par);
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info);
-
-#include "ati-gx.h"
-#include "ati-gt.h"
-#include "ati-vt.h"
-
-static struct aty_regvals *aty_gt_reg_init[20] = {
- NULL, NULL, NULL, NULL,
- &aty_gt_reg_init_5,
- &aty_gt_reg_init_6,
- NULL, NULL,
- &aty_gt_reg_init_9,
- &aty_gt_reg_init_10,
- &aty_gt_reg_init_11,
- &aty_gt_reg_init_12,
- &aty_gt_reg_init_13,
- &aty_gt_reg_init_14,
- &aty_gt_reg_init_15,
- NULL,
- &aty_gt_reg_init_17,
- &aty_gt_reg_init_18,
- NULL,
- &aty_gt_reg_init_20
-};
-
-static struct aty_regvals *aty_gx_reg_init[20] = {
- NULL, NULL, NULL, NULL,
- &aty_gx_reg_init_6,
- &aty_gx_reg_init_6,
- NULL, NULL, NULL, NULL, NULL, NULL,
- &aty_gx_reg_init_13,
- &aty_gx_reg_init_14,
- &aty_gx_reg_init_15,
- NULL,
- &aty_gx_reg_init_17,
- &aty_gx_reg_init_18,
- NULL,
- &aty_gx_reg_init_20
-};
-
-static struct aty_regvals *aty_vt_reg_init[21] = {
- NULL, NULL, NULL, NULL,
- &aty_vt_reg_init_5,
- &aty_vt_reg_init_6,
- NULL, NULL, NULL,
- &aty_vt_reg_init_10,
- &aty_vt_reg_init_11,
- &aty_vt_reg_init_12,
- &aty_vt_reg_init_13,
- &aty_vt_reg_init_14,
- &aty_vt_reg_init_15,
- NULL,
- &aty_vt_reg_init_17,
- &aty_vt_reg_init_18,
- &aty_vt_reg_init_19,
- &aty_vt_reg_init_20
-};
-
-
-#define CLASS_GX 1
-#define CLASS_CT 2
-#define CLASS_VT 3
-#define CLASS_GT 4
-
-struct aty_features {
- u16 pci_id;
+ u32 total_vram;
+ u32 pll_per;
+ u32 mclk_per;
u16 chip_type;
- const char *name;
- u8 chip_class;
- u8 pixclock_lim_8; /* MHz, <= 8 bpp (not sure about these limits!) */
- u8 pixclock_lim_hi; /* MHz, > 8 bpp (not sure about these limits!) */
-} aty_features[] __initdata = {
- /* mach64GX family */
- { 0x4758, 0x00d7, "mach64GX (ATI888GX00)", CLASS_GX, 135, 80 },
- { 0x4358, 0x0057, "mach64CX (ATI888CX00)", CLASS_GX, 135, 80 },
-
- /* mach64CT family */
- { 0x4354, 0x4354, "mach64CT (ATI264CT)", CLASS_CT, 135, 80 },
- { 0x4554, 0x4554, "mach64ET (ATI264ET)", CLASS_CT, 135, 80 },
-
- /* mach64CT family / mach64VT class */
- { 0x5654, 0x5654, "mach64VT (ATI264VT)", CLASS_VT, 160, 135 },
- { 0x5655, 0x5655, "mach64VTB (ATI264VTB)", CLASS_VT, 160, 135 },
- { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)", CLASS_VT, 160, 135 },
-
- /* mach64CT family / mach64GT (3D RAGE) class */
- { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)", CLASS_GT, 240, 240 },
- { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)", CLASS_GT, 240, 240 },
- { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)", CLASS_GT, 240, 240 },
- { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)", CLASS_GT, 240, 240 },
- { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)", CLASS_GT, 240, 240 },
- { 0x4754, 0x4754, "3D RAGE (GT)", CLASS_GT, 200, 200 },
- { 0x4755, 0x4755, "3D RAGE II+ (GTB)", CLASS_GT, 200, 200 },
- { 0x4756, 0x4756, "3D RAGE IIC", CLASS_GT, 200, 200 },
- { 0x4c47, 0x4c47, "3D RAGE LT", CLASS_GT, 200, 200 },
+#define Gx info->chip_type
+ u8 chip_rev;
+#define Rev info->chip_rev
+ u8 bus_type;
+ u8 ram_type;
+ u8 dac_type;
+ u8 clk_type;
+ u8 mem_refresh_rate;
+#ifdef __sparc__
+ u8 open;
+ u8 mmaped;
+ int vtconsole;
+ int consolecnt;
+#endif
};
/*
- * Interface used by the world
+ * Frame buffer device API
*/
-void atyfb_init(void);
-#ifdef CONFIG_FB_OF
-void atyfb_of_init(struct device_node *dp);
-#endif
-void atyfb_setup(char *options, int *ints);
-
static int atyfb_open(struct fb_info *info, int user);
static int atyfb_release(struct fb_info *info, int user);
static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
* Interface to the low level console driver
*/
-static int atyfbcon_switch(int con, struct fb_info *info);
-static int atyfbcon_updatevar(int con, struct fb_info *info);
-static void atyfbcon_blank(int blank, struct fb_info *info);
+static int atyfbcon_switch(int con, struct fb_info *fb);
+static int atyfbcon_updatevar(int con, struct fb_info *fb);
+static void atyfbcon_blank(int blank, struct fb_info *fb);
/*
* Text console acceleration
*/
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_aty8;
+static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
#endif
#ifdef FBCON_HAS_CFB16
static struct display_switch fbcon_aty16;
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty24;
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
#endif
#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_aty32;
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
#endif
static char *strtoke(char *s, const char *ct);
#endif
+static void reset_engine(const struct fb_info_aty *info);
+static void init_engine(const struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_set_crtc(const struct fb_info_aty *info,
+ const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct crtc *crtc);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp);
+static int aty_crtc_to_var(const struct crtc *crtc,
+ struct fb_var_screeninfo *var);
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+ const struct pll_gx *pll);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll);
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+ struct fb_var_screeninfo *var);
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+ const struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+ u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+ u8 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct pll_ct *pll);
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+ struct fb_var_screeninfo *var);
+static void atyfb_set_par(const struct atyfb_par *par,
+ struct fb_info_aty *info);
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+ struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static void set_off_pitch(struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static int encode_fix(struct fb_fix_screeninfo *fix,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info);
static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
+ u_int *transp, struct fb_info *fb);
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
+ u_int transp, struct fb_info *fb);
static void do_install_cmap(int con, struct fb_info *info);
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int read_aty_sense(const struct fb_info_aty *info);
+#endif
+
+
+ /*
+ * Interface used by the world
+ */
+
+void atyfb_init(void);
+#ifdef CONFIG_FB_OF
+void atyfb_of_init(struct device_node *dp);
+#endif
+void atyfb_setup(char *options, int *ints);
+static int currcon = 0;
+
static struct fb_ops atyfb_ops = {
atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl,
#endif
};
+static char atyfb_name[16] = "ATY Mach64";
+static char fontname[40] __initdata = { 0 };
+
+static const u32 ref_clk_per = 1000000000000ULL/14318180;
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+
+static struct aty_features {
+ u16 pci_id;
+ u16 chip_type;
+ const char *name;
+} aty_features[] __initdata = {
+ /* mach64GX family */
+ { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
+ { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
+
+ /* mach64CT family */
+ { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
+ { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
+
+ /* mach64CT family / mach64VT class */
+ { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
+ { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
+/* { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */
+
+ /* mach64CT family / mach64GT (3D RAGE) class */
+ { 0x4c54, 0x4c54, "3D RAGE LT" },
+ { 0x4c47, 0x4c47, "3D RAGE LG" },
+ { 0x4754, 0x4754, "3D RAGE (GT)" },
+ { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
+/* { 0x4756, 0x4756, "3D RAGE IIC" }, */
+ { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
+ { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
+ { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
+ { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
+ { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
+};
-static inline int aty_vram_reqd(const struct atyfb_par *par)
-{
- return (par->vxres*par->vyres) << par->hw.gx.cmode;
-}
static inline u32 aty_ld_le32(volatile unsigned int regindex,
- struct fb_info_aty *info)
+ const struct fb_info_aty *info)
{
unsigned long temp;
u32 val;
-#ifdef __powerpc__
+#if defined(__powerpc__)
temp = info->ati_regbase;
- asm("lwbrx %0,%1,%2": "=r"(val):"r"(regindex), "r"(temp));
-#else
-#ifdef __sparc__v9__
+ asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+#elif defined(__sparc_v9__)
temp = info->ati_regbase + regindex;
asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
#else
temp = info->ati_regbase+regindex;
val = le32_to_cpu(*((volatile u32 *)(temp)));
-#endif
#endif
return val;
}
static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
- struct fb_info_aty *info)
+ const struct fb_info_aty *info)
{
unsigned long temp;
-#ifdef __powerpc__
+#if defined(__powerpc__)
temp = info->ati_regbase;
- asm("stwbrx %0,%1,%2": : "r"(val), "r"(regindex), "r"(temp):"memory");
-#else
-#ifdef __sparc__v9__
+ asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+ "memory");
+#elif defined(__sparc_v9__)
temp = info->ati_regbase + regindex;
- asm("stwa %0, [%1] %2" : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+ asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
#else
temp = info->ati_regbase+regindex;
*((volatile u32 *)(temp)) = cpu_to_le32(val);
#endif
-#endif
}
static inline u8 aty_ld_8(volatile unsigned int regindex,
- struct fb_info_aty *info)
+ const struct fb_info_aty *info)
{
return *(volatile u8 *)(info->ati_regbase+regindex);
}
static inline void aty_st_8(volatile unsigned int regindex, u8 val,
- struct fb_info_aty *info)
+ const struct fb_info_aty *info)
{
*(volatile u8 *)(info->ati_regbase+regindex) = val;
}
+
+ /*
+ * Generic Mach64 routines
+ */
+
/*
* All writes to draw engine registers are automatically routed through a
* 32-bit-wide, 16-entry-deep command FIFO ...
* (from Chapter 5 of the Mach64 Programmer's Guide)
*/
-static inline void wait_for_fifo(u16 entries, struct fb_info_aty *info)
+static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
{
while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
((u32)(0x8000 >> entries)));
}
-static inline void wait_for_idle(struct fb_info_aty *info)
+static inline void wait_for_idle(const struct fb_info_aty *info)
{
wait_for_fifo(16, info);
while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
}
-static void reset_engine(struct fb_info_aty *info)
+static void reset_engine(const struct fb_info_aty *info)
{
/* reset engine */
aty_st_le32(GEN_TEST_CNTL,
BUS_FIFO_ERR_ACK, info);
}
-static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
+static void init_engine(const struct atyfb_par *par,
+ const struct fb_info_aty *info)
{
u32 pitch_value;
/* determine modal information from global mode structure */
- pitch_value = par->vxres;
+ pitch_value = par->crtc.vxres;
-#if 0
- if (par->hw.gx.cmode == CMODE_24) {
+ if (par->crtc.bpp == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
/* horizontal coordinates and widths must be adjusted */
pitch_value = pitch_value * 3;
}
-#endif
/* Reset engine, enable, and clear any engine errors */
reset_engine(info);
/* set scissors to modal size */
aty_st_le32(SC_LEFT, 0, info);
aty_st_le32(SC_TOP, 0, info);
- aty_st_le32(SC_BOTTOM, par->vyres-1, info);
+ aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
aty_st_le32(SC_RIGHT, pitch_value-1, info);
/* set background color to minimum value (usually BLACK) */
/* set pixel depth */
wait_for_fifo(2, info);
- switch(par->hw.gx.cmode) {
-#ifdef FBCON_HAS_CFB8
- case CMODE_8:
- aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
- BYTE_ORDER_LSB_TO_MSB,
- info);
- aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case CMODE_16:
- aty_st_le32(DP_PIX_WIDTH, HOST_15BPP | SRC_15BPP | DST_15BPP |
- BYTE_ORDER_LSB_TO_MSB,
- info);
- aty_st_le32(DP_CHAIN_MASK, 0x4210, info);
- break;
-#endif
-#if 0
- case CMODE_24:
- aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
- BYTE_ORDER_LSB_TO_MSB,
- info);
- aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case CMODE_32:
- aty_st_le32(DP_PIX_WIDTH, HOST_32BPP | SRC_32BPP | DST_32BPP |
- BYTE_ORDER_LSB_TO_MSB, info);
- aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
- break;
-#endif
- }
+ aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
+ aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
+
/* insure engine is idle before leaving */
wait_for_idle(info);
}
-static void aty_st_514(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
{
aty_st_8(DAC_CNTL, 1, info);
/* right addr byte */
- aty_st_8(DAC_W_INDEX, offset & 0xff, info);
+ aty_st_8(DAC_W_INDEX, offset & 0xff, info);
/* left addr byte */
aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
eieio();
aty_st_8(DAC_CNTL, 0, info);
}
-static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
{
/* write addr byte */
aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
}
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info)
+#if 0 /* ecd debug */
+static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
{
- int v = vmode - 1;
+ u8 val;
- switch (info->chip_class) {
- case CLASS_GX:
- return aty_gx_reg_init[v];
- break;
- case CLASS_CT:
- case CLASS_VT:
- return aty_vt_reg_init[v];
- break;
- case CLASS_GT:
- return aty_gt_reg_init[v];
- break;
- default:
- /* should NOT happen */
- return NULL;
- }
+ /* write addr byte */
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
+ eieio();
+ /* read the register value */
+ val = aty_ld_8(CLOCK_CNTL + 2, info);
+ eieio();
+ return val;
}
+#endif /* ecd debug */
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
-static int read_aty_sense(struct fb_info_aty *info)
+ /*
+ * Apple monitor sense
+ */
+
+static int read_aty_sense(const struct fb_info_aty *info)
{
int sense, i;
return sense;
}
-static void RGB514_Program(int cmode, struct fb_info_aty *info)
-{
- typedef struct {
- u8 pixel_dly;
- u8 misc2_cntl;
- u8 pixel_rep;
- u8 pixel_cntl_index;
- u8 pixel_cntl_v1;
- } RGB514_DAC_Table;
-
- static RGB514_DAC_Table RGB514DAC_Tab[8] = {
- {0, 0x41, 0x03, 0x71, 0x45}, /* 8bpp */
- {0, 0x45, 0x04, 0x0c, 0x01}, /* 555 */
- {0, 0x45, 0x06, 0x0e, 0x00}, /* XRGB */
- };
- RGB514_DAC_Table *pDacProgTab;
-
- pDacProgTab = &RGB514DAC_Tab[cmode];
-
- aty_st_514(0x90, 0x00, info);
- aty_st_514(0x04, pDacProgTab->pixel_dly, info);
- aty_st_514(0x05, 0x00, info);
-
- aty_st_514(0x2, 0x1, info);
- aty_st_514(0x71, pDacProgTab->misc2_cntl, info);
- aty_st_514(0x0a, pDacProgTab->pixel_rep, info);
-
- aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1,
- info);
-}
-
-static void set_off_pitch(const struct atyfb_par *par,
- struct fb_info_aty *info)
-{
- u32 pitch, offset;
+#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */
- pitch = par->vxres>>3;
- offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->hw.gx.cmode;
- aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset, info);
-}
+/* ------------------------------------------------------------------------- */
-/*
- * Hardware Cursor support.
- */
+ /*
+ * Hardware Cursor support.
+ */
static u8 cursor_pixel_map[2] = { 0, 15 };
static u8 cursor_color_map[2] = { 0, 0xff };
if (!c)
return;
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
for (i = 0; i < 2; i++) {
c->color[i] = (u32)red[i] << 24;
c->color[i] |= (u32)green[i] << 16;
wait_for_fifo(2, fb);
aty_st_le32(CUR_CLR0, c->color[0], fb);
aty_st_le32(CUR_CLR1, c->color[1], fb);
- wait_for_idle(fb);
}
static void
if (!c)
return;
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
ram = (u8 *)(fb->frame_buffer + c->offset);
for (y = 0; y < c->size.y; y++) {
if (!c)
return;
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
if (c->on) {
x = c->pos.x - c->hot.x;
if (x < 0) {
aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
fb);
}
- wait_for_idle(fb);
}
static void
if (!c)
return;
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
x *= d->fontwidth;
y *= d->fontheight;
if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on)
}
-static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
-{
- int i, j = 0, hres;
- struct aty_regvals *init = get_aty_struct(par->hw.gx.vmode, info);
- int vram_type = aty_ld_le32(CONFIG_STAT0, info) & 7;
- if (init == 0) /* paranoia, shouldn't get here */
- panic("aty: display mode %d not supported", par->hw.gx.vmode);
- info->current_par = *par;
- hres = vmode_attrs[par->hw.gx.vmode-1].hres;
+/* ------------------------------------------------------------------------- */
- if (info->chip_class != CLASS_GT) {
- i = aty_ld_le32(CRTC_GEN_CNTL, info);
- aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN, info);
- }
+ /*
+ * CRTC programming
+ */
- if (info->chip_class == CLASS_GX) {
- i = aty_ld_le32(GEN_TEST_CNTL, info);
- aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN, info);
- }
+static void aty_set_crtc(const struct fb_info_aty *info,
+ const struct crtc *crtc)
+{
+ aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
+ aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
+ aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
+ aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
+ aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+ aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
+ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
+}
- switch (info->chip_class) {
- case CLASS_GX:
- RGB514_Program(par->hw.gx.cmode, info);
- wait_for_idle(info);
- aty_st_514(0x06, 0x02, info);
- aty_st_514(0x10, 0x01, info);
- aty_st_514(0x70, 0x01, info);
- aty_st_514(0x8f, 0x1f, info);
- aty_st_514(0x03, 0x00, info);
- aty_st_514(0x05, 0x00, info);
- aty_st_514(0x20, init->clock_val[0], info);
- aty_st_514(0x21, init->clock_val[1], info);
- break;
- case CLASS_CT:
- case CLASS_VT:
- aty_st_pll(VPLL_CNTL, 0xb5, info);
- aty_st_pll(PLL_REF_DIV, 0x2d, info);
- aty_st_pll(PLL_GEN_CNTL, 0x14, info);
- aty_st_pll(MCLK_FB_DIV, 0xbd, info);
- aty_st_pll(PLL_VCLK_CNTL, 0x0b, info);
- aty_st_pll(VCLK_POST_DIV, init->clock_val[0], info);
- aty_st_pll(VCLK0_FB_DIV, init->clock_val[1], info);
- aty_st_pll(VCLK1_FB_DIV, 0xd6, info);
- aty_st_pll(VCLK2_FB_DIV, 0xee, info);
- aty_st_pll(VCLK3_FB_DIV, 0xf8, info);
- aty_st_pll(PLL_EXT_CNTL, 0x0, info);
- aty_st_pll(PLL_TEST_CTRL, 0x0, info);
- aty_st_pll(PLL_TEST_COUNT, 0x0, info);
- break;
- case CLASS_GT:
- if (vram_type == 5) {
- aty_st_pll(MPLL_CNTL, 0xcd, info);
- aty_st_pll(VPLL_CNTL,
- par->hw.gx.vmode >= VMODE_1024_768_60 ? 0xd3
- : 0xd5,
- info);
- aty_st_pll(PLL_REF_DIV, 0x21, info);
- aty_st_pll(PLL_GEN_CNTL, 0x44, info);
- aty_st_pll(MCLK_FB_DIV, 0xe8, info);
- aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
- aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
- aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
- aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
- aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
- aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
- aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
- aty_st_pll(DLL_CNTL, 0xa6, info);
- aty_st_pll(VFC_CNTL, 0x1b, info);
- } else {
- aty_st_pll(VPLL_CNTL, 0xd5, info);
- aty_st_pll(PLL_REF_DIV, 0x21, info);
- aty_st_pll(PLL_GEN_CNTL, 0xc4, info);
- aty_st_pll(MCLK_FB_DIV, 0xda, info);
- aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
- /* offset actually holds clock values */
- aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
- aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
- aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
- aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
- aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
- aty_st_pll(PLL_TEST_CTRL, 0x0, info);
- aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
- aty_st_pll(DLL_CNTL, 0xa0, info);
- aty_st_pll(VFC_CNTL, 0x1b, info);
- }
- break;
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct crtc *crtc)
+{
+ u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+ u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+ u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+ u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+ u32 pix_width, dp_pix_width, dp_chain_mask;
+
+ /* input */
+ xres = var->xres;
+ yres = var->yres;
+ vxres = var->xres_virtual;
+ vyres = var->yres_virtual;
+ xoffset = var->xoffset;
+ yoffset = var->yoffset;
+ bpp = var->bits_per_pixel;
+ left = var->left_margin;
+ right = var->right_margin;
+ upper = var->upper_margin;
+ lower = var->lower_margin;
+ hslen = var->hsync_len;
+ vslen = var->vsync_len;
+ sync = var->sync;
+ vmode = var->vmode;
+
+ /* convert (and round up) and validate */
+ xres = (xres+7) & ~7;
+ xoffset = (xoffset+7) & ~7;
+ vxres = (vxres+7) & ~7;
+ if (vxres < xres+xoffset)
+ vxres = xres+xoffset;
+ h_disp = xres/8-1;
+ if (h_disp > 0xff)
+ FAIL("h_disp too large");
+ h_sync_strt = h_disp+(right/8);
+ if (h_sync_strt > 0x1ff)
+ FAIL("h_sync_start too large");
+ h_sync_dly = right & 7;
+ h_sync_wid = (hslen+7)/8;
+ if (h_sync_wid > 0x1f)
+ FAIL("h_sync_wid too large");
+ h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8;
+ if (h_total > 0x1ff)
+ FAIL("h_total too large");
+ h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+
+ if (vyres < yres+yoffset)
+ vyres = yres+yoffset;
+ v_disp = yres-1;
+ if (v_disp > 0x7ff)
+ FAIL("v_disp too large");
+ v_sync_strt = v_disp+lower;
+ if (v_sync_strt > 0x7ff)
+ FAIL("v_sync_strt too large");
+ v_sync_wid = vslen;
+ if (v_sync_wid > 0x1f)
+ FAIL("v_sync_wid too large");
+ v_total = v_sync_strt+v_sync_wid+upper;
+ if (v_total > 0x7ff)
+ FAIL("v_total too large");
+ v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+ if (bpp <= 8) {
+ bpp = 8;
+ pix_width = CRTC_PIX_WIDTH_8BPP;
+ dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = 0x8080;
+ } else if (bpp <= 16) {
+ bpp = 16;
+ pix_width = CRTC_PIX_WIDTH_15BPP;
+ dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+ BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = 0x4210;
+ } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+ bpp = 24;
+ pix_width = CRTC_PIX_WIDTH_24BPP;
+ dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = 0x8080;
+ } else if (bpp <= 32) {
+ bpp = 32;
+ pix_width = CRTC_PIX_WIDTH_32BPP;
+ dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
+ BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = 0x8080;
+ } else
+ FAIL("invalid bpp");
+
+ if (vxres*vyres*bpp/8 > info->total_vram)
+ FAIL("not enough video RAM");
+
+ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ FAIL("invalid vmode");
+
+ /* output */
+ crtc->vxres = vxres;
+ crtc->vyres = vyres;
+ crtc->xoffset = xoffset;
+ crtc->yoffset = yoffset;
+ crtc->bpp = bpp;
+ crtc->h_tot_disp = h_total | (h_disp<<16);
+ crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+ ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) |
+ (h_sync_pol<<21);
+ crtc->v_tot_disp = v_total | (v_disp<<16);
+ crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+ crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+ crtc->gen_cntl = pix_width | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
+ ((Gx == VT_CHIP_ID) && !(Rev & 0x03)) ||
+ ((Gx == GT_CHIP_ID) && !(Rev & 0x03))) {
+ /* Not VTB/GTB */
+ /* FIXME: magic FIFO values */
+ crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
}
+ crtc->dp_pix_width = dp_pix_width;
+ crtc->dp_chain_mask = dp_chain_mask;
- aty_ld_8(DAC_REGS, info); /* clear counter */
- wait_for_idle(info);
-
- aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp, info);
- aty_st_le32(CRTC_H_SYNC_STRT_WID,
- init->crtc_h_sync_strt_wid[par->hw.gx.cmode], info);
- aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp, info);
- aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid, info);
+ return 0;
+}
- aty_st_8(CLOCK_CNTL, 0, info);
- aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
-
- aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
+{
+ static struct {
+ u8 pixel_dly;
+ u8 misc2_cntl;
+ u8 pixel_rep;
+ u8 pixel_cntl_index;
+ u8 pixel_cntl_v1;
+ } tab[3] = {
+ { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */
+ { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */
+ { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */
+ };
+ int i;
- set_off_pitch(par, info);
+ switch (bpp) {
+ case 8:
+ default:
+ i = 0;
+ break;
+ case 16:
+ i = 1;
+ break;
+ case 32:
+ i = 2;
+ break;
+ }
+ aty_st_514(0x90, 0x00, info); /* VRAM Mask Low */
+ aty_st_514(0x04, tab[i].pixel_dly, info); /* Horizontal Sync Control */
+ aty_st_514(0x05, 0x00, info); /* Power Management */
+ aty_st_514(0x02, 0x01, info); /* Misc Clock Control */
+ aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */
+ aty_st_514(0x0a, tab[i].pixel_rep, info); /* Pixel Format */
+ aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
+ /* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+}
- switch (info->chip_class) {
- case CLASS_GX:
- /* The magic constant below translates into:
- * 5 = No RDY delay, 1 wait st for mem write, increment during
- * burst transfer
- * 9 = DAC access delayed, 1 wait state for DAC
- * 0 = Disables interupts for FIFO errors
- * e = Allows FIFO to generate 14 wait states before generating
- * error
- * 1 = DAC snooping disabled, ROM disabled
- * 0 = ROM page at 0 (disabled so doesn't matter)
- * f = 15 ROM wait states (disabled so doesn't matter)
- * f = 15 BUS wait states (I'm not sure this applies to PCI bus
- * types)
- * at some point it would be good to experiment with bench marks to
- * if we can gain some speed by fooling with the wait states etc.
- */
- aty_st_le32(BUS_CNTL, 0x890e20f1 /* 0x590e10ff */, info);
- j = 0x47012100;
- j = 0x47052100;
+static int aty_crtc_to_var(const struct crtc *crtc,
+ struct fb_var_screeninfo *var)
+{
+ u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+ u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+ u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+ u32 pix_width;
+
+ /* input */
+ h_total = crtc->h_tot_disp & 0x1ff;
+ h_disp = (crtc->h_tot_disp>>16) & 0xff;
+ h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+ ((crtc->h_sync_strt_wid>>4) & 0x100);
+ h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+ h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+ h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+ v_total = crtc->v_tot_disp & 0x7ff;
+ v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
+ v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+ v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+ v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+ pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+ /* convert */
+ xres = (h_disp+1)*8;
+ yres = v_disp+1;
+ left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+ right = (h_sync_strt-h_disp)*8;
+ hslen = h_sync_wid*8;
+ upper = v_total-v_sync_strt-v_sync_wid;
+ lower = v_sync_strt-v_disp;
+ vslen = v_sync_wid;
+ sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
+
+ switch (pix_width) {
+#if 0
+ case CRTC_PIX_WIDTH_4BPP:
+ bpp = 4;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_8BPP:
+ bpp = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */
+ bpp = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
break;
+#if 0
+ case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */
+ bpp = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 6;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */
+ bpp = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */
+ bpp = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ default:
+ FAIL("Invalid pixel width");
+ }
- case CLASS_VT:
- if (vram_type == 4) {
- /*
- * What to do here? - The contents of MEM_CNTL do not
- * seem to match my documentation, and touching this
- * register makes the output unusable.
- * (green bars across the screen and similar effects).
- *
- * Eddie C. Dost (ecd@skynet.be)
- */
- j = 0x87010184;
- break;
- }
- /* fallthrough */
+ /* output */
+ var->xres = xres;
+ var->yres = yres;
+ var->xres_virtual = crtc->vxres;
+ var->yres_virtual = crtc->vyres;
+ var->bits_per_pixel = bpp;
+ var->xoffset = crtc->xoffset;
+ var->yoffset = crtc->yoffset;
+ var->left_margin = left;
+ var->right_margin = right;
+ var->upper_margin = upper;
+ var->lower_margin = lower;
+ var->hsync_len = hslen;
+ var->vsync_len = vslen;
+ var->sync = sync;
+ var->vmode = FB_VMODE_NONINTERLACED;
- case CLASS_CT:
- aty_st_le32(BUS_CNTL, 0x680000f9, info);
- switch (info->total_vram) {
- case 0x00100000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->hw.gx.cmode],
- info);
- break;
- case 0x00200000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->hw.gx.cmode],
- info);
- break;
- case 0x00400000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->hw.gx.cmode],
- info);
- break;
- default:
- i = aty_ld_le32(MEM_CNTL, info) & 0x000F;
- aty_st_le32(MEM_CNTL,
- (init->mem_cntl[par->hw.gx.cmode] &
- 0xFFFFFFF0) | i,
- info);
- }
- j = 0x87010184;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+ /*
+ * PLL programming (Mach64 GX family)
+ *
+ * FIXME: use function pointer tables instead of switch statements
+ */
+
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+ const struct pll_gx *pll)
+{
+ switch (info->clk_type) {
+ case CLK_ATI18818_1:
+ aty_st_8(CLOCK_CNTL, pll->m, info);
+ break;
+ case CLK_IBMRGB514:
+ aty_st_514(0x06, 0x02, info); /* DAC Operation */
+ aty_st_514(0x10, 0x01, info); /* PLL Control 1 */
+ aty_st_514(0x70, 0x01, info); /* Misc Control 1 */
+ aty_st_514(0x8f, 0x1f, info); /* PLL Ref. Divider Input */
+ aty_st_514(0x03, 0x00, info); /* Sync Control */
+ aty_st_514(0x05, 0x00, info); /* Power Management */
+ aty_st_514(0x20, pll->m, info); /* F0 / M0 */
+ aty_st_514(0x21, pll->m, info); /* F1 / N0 */
break;
+ }
+}
- case CLASS_GT:
- aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll)
+{
+ /*
+ * FIXME: use real calculations instead of using fixed values from the old
+ * driver
+ */
+ static struct {
+ u32 ps_lim; /* pixclock period rounding limit (arbitrary) */
+ u8 mode; /* (prescsaler << 4) | Select */
+ u8 prog; /* ref_div_count */
+ } ATI18818_clocks[] = {
+ { 7500, 0x0B, 1 }, /* 7407.4 ps = 135.00 MHz */
+ { 9000, 0x0A, 1 }, /* 7936.5 ps = 126.00 MHz */
+ { 11000, 0x09, 1 }, /* 10000.0 ps = 100.00 MHz */
+ { 12800, 0x0D, 1 }, /* 12500.0 ps = 80.00 MHz */
+ { 13500, 0x0E, 1 }, /* 13333.3 ps = 75.00 MHz */
+/* { 14000, 0x03, 2 },*/ /* 13888.8 ps = 72.00 MHz */
+ { 15000, 0x1B, 1 }, /* 14814.8 ps = 67.50 MHz */
+ { 15500, 0x0F, 1 }, /* 15384.6 ps = 65.00 MHz */
+ { 16000, 0x1A, 1 }, /* 15873.0 ps = 63.00 MHz */
+/* { 16000, 0x02, 2 },*/ /* 15873.0 ps = 63.00 MHz */
+/* { 18000, 0x01, 2 },*/ /* 17655.4 ps = 56.64 MHz */
+/* { 19900, 0x00, 2 },*/ /* 19860.9 ps = 50.35 MHz */
+ { 20000, 0x07, 1 }, /* 20000.0 ps = 50.00 MHz */
+ { 20300, 0x06, 1 }, /* 20202.0 ps = 49.50 MHz */
+ { 22500, 0x05, 1 }, /* 22271.2 ps = 44.90 MHz */
+ { 25000, 0x04, 1 }, /* 25000.0 ps = 40.00 MHz */
+/* { 28000, 0x03, 1 },*/ /* 27777.8 ps = 36.00 MHz */
+ { 30000, 0x2B, 1 }, /* 29629,6 ps = 33.75 MHz */
+ { 31000, 0x1F, 1 }, /* 30769.2 ps = 32.50 MHz */
+ { 32000, 0x2A, 1 }, /* 31746.0 ps = 31.50 MHz */
+/* { 32000, 0x02, 1 },*/ /* 31746.0 ps = 31.50 MHz */
+/* { 36000, 0x01, 1 },*/ /* 35310.7 ps = 28.32 MHz */
+/* { 39900, 0x00, 1 },*/ /* 39714.1 ps = 25.18 MHz */
+ { 40000, 0x17, 1 }, /* 40000.0 ps = 25.00 MHz */
+ { 40600, 0x16, 1 }, /* 40404.0 ps = 24.75 MHz */
+ { 45000, 0x15, 1 }, /* 44543.4 ps = 22.45 MHz */
+ { 50000, 0x14, 1 }, /* 50000.0 ps = 20.00 MHz */
+/* { 56000, 0x13, 1 },*/ /* 55555.5 ps = 18.00 MHz */
+ { 62000, 0x2F, 1 }, /* 61538.8 ps = 16.25 MHz */
+/* { 64000, 0x12, 1 },*/ /* 63492.0 ps = 15.75 MHz */
+ };
+ int set;
+
+ for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
+ set++)
+ if (var->pixclock <= ATI18818_clocks[set].ps_lim) {
+ pll->m = ATI18818_clocks[set].mode;
+ pll->n = ATI18818_clocks[set].prog;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll)
+{
+ /*
+ * FIXME: use real calculations instead of using fixed values from the old
+ * driver
+ */
+ static struct {
+ u32 limit; /* pixlock rounding limit (arbitrary) */
+ u8 m; /* (df<<6) | vco_div_count */
+ u8 n; /* ref_div_count */
+ } RGB514_clocks[7] = {
+ { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */
+ { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */
+ { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */
+ { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */
+ { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */
+ { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */
+ { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */
+ };
+ int i;
+
+ for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
+ if (var->pixclock <= RGB514_clocks[i].limit) {
+ pll->m = RGB514_clocks[i].m;
+ pll->n = RGB514_clocks[i].n;
+ return 0;
+ }
+ return -EINVAL;
+}
- /* need to set DSP values !! assume sdram */
- i = init->crtc_gen_cntl[0] - (0x100000 * par->hw.gx.cmode);
- if ( vram_type == 5 )
- i = init->crtc_gen_cntl[1] - (0x100000 * par->hw.gx.cmode);
- aty_st_le32(DSP_CONFIG, i, info);
+ /* FIXME: ATI18818?? */
- i = aty_ld_le32(MEM_CNTL, info) & MEM_SIZE_ALIAS;
- if ( vram_type == 5 ) {
- i |= ((1 * par->hw.gx.cmode) << 26) | 0x4215b0;
- aty_st_le32(DSP_ON_OFF,
- sgram_dsp[par->hw.gx.vmode-1][par->hw.gx.cmode],
- info);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+ struct fb_var_screeninfo *var)
+{
+ u8 df, vco_div_count, ref_div_count;
- /* aty_st_le32(CLOCK_CNTL, 8192, info); */
- } else {
- i |= ((1 * par->hw.gx.cmode) << 26) | 0x300090;
- aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->hw.gx.cmode],
- info);
- }
- aty_st_le32(MEM_CNTL, i, info);
- aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+ df = pll->m >> 6;
+ vco_div_count = pll->m & 0x3f;
+ ref_div_count = pll->n;
+
+ var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df);
+
+ return 0;
+}
- /* if (info->total_vram > 0x400000)
- i |= 0x538; this not been verified on > 4Megs!! */
- j = 0x86010102;
+ /*
+ * PLL programming (Mach64 CT family)
+ */
+
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+ const struct pll_ct *pll)
+{
+#if 0 /* ecd debug */
+printk("PLL_REF_DIV: %02x (%02x)\n",
+ pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info));
+printk("PLL_GEN_CNTL: %02x (%02x)\n",
+ pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info));
+printk("MCLK_FB_DIV: %02x (%02x)\n",
+ pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info));
+printk("PLL_VCLK_CNTL: %02x (%02x)\n",
+ pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info));
+printk("VCLK_POST_DIV: %02x (%02x)\n",
+ pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info));
+printk("VCLK0_FB_DIV: %02x (%02x)\n",
+ pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info));
+printk("PLL_EXT_CNTL: %02x (%02x)\n",
+ pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info));
+#endif /* ecd debug */
+ aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);
+ aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);
+ aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);
+ aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);
+ aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);
+ aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
+ aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
+
+ if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) {
+ if (info->ram_type >= SDRAM)
+ aty_st_pll(DLL_CNTL, 0xa6, info);
+ else
+ aty_st_pll(DLL_CNTL, 0xa0, info);
+ aty_st_pll(VFC_CNTL, 0x1b, info);
+ aty_st_le32(DSP_CONFIG, pll->dsp_config, info);
+ aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);
+ }
+}
+
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+ u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+ u8 bpp, struct pll_ct *pll)
+{
+ u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
+ u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
+
+ /* xclocks_per_row<<11 */
+ xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/
+ (vclk_fb_div*mclk_post_div*bpp);
+ if (xclks_per_row < (1<<11))
+ FAIL("Dotclock to high");
+ fifo_size = 24;
+ dsp_precision = 0;
+ y = (xclks_per_row*fifo_size)>>11;
+ while (y) {
+ y >>= 1;
+ dsp_precision++;
+ }
+ dsp_precision -= 5;
+ /* fifo_off<<6 */
+ fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6);
+
+ if (info->total_vram > 1*1024*1024) {
+ if (info->ram_type >= SDRAM) {
+ /* >1 MB SDRAM */
+ dsp_loop_latency = 8;
+ page_size = 8;
+ } else {
+ /* >1 MB DRAM */
+ dsp_loop_latency = 6;
+ page_size = 9;
+ }
+ } else {
+ if (info->ram_type >= SDRAM) {
+ /* <2 MB SDRAM */
+ dsp_loop_latency = 9;
+ page_size = 10;
+ } else {
+ /* <2 MB DRAM */
+ dsp_loop_latency = 8;
+ page_size = 10;
+ }
+ }
+ /* fifo_on<<6 */
+ if (xclks_per_row >= (page_size<<11))
+ fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
+ else
+ fifo_on = (3*page_size)<<6;
+
+ dsp_xclks_per_row = xclks_per_row>>dsp_precision;
+ dsp_on = fifo_on>>dsp_precision;
+ dsp_off = fifo_off>>dsp_precision;
+
+ pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
+ ((dsp_loop_latency & 0xf)<<16) |
+ ((dsp_precision & 7)<<20);
+ pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
+ return 0;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct pll_ct *pll)
+{
+ u32 vclk_per, q, x; /* x is a workaround for sparc64-linux-gcc */
+ u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
+ u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
+ u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
+ int err;
+
+ x = x; /* x is a workaround for sparc64-linux-gcc */
+
+ pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+
+ vclk_per = var->pixclock;
+ pll_ref_div = info->pll_per*2*255/ref_clk_per;
+
+ /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+ q = ref_clk_per*pll_ref_div*4/info->mclk_per; /* actually 8*q */
+ if (q < 16*8 || q > 255*8)
+ FAIL("mclk out of range");
+ else if (q < 32*8)
+ mclk_post_div = 8;
+ else if (q < 64*8)
+ mclk_post_div = 4;
+ else if (q < 128*8)
+ mclk_post_div = 2;
+ else
+ mclk_post_div = 1;
+ mclk_fb_div = q*mclk_post_div/8;
+
+ /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+ q = ref_clk_per*pll_ref_div*4/vclk_per; /* actually 8*q */
+ if (q < 16*8 || q > 255*8)
+ FAIL("vclk out of range");
+ else if (q < 32*8)
+ vclk_post_div = 8;
+ else if (q < 64*8)
+ vclk_post_div = 4;
+ else if (q < 128*8)
+ vclk_post_div = 2;
+ else
+ vclk_post_div = 1;
+ vclk_fb_div = q*vclk_post_div/8;
+
+ if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
+ vclk_post_div, var->bits_per_pixel, pll)))
+ return err;
+
+ if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
+ pll_gen_cntl = 0x04;
+ else
+ pll_gen_cntl = 0x84;
+
+ switch (mclk_post_div) {
+ case 1:
+ mpostdiv = 0;
+ break;
+ case 2:
+ mpostdiv = 1;
+ break;
+ case 3:
+ mpostdiv = 4;
+ break;
+ case 4:
+ mpostdiv = 2;
+ break;
+ case 8:
+ mpostdiv = 3;
break;
}
+ pll_gen_cntl |= mpostdiv<<4; /* mclk */
- /* These magic constants (variable j) are harder to figure out
- * on the vt chipset bit 2 set makes the screen brighter
- * and bit 15 makes the screen black! But nothing else
- * seems to matter for the vt DAC_CNTL
- */
- aty_st_le32(DAC_CNTL, j, info);
- aty_st_8(DAC_MASK, 0xff, info);
+ if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
+ pll_ext_cntl = 0;
+ else
+ pll_ext_cntl = mpostdiv; /* xclk == mclk */
- switch (par->hw.gx.cmode) {
- case CMODE_16:
- i = CRTC_PIX_WIDTH_15BPP; break;
- /*case CMODE_24: */
- case CMODE_32:
- i = CRTC_PIX_WIDTH_32BPP; break;
- case CMODE_8:
- default:
- i = CRTC_PIX_WIDTH_8BPP; break;
+ switch (vclk_post_div) {
+ case 1:
+ vpostdiv = 0;
+ break;
+ case 2:
+ vpostdiv = 1;
+ break;
+ case 3:
+ vpostdiv = 0;
+ pll_ext_cntl |= 0x10;
+ break;
+ case 4:
+ vpostdiv = 2;
+ break;
+ case 6:
+ vpostdiv = 2;
+ pll_ext_cntl |= 0x10;
+ break;
+ case 8:
+ vpostdiv = 3;
+ break;
+ case 12:
+ vpostdiv = 3;
+ pll_ext_cntl |= 0x10;
+ break;
}
+ vclk_post_div = vpostdiv;
+
+ pll->pll_ref_div = pll_ref_div;
+ pll->pll_gen_cntl = pll_gen_cntl;
+ pll->mclk_fb_div = mclk_fb_div;
+ pll->vclk_post_div = vclk_post_div;
+ pll->vclk_fb_div = vclk_fb_div;
+ pll->pll_ext_cntl = pll_ext_cntl;
+ return 0;
+}
+
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+ struct fb_var_screeninfo *var)
+{
+ u8 pll_ref_div = pll->pll_ref_div;
+ u8 vclk_fb_div = pll->vclk_fb_div;
+ u8 vclk_post_div = pll->vclk_post_div;
+ u8 pll_ext_cntl = pll->pll_ext_cntl;
+ static u8 vclk_post_div_tab[] = {
+ 1, 2, 4, 8,
+ 3, 0, 6, 12
+ };
+ u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 1) |
+ (vclk_post_div & 3)];
+ if (vpostdiv == 0)
+ return -EINVAL;
+ var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void atyfb_set_par(const struct atyfb_par *par,
+ struct fb_info_aty *info)
+{
+ u32 i;
+
+ info->current_par = *par;
+
+ aty_set_crtc(info, &par->crtc);
+ aty_st_8(CLOCK_CNTL, 0, info);
+ aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
- if (info->chip_class != CLASS_GT) {
- aty_st_le32(CRTC_INT_CNTL, 0x00000002, info);
- aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE,
- info); /* gui_en block_en */
- i |= init->crtc_gen_cntl[par->hw.gx.cmode];
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ switch (info->dac_type) {
+ case DAC_IBMRGB514:
+ aty_set_dac_514(info, par->crtc.bpp);
+ break;
+ case DAC_ATI68860_B:
+ /* FIXME */
+ break;
+ }
+ aty_set_pll_gx(info, &par->pll.gx);
+ aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+ aty_st_le32(DAC_CNTL, 0x47052100, info);
+ } else {
+ aty_set_pll_ct(info, &par->pll.ct);
+ i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+ if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
+ i |= info->mem_refresh_rate << 20;
+ switch (par->crtc.bpp) {
+ case 8:
+ case 24:
+ i |= 0x00000000;
+ break;
+ case 16:
+ i |= 0x04000000;
+ break;
+ case 32:
+ i |= 0x08000000;
+ break;
+ }
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ aty_st_le32(DAC_CNTL, 0x87010184, info);
+ aty_st_le32(BUS_CNTL, 0x680000f9, info);
+ } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+ aty_st_le32(DAC_CNTL, 0x87010184, info);
+ aty_st_le32(BUS_CNTL, 0x680000f9, info);
+ } else {
+ /* GT */
+ aty_st_le32(DAC_CNTL, 0x86010102, info);
+ aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+ aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+ }
+ aty_st_le32(MEM_CNTL, i, info);
}
- /* Gentlemen, start your crtc engine */
- aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info);
+ aty_st_8(DAC_MASK, 0xff, info);
/* Initialize the graphics engine */
- if (par->accel & FB_ACCELF_TEXT)
+ if (par->accel_flags & FB_ACCELF_TEXT)
init_engine(par, info);
#ifdef CONFIG_FB_COMPAT_XPMAC
if (console_fb_info == &info->fb_info) {
- display_info.height = vmode_attrs[par->hw.gx.vmode-1].vres;
- display_info.width = vmode_attrs[par->hw.gx.vmode-1].hres;
- display_info.depth = 8<<par->hw.gx.cmode;
- display_info.pitch = par->vxres<<par->hw.gx.cmode;
- display_info.mode = par->hw.gx.vmode;
+ struct fb_var_screeninfo var;
+ int vmode, cmode;
+ display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+ display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+ display_info.depth = par->crtc.bpp;
+ display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
+ atyfb_encode_var(&var, par, info);
+ if (mac_var_to_vmode(&var, &vmode, &cmode))
+ display_info.mode = 0;
+ else
+ display_info.mode = vmode;
strcpy(display_info.name, atyfb_name);
display_info.fb_address = info->frame_buffer_phys;
- if (info->chip_class == CLASS_VT)
- display_info.fb_address += init->offset[par->hw.gx.cmode];
display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
display_info.disp_reg_address = info->ati_regbase_phys;
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+ struct atyfb_par *par,
+ const struct fb_info_aty *info)
+{
+ int err;
+
+ if ((err = aty_var_to_crtc(info, var, &par->crtc)))
+ return err;
+ if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+ switch (info->clk_type) {
+ case CLK_ATI18818_1:
+ err = aty_var_to_pll_18818(var, &par->pll.gx);
+ break;
+ case CLK_IBMRGB514:
+ err = aty_var_to_pll_514(var, &par->pll.gx);
+ break;
+ }
+ else
+ err = aty_var_to_pll_ct(info, var, &par->pll.ct);
+ if (err)
+ return err;
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ par->accel_flags = FB_ACCELF_TEXT;
+ else
+ par->accel_flags = 0;
+
+#if 0
+ if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+ return -EINVAL;
+#endif
+
+ return 0;
+}
+
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info)
+{
+ int err;
+
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+ if ((err = aty_crtc_to_var(&par->crtc, var)))
+ return err;
+ if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+ err = aty_pll_gx_to_var(&par->pll.gx, var);
+ else
+ err = aty_pll_ct_to_var(&par->pll.ct, var);
+ if (err)
+ return err;
+
+ var->height = -1;
+ var->width = -1;
+ var->accel_flags = par->accel_flags;
+
+ return 0;
+}
+
+
+
+static void set_off_pitch(struct atyfb_par *par,
+ const struct fb_info_aty *info)
+{
+ u32 xoffset = par->crtc.xoffset;
+ u32 yoffset = par->crtc.yoffset;
+ u32 vxres = par->crtc.vxres;
+ u32 bpp = par->crtc.bpp;
+
+ par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
+}
+
/*
* Open/Release the frame buffer device
static int atyfb_open(struct fb_info *info, int user)
{
- /*
- * Nothing, only a usage count for the moment
- */
-
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+ if (user) {
+ if (fb->open)
+ return -EBUSY;
+ fb->mmaped = 0;
+ fb->open = 1;
+ fb->vtconsole = -1;
+ } else {
+ fb->consolecnt++;
+ }
+#endif
MOD_INC_USE_COUNT;
return(0);
}
static int atyfb_release(struct fb_info *info, int user)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+ if (user) {
+ if (fb->vtconsole != -1)
+ vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+ fb->open = 0;
+ fb->mmaped = 0;
+ fb->vtconsole = -1;
+ } else {
+ fb->consolecnt--;
+ }
+#endif
MOD_DEC_USE_COUNT;
return(0);
}
static int encode_fix(struct fb_fix_screeninfo *fix,
- const struct atyfb_par *par, struct fb_info_aty *info)
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info)
{
- struct aty_regvals *init;
-
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, atyfb_name);
- init = get_aty_struct(par->hw.gx.vmode, info);
- /*
- * FIXME: This will cause problems on non-GT chips, because the frame
- * buffer must be aligned to a page
- */
fix->smem_start = (char *)info->frame_buffer_phys;
- if (info->chip_class == CLASS_VT)
- fix->smem_start += init->offset[par->hw.gx.cmode];
fix->smem_len = (u32)info->total_vram;
#ifdef __LITTLE_ENDIAN
/*
* Last page of 8 MB little-endian aperture is MMIO
- * FIXME: we should use the auxillary aperture instead so we can acces the
+ * FIXME: we should use the auxiliary aperture instead so we can acces the
* full 8 MB of video RAM on 8 MB boards
*/
- if (fix->smem_len > 0x800000-PAGE_SIZE)
- fix->smem_len = 0x800000-PAGE_SIZE;
+ if (fix->smem_len > 0x800000-GUI_RESERVE)
+ fix->smem_len = 0x800000-GUI_RESERVE;
#endif
/*
* Reg Block 0 (CT-compatible block) is at ati_regbase_phys
* Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
- */
- switch (info->chip_class) {
- case CLASS_GX:
- fix->mmio_start = (char *)info->ati_regbase_phys;
- fix->mmio_len = 0x400;
- fix->accel = FB_ACCEL_ATI_MACH64GX;
- break;
- case CLASS_CT:
- fix->mmio_start = (char *)info->ati_regbase_phys;
- fix->mmio_len = 0x400;
- fix->accel = FB_ACCEL_ATI_MACH64CT;
- break;
- case CLASS_VT:
- fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
- fix->mmio_len = 0x800;
- fix->accel = FB_ACCEL_ATI_MACH64VT;
- break;
- case CLASS_GT:
- fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
- fix->mmio_len = 0x800;
- fix->accel = FB_ACCEL_ATI_MACH64GT;
- break;
- default:
- fix->mmio_start = NULL;
- fix->mmio_len = 0;
- fix->accel = 0;
- }
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- fix->line_length = par->vxres<<par->hw.gx.cmode;
- fix->visual = par->hw.gx.cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_TRUECOLOR;
- fix->ywrapstep = 0;
- fix->xpanstep = 8;
- fix->ypanstep = 1;
-
- return 0;
-}
-
-
-static int decode_var(struct fb_var_screeninfo *var,
- struct atyfb_par *par, struct fb_info_aty *info)
-{
- int xres = var->xres;
- int yres = var->yres;
- int bpp = var->bits_per_pixel;
- struct aty_regvals *init;
-
- /* This should support more video modes */
-
- if (xres <= 512 && yres <= 384)
- par->hw.gx.vmode = VMODE_512_384_60; /* 512x384, 60Hz */
- else if (xres <= 640 && yres <= 480)
- par->hw.gx.vmode = VMODE_640_480_67; /* 640x480, 67Hz */
- else if (xres <= 640 && yres <= 870)
- par->hw.gx.vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
- else if (xres <= 768 && yres <= 576)
- par->hw.gx.vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */
- else if (xres <= 800 && yres <= 600)
- par->hw.gx.vmode = VMODE_800_600_75; /* 800x600, 75Hz */
- else if (xres <= 832 && yres <= 624)
- par->hw.gx.vmode = VMODE_832_624_75; /* 832x624, 75Hz */
- else if (xres <= 1024 && yres <= 768)
- par->hw.gx.vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
- else if (xres <= 1152 && yres <= 870)
- par->hw.gx.vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
- else if (xres <= 1280 && yres <= 960)
- par->hw.gx.vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
- else if (xres <= 1280 && yres <= 1024)
- par->hw.gx.vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
- else
- return -EINVAL;
-
- xres = vmode_attrs[par->hw.gx.vmode-1].hres;
- yres = vmode_attrs[par->hw.gx.vmode-1].vres;
-
- if (var->xres_virtual <= xres)
- par->vxres = xres;
- else
- par->vxres = (var->xres_virtual+7) & ~7;
- if (var->yres_virtual <= yres)
- par->vyres = yres;
- else
- par->vyres = var->yres_virtual;
-
- par->xoffset = (var->xoffset+7) & ~7;
- par->yoffset = var->yoffset;
- if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
- return -EINVAL;
-
- if (bpp <= 8)
- par->hw.gx.cmode = CMODE_8;
- else if (bpp <= 16)
- par->hw.gx.cmode = CMODE_16;
- else if (bpp <= 32)
- par->hw.gx.cmode = CMODE_32;
- else
- return -EINVAL;
-
- if (var->accel_flags & FB_ACCELF_TEXT)
- par->accel = FB_ACCELF_TEXT;
- else
- par->accel = 0;
-
- if (aty_vram_reqd(par) > info->total_vram)
- return -EINVAL;
-
- /* Check if we know about the wanted video mode */
- init = get_aty_struct(par->hw.gx.vmode, info);
- if (init == NULL || init->crtc_h_sync_strt_wid[par->hw.gx.cmode] == 0 ||
- (info->chip_class != CLASS_GT &&
- init->crtc_gen_cntl[par->hw.gx.cmode] == 0) ||
- (info->chip_class == CLASS_GT &&
- (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 &&
- init->crtc_gen_cntl[1] == 0))
- return -EINVAL;
-
-#if 0
- if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
- return -EINVAL;
-#endif
+ */
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ fix->mmio_start = (char *)info->ati_regbase_phys;
+ fix->mmio_len = 0x400;
+ fix->accel = FB_ACCEL_ATI_MACH64GX;
+ } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ fix->mmio_start = (char *)info->ati_regbase_phys;
+ fix->mmio_len = 0x400;
+ fix->accel = FB_ACCEL_ATI_MACH64CT;
+ } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+ fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+ fix->mmio_len = 0x800;
+ fix->accel = FB_ACCEL_ATI_MACH64VT;
+ } else {
+ fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+ fix->mmio_len = 0x800;
+ fix->accel = FB_ACCEL_ATI_MACH64GT;
+ }
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+ fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ fix->ywrapstep = 0;
+ fix->xpanstep = 8;
+ fix->ypanstep = 1;
return 0;
}
-static int encode_var(struct fb_var_screeninfo *var,
- const struct atyfb_par *par,
- struct fb_info_aty *info)
-{
- int vmode = par->hw.gx.vmode;
- int cmode = par->hw.gx.cmode;
- struct aty_regvals *init = get_aty_struct(vmode, info);
- u_int h_total, h_disp;
- u_int h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
- u_int v_total, v_disp;
- u_int v_sync_strt, v_sync_wid, v_sync_pol;
- u_int xtalin, vclk = 0;
- u8 pll_ref_div, vclk_fb_div, vclk_post_div, pll_ext_cntl;
-
- memset(var, 0, sizeof(struct fb_var_screeninfo));
- if (!init)
- return -EINVAL;
- var->xres = vmode_attrs[vmode-1].hres;
- var->yres = vmode_attrs[vmode-1].vres;
- var->xres_virtual = par->vxres;
- var->yres_virtual = par->vyres;
- var->xoffset = par->xoffset;
- var->yoffset = par->yoffset;
- var->grayscale = 0;
- switch (cmode) {
- case CMODE_8:
- var->bits_per_pixel = 8;
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CMODE_16: /* RGB 555 */
- var->bits_per_pixel = 16;
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CMODE_32: /* RGB 888 */
- var->bits_per_pixel = 32;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- }
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
- var->nonstd = 0;
- var->activate = 0;
- var->height = -1;
- var->width = -1;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->accel_flags = par->accel;
-
- h_total = (init->crtc_h_tot_disp<<3) & 0xff8;
- h_disp = (init->crtc_h_tot_disp>>13) & 0x7f8;
- h_sync_strt = ((init->crtc_h_sync_strt_wid[cmode]<<3) & 0x7f8) |
- ((init->crtc_h_sync_strt_wid[cmode]>>1) & 0x800);
- h_sync_dly = (init->crtc_h_sync_strt_wid[cmode]>>8) & 0x7;
- h_sync_wid = (init->crtc_h_sync_strt_wid[cmode]>>13) & 0xf8;
- h_sync_pol = (init->crtc_h_sync_strt_wid[cmode]>>21) & 0x1;
-
- v_total = init->crtc_v_tot_disp & 0x7ff;
- v_disp = (init->crtc_v_tot_disp>>16) & 0x7ff;
- v_sync_strt = init->crtc_v_sync_strt_wid & 0x7ff;
- v_sync_wid = (init->crtc_v_sync_strt_wid>>16) & 0x1f;
- v_sync_pol = (init->crtc_v_sync_strt_wid>>21) & 0x1;
-
- var->left_margin = (h_total+8)-h_sync_strt-h_sync_wid;
- var->right_margin = h_sync_strt-(h_disp+8);
- var->upper_margin = (v_total+1)-v_sync_strt-v_sync_wid;
- var->lower_margin = v_sync_strt-(v_disp+1);
- var->hsync_len = h_sync_wid;
- var->vsync_len = v_sync_wid;
- var->sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
- (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
-
- xtalin = 69841; /* 14.31818 MHz */
- switch (info->chip_class) {
- case CLASS_GX:
- {
- /* haven't read the IBM RGB514 PDF yet, so just guesses */
- static u32 gx_vclk[VMODE_MAX] = {
- 0, /* vmode 1 */
- 0, /* vmode 2 */
- 0, /* vmode 3 */
- 0, /* vmode 4 */
- 39722, /* vmode 5 (25.175 MHz) */
- 33333, /* vmode 6 (30 MHz) */
- 0, /* vmode 7 */
- 0, /* vmode 8 */
- 27778, /* vmode 9 (36 MHz) */
- 25000, /* vmode 10 (40 MHz) */
- 20000, /* vmode 11 (50 MHz) */
- 20000, /* vmode 12 (50 MHz) */
- 17544, /* vmode 13 (57 MHz) */
- 15385, /* vmode 14 (65 MHz) */
- 13333, /* vmode 15 (75 MHz) */
- 0, /* vmode 16 */
- 12821, /* vmode 17 (78 MHz) */
- 10000, /* vmode 18 (100 MHz) */
- 7937, /* vmode 19 (126 MHz) */
- 7407 /* vmode 20 (135 MHz) */
- };
- vclk = gx_vclk[vmode-1];
- }
- break;
- case CLASS_CT:
- case CLASS_GT:
- case CLASS_VT:
- if (info->chip_class == CLASS_GT) {
- pll_ref_div = 0x21;
- vclk_post_div = init->offset[0];
- vclk_fb_div = init->offset[1];
- pll_ext_cntl = init->offset[2];
- } else {
- pll_ref_div = 0x2d;
- vclk_post_div = init->clock_val[0];
- vclk_fb_div = init->clock_val[1];
- pll_ext_cntl = 0x0;
- }
- vclk = xtalin*pll_ref_div;
- switch (vclk_post_div & 3) {
- case 0:
- vclk *= (pll_ext_cntl & 0x10) ? 3 : 1;
- break;
- case 1:
- if (pll_ext_cntl & 0x10)
- return -EINVAL;
- vclk *= 2;
- break;
- case 2:
- vclk *= (pll_ext_cntl & 0x10) ? 6 : 4;
- break;
- case 3:
- vclk *= (pll_ext_cntl & 0x10) ? 12 : 8;
- break;
- }
- vclk /= 2*vclk_fb_div;
- break;
- }
- var->pixclock = vclk;
+struct fb_var_screeninfo default_var = {
+ /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
- return 0;
-}
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+ /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+ /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+ 1152, 900, 1152, 900, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
-static void init_par(struct atyfb_par *par, int vmode, int cmode)
-{
- par->hw.gx.vmode = vmode;
- par->hw.gx.cmode = cmode;
- par->vxres = vmode_attrs[vmode-1].hres;
- par->vyres = vmode_attrs[vmode-1].vres;
- par->xoffset = 0;
- par->yoffset = 0;
- par->accel = FB_ACCELF_TEXT;
-}
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+ /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+#endif
/*
*/
static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ const struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
if (con == -1)
- par = info2->default_par;
+ par = info->default_par;
else
- decode_var(&fb_display[con].var, &par, info2);
- encode_fix(fix, &par, info2);
+ atyfb_decode_var(&fb_display[con].var, &par, info);
+ encode_fix(fix, &par, info);
return 0;
}
*/
static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ const struct fb_info_aty *info = (struct fb_info_aty *)fb;
if (con == -1)
- encode_var(var, &info2->default_par, (struct fb_info_aty *)info);
+ atyfb_encode_var(var, &info->default_par, info);
else
*var = fb_display[con].var;
return 0;
*/
static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
struct display *display;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
if (con >= 0)
display = &fb_display[con];
else
- display = &fb_disp; /* used during initialization */
+ display = fb->disp; /* used during initialization */
- if ((err = decode_var(var, &par, info2)))
+ if ((err = atyfb_decode_var(var, &par, info)))
return err;
- encode_var(var, &par, (struct fb_info_aty *)info);
+ atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldxres = display->var.xres;
oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
struct fb_fix_screeninfo fix;
- encode_fix(&fix, &par, info2);
- display->screen_base = (char *)info2->frame_buffer;
+ encode_fix(&fix, &par, info);
+ display->screen_base = (char *)info->frame_buffer;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->can_soft_blank = 1;
display->inverse = 0;
accel = var->accel_flags & FB_ACCELF_TEXT;
- switch (par.hw.gx.cmode) {
+ switch (par.crtc.bpp) {
#ifdef FBCON_HAS_CFB8
- case CMODE_8:
- display->dispsw = accel ? &fbcon_aty8 : &fbcon_cfb8;
+ case 8:
+ *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
- case CMODE_16:
- display->dispsw = accel ? &fbcon_aty16 : &fbcon_cfb16;
+ case 16:
+ *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
- case CMODE_32:
- display->dispsw = accel ? &fbcon_aty32 : &fbcon_cfb32;
+ case 32:
+ *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
break;
#endif
default:
break;
}
display->scrollmode = accel ? 0 : SCROLL_YREDRAW;
- if (info->changevar)
- (*info->changevar)(con);
- if (info2->cursor) {
- display->dispsw->cursor = atyfb_cursor;
- display->dispsw->set_font = atyfb_set_font;
+ if (info->fb_info.changevar)
+ (*info->fb_info.changevar)(con);
+ if (info->cursor) {
+ display->dispsw->cursor = atyfb_cursor;
+ display->dispsw->set_font = atyfb_set_font;
}
}
if (con == currcon)
- atyfb_set_par(&par, info2);
+ atyfb_set_par(&par, info);
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con, info);
+ do_install_cmap(con, &info->fb_info);
}
}
*/
static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
u32 xres, yres, xoffset, yoffset;
- struct atyfb_par *par = &info2->current_par;
+ struct atyfb_par *par = &info->current_par;
- xres = vmode_attrs[par->hw.gx.vmode-1].hres;
- yres = vmode_attrs[par->hw.gx.vmode-1].vres;
+ xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+ yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
xoffset = (var->xoffset+7) & ~7;
yoffset = var->yoffset;
- if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
+ if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
return -EINVAL;
- par->xoffset = xoffset;
- par->yoffset = yoffset;
- set_off_pitch(par, info2);
+ par->crtc.xoffset = xoffset;
+ par->crtc.yoffset = yoffset;
+ set_off_pitch(par, info);
return 0;
}
vma->vm_file = file;
file->f_count++;
vma->vm_flags |= VM_IO;
+
+ if (!fb->mmaped) {
+ int lastconsole = 0;
+
+ if (info->display_fg)
+ lastconsole = info->display_fg->vc_num;
+ fb->mmaped = 1;
+ if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
+ fb->vtconsole = lastconsole;
+ vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+ }
+ }
return 0;
}
#endif /* __sparc__ */
{
u32 chip_id;
u32 i;
- int j, k, sense;
+ int j, k;
struct fb_var_screeninfo var;
- struct aty_regvals *init;
+ struct display *disp;
const char *chipname = NULL;
- u8 rev;
+ int pll, mclk;
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+ int sense;
+#endif
info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+ Gx = chip_id & CFG_CHIP_TYPE;
+ Rev = (chip_id & CFG_CHIP_REV)>>24;
for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
- if (aty_features[j].chip_type == (chip_id & CFG_CHIP_TYPE)) {
+ if (aty_features[j].chip_type == Gx) {
chipname = aty_features[j].name;
- info->chip_class = aty_features[j].chip_class;
- info->pixclock_lim_8 = 1000000/aty_features[j].pixclock_lim_8;
- info->pixclock_lim_hi = 1000000/aty_features[j].pixclock_lim_hi;
+ break;
}
if (!chipname) {
- printk("atyfb: Unknown Mach64 0x%04x\n", chip_id & CFG_CHIP_TYPE);
+ printk("atyfb: Unknown mach64 0x%04x\n", Gx);
return 0;
} else
- printk("atyfb: %s [", chipname);
- rev = (chip_id & CFG_CHIP_REV)>>24;
- switch ((rev>>3) & 7) {
- case MACH64_FND_SGS:
- printk("SGS");
- break;
- case MACH64_FND_NEC:
- printk("NEC");
- break;
- case MACH64_FND_UMC:
- printk("UMC");
- break;
+ printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev);
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
+ info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
+ /* FIXME: clockchip/RAMDAC probing? */
+#ifdef CONFIG_ATARI
+ info->dac_type = DAC_ATI68860_B;
+ info->clk_type = CLK_ATI18818_1;
+#else
+ info->dac_type = DAC_IBMRGB514;
+ info->clk_type = CLK_IBMRGB514;
+#endif
+ /* FIXME */
+ pll = 135;
+ mclk = 50;
+ } else {
+ info->bus_type = PCI;
+ info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+ info->dac_type = DAC_INTERNAL;
+ info->clk_type = CLK_INTERNAL;
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ pll = 135;
+ mclk = 60;
+ } else {
+ mclk = info->ram_type >= SDRAM ? 67 : 63;
+ if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) {
+ /* VTA3 */
+ pll = 170;
+ } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) ||
+ (Rev == 0x48))) ||
+ ((Gx == VT_CHIP_ID) && ((Rev == 0x01) ||
+ (Rev == 0x9a))) ||
+ (Gx == VU_CHIP_ID)) {
+ /* VTA4 or VTB */
+ pll = 200;
+ } else if (Gx == VT_CHIP_ID) {
+ /* other VT */
+ pll = 135;
+ mclk = 63;
+ } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) {
+ /* RAGE II */
+ pll = 170;
+ } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) ||
+ (Gx == GU_CHIP_ID)) {
+ /* RAGE II+ */
+ pll = 200;
+ } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) ||
+ (Gx == GQ_CHIP_ID)) {
+ /* RAGE PRO */
+ pll = 230;
+ } else {
+ /* other RAGE */
+ pll = 135;
+ mclk = 63;
+ }
+ }
}
- printk(" %c%d]\n", 'A'+(rev & 7), rev>>6);
+ if (mclk < 44)
+ info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */
+ else if (mclk < 50)
+ info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */
+ else if (mclk < 55)
+ info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */
+ else if (mclk < 66)
+ info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */
+ else if (mclk < 75)
+ info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */
+ else if (mclk < 80)
+ info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */
+ else if (mclk < 100)
+ info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */
+ else
+ info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */
+ printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk);
+ info->pll_per = 1000000/pll;
+ info->mclk_per = 1000000/mclk;
i = aty_ld_le32(MEM_CNTL, info);
- if (info->chip_class != CLASS_GT)
- switch (i & MEM_SIZE_ALIAS) {
+ if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+ switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
case MEM_SIZE_512K:
info->total_vram = 0x80000;
break;
case MEM_SIZE_1M:
info->total_vram = 0x100000;
break;
- case MEM_SIZE_2M:
+ case MEM_SIZE_2M_GTB:
info->total_vram = 0x200000;
break;
- case MEM_SIZE_4M:
+ case MEM_SIZE_4M_GTB:
info->total_vram = 0x400000;
break;
- case MEM_SIZE_6M:
+ case MEM_SIZE_6M_GTB:
info->total_vram = 0x600000;
break;
- case MEM_SIZE_8M:
+ case MEM_SIZE_8M_GTB:
info->total_vram = 0x800000;
break;
default:
info->total_vram = 0x80000;
}
else
- switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+ switch (i & MEM_SIZE_ALIAS) {
case MEM_SIZE_512K:
info->total_vram = 0x80000;
break;
case MEM_SIZE_1M:
info->total_vram = 0x100000;
break;
- case MEM_SIZE_2M_GTB:
+ case MEM_SIZE_2M:
info->total_vram = 0x200000;
break;
- case MEM_SIZE_4M_GTB:
+ case MEM_SIZE_4M:
info->total_vram = 0x400000;
break;
- case MEM_SIZE_6M_GTB:
+ case MEM_SIZE_6M:
info->total_vram = 0x600000;
break;
- case MEM_SIZE_8M_GTB:
+ case MEM_SIZE_8M:
info->total_vram = 0x800000;
break;
default:
info->total_vram = 0x80000;
}
-#ifdef CONFIG_ATARI /* this is definately not the wrong way to set this */
- if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
- /* protect GUI-regs if complete Aperture is VRAM */
- info->total_vram -= 0x00001000;
- }
-#endif
-#if 0
- printk("aty_init: regbase = %lx, frame_buffer = %lx, total_vram = %x\n",
- info->ati_regbase, info->frame_buffer, info->total_vram);
-#endif
+ if (info->bus_type == ISA)
+ if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
+ /* protect GUI-regs if complete Aperture is VRAM */
+ info->total_vram -= GUI_RESERVE;
+ }
- sense = read_aty_sense(info);
-#if 0
- printk("monitor sense = %x\n", sense);
-#endif
#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
if (default_vmode == VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
- init = get_aty_struct(default_vmode, info);
- if (default_vmode <= 0 || default_vmode > VMODE_MAX || init == 0)
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_CHOOSE;
}
- if (default_vmode == VMODE_CHOOSE)
- default_vmode = map_monitor_sense(sense);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
- if (default_vmode == VMODE_NVRAM)
- default_vmode = map_monitor_sense(sense);
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
-
- if (!(init = get_aty_struct(default_vmode, info)))
+ if (default_vmode == VMODE_CHOOSE) {
+ sense = read_aty_sense(info);
+ default_vmode = mac_map_monitor_sense(sense);
+ }
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
-
- /*
- * Reduce the pixel size if we don't have enough VRAM.
- */
-
if (default_cmode == CMODE_NVRAM)
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
default_cmode = nvram_read_byte(NV_CMODE);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
- default_cmode = CMODE_8;
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
-
- init_par(&info->default_par, default_vmode, default_cmode);
- while (aty_vram_reqd(&info->default_par) > info->total_vram) {
- while (default_cmode > CMODE_8 &&
- aty_vram_reqd(&info->default_par) > info->total_vram) {
- --default_cmode;
- init_par(&info->default_par, default_vmode, default_cmode);
- }
- /*
- * Adjust the video mode smaller if there still is not enough VRAM
- */
- if (aty_vram_reqd(&info->default_par) > info->total_vram)
- do {
- default_vmode--;
- init_par(&info->default_par, default_vmode, default_cmode);
- init = get_aty_struct(default_vmode, info);
- } while ((init == 0) &&
- (default_vmode > VMODE_640_480_60));
+ if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+ var = default_var;
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+ var = default_var;
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+ var.accel_flags |= FB_ACCELF_TEXT;
+ if (atyfb_decode_var(&var, &info->default_par, info)) {
+ printk("atyfb: can't set default video mode\n");
+ return 0;
}
- if (info->chip_class == CLASS_GT &&
- (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5
- && init->crtc_gen_cntl[1] == 0) {
- default_vmode = VMODE_640_480_67;
- default_cmode = CMODE_8;
- init_par(&info->default_par, default_vmode, default_cmode);
- }
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+ strcat(atyfb_name, "GX");
+ else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID))
+ strcat(atyfb_name, "CT");
+ else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID))
+ strcat(atyfb_name, "VT");
+ else
+ strcat(atyfb_name, "GT");
+
+ disp = &info->disp;
- switch (info->chip_class) {
- case CLASS_GX:
- strcat(atyfb_name, "GX");
- break;
- case CLASS_CT:
- strcat(atyfb_name, "CT");
- break;
- case CLASS_VT:
- strcat(atyfb_name, "VT");
- break;
- case CLASS_GT:
- strcat(atyfb_name, "GT");
- break;
- }
strcpy(info->fb_info.modename, atyfb_name);
info->fb_info.node = -1;
info->fb_info.fbops = &atyfb_ops;
- info->fb_info.disp = &fb_disp;
- info->fb_info.fontname[0] = '\0';
+ info->fb_info.disp = disp;
+ strcpy(info->fb_info.fontname, fontname);
info->fb_info.changevar = NULL;
info->fb_info.switch_con = &atyfbcon_switch;
info->fb_info.updatevar = &atyfbcon_updatevar;
info->palette[j].blue = default_blu[k];
}
- if (info->chip_class == CLASS_VT || info->chip_class == CLASS_GT) {
+ if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) {
info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
- memset(info->cursor, 0, sizeof(*info->cursor));
+ if (info->cursor)
+ memset(info->cursor, 0, sizeof(*info->cursor));
}
- atyfb_set_par(&info->default_par, info);
- encode_var(&var, &info->default_par, info);
+ disp->dispsw = &info->dispsw;
atyfb_set_var(&var, -1, &info->fb_info);
if (register_framebuffer(&info->fb_info) < 0)
struct pci_dev *pdev;
struct fb_info_aty *info;
unsigned long addr;
- int i, j;
- u16 tmp;
#ifdef __sparc__
extern int con_is_present(void);
+ u32 chip_id;
+ int i, j;
/* Do not attach when we have a serial console. */
if (!con_is_present())
- return;
+ return;
+#else
+ u16 tmp;
#endif
for (pdev = pci_devices; pdev; pdev = pdev->next) {
/* nothing */;
j = i + 1;
- info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
+ info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
if (!info->mmap_map) {
printk("atyfb_init: can't alloc mmap_map\n");
kfree(info);
/*
* Fix PROMs idea of MEM_CNTL settings...
*/
- tmp = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
- if (tmp == VT_CHIP_ID) {
+ chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
+ if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) {
u32 mem = aty_ld_le32(MEM_CNTL, info);
switch (mem & 0x0f) {
case 3:
int height = prom_getintdefault(node, "height", 768);
int depth = prom_getintdefault(node, "depth", 8);
- switch (depth) {
- case 8:
- default_cmode = CMODE_8;
+ switch (width) {
+ case 1024:
+ if (height == 768)
+ default_var = default_var_1024x768;
break;
- case 16:
- default_cmode = CMODE_16;
+ case 1152:
+ if (height == 900)
+ default_var = default_var_1152x900;
break;
- case 32:
- default_cmode = CMODE_32;
+ case 1280:
+ if (height == 1024)
+ default_var = default_var_1280x1024;
break;
default:
break;
}
- switch (width) {
- case 1024:
- if (height == 768)
- default_vmode = VMODE_1024_768_75;
+ switch (depth) {
+ case 8:
+ default_var.bits_per_pixel = 8;
break;
- case 1152:
- if (height == 870)
- default_vmode = VMODE_1152_870_75;
+ case 16:
+ default_var.bits_per_pixel = 16;
break;
- case 1280:
- if (height == 960)
- default_vmode = VMODE_1280_960_75;
- else if (height == 1024)
- default_vmode = VMODE_1280_1024_75;
+ case 24:
+ default_var.bits_per_pixel = 24;
+ break;
+ case 32:
+ default_var.bits_per_pixel = 32;
break;
default:
break;
#else /* __sparc__ */
- info->ati_regbase = (unsigned long)
- ioremap(0x7ff000 + addr, 0x1000) + 0xc00;
-
info->ati_regbase_phys = 0x7ff000 + addr;
info->ati_regbase = (unsigned long)
ioremap(info->ati_regbase_phys, 0x1000);
if (!aty_init(info, "PCI")) {
if (info->mmap_map)
kfree(info->mmap_map);
- kfree(info);
+ kfree(info);
}
}
}
__initfunc(void atyfb_setup(char *options, int *ints))
{
char *this_opt;
- int vmode;
- int depth;
+
if (!options || !*options)
return;
for (this_opt = strtok(options, ","); this_opt;
this_opt = strtok(NULL, ",")) {
+ if (!strncmp(this_opt, "font:", 5)) {
+ char *p;
+ int i;
+
+ p = this_opt + 5;
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (!*p || *p == ' ' || *p == ',')
+ break;
+ memcpy(fontname, this_opt + 5, i);
+ fontname[i] = 0;
+ }
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
if (!strncmp(this_opt, "vmode:", 6)) {
- vmode = simple_strtoul(this_opt+6, NULL, 0);
+ int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
default_vmode = vmode;
} else if (!strncmp(this_opt, "cmode:", 6)) {
- depth = simple_strtoul(this_opt+6, NULL, 0);
+ int depth = simple_strtoul(this_opt+6, NULL, 0);
switch (depth) {
case 8:
- default_cmode = CMODE_8;
+ default_cmode = 0;
break;
case 15:
case 16:
- default_cmode = CMODE_16;
+ default_cmode = 1;
break;
case 24:
case 32:
- default_cmode = CMODE_32;
+ default_cmode = 2;
break;
}
}
+#endif
#ifdef CONFIG_ATARI
/*
* Why do we need this silly Mach64 argument?
* We are already here because of mach64= so its redundant.
*/
- else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
+ if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
static unsigned char m64_num;
static char mach64_str[80];
strncpy(mach64_str, this_opt+7, 80);
}
#endif /* CONFIG_ATARI */
-static int atyfbcon_switch(int con, struct fb_info *info)
+static int atyfbcon_switch(int con, struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
/* Do we have to save the colormap? */
if (fb_display[currcon].cmap.len)
fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
- atyfb_getcolreg, info);
+ atyfb_getcolreg, fb);
+
+ /* Erase HW Cursor */
+ if (info->cursor)
+ atyfb_cursor(&fb_display[currcon], CM_ERASE,
+ info->cursor->pos.x, info->cursor->pos.y);
+
currcon = con;
- decode_var(&fb_display[con].var, &par, info2);
- atyfb_set_par(&par, info2);
+
+ atyfb_decode_var(&fb_display[con].var, &par, info);
+ atyfb_set_par(&par, info);
+
/* Install new colormap */
- do_install_cmap(con, info);
+ do_install_cmap(con, fb);
+
/* Install hw cursor */
- if (info2->cursor) {
- aty_set_cursor_color(info2, cursor_pixel_map, cursor_color_map,
+ if (info->cursor) {
+ aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map,
cursor_color_map, cursor_color_map);
- aty_set_cursor_shape(info2);
+ aty_set_cursor_shape(info);
}
- return 0;
+ return 1;
}
/*
* Update the `var' structure (called by fbcon.c)
*/
-static int atyfbcon_updatevar(int con, struct fb_info *info)
+static int atyfbcon_updatevar(int con, struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
- info2->current_par.yoffset = fb_display[con].var.yoffset;
- set_off_pitch(&info2->current_par, info2);
+ info->current_par.crtc.yoffset = fb_display[con].var.yoffset;
+ set_off_pitch(&info->current_par, info);
return 0;
}
* Blank the display.
*/
-static void atyfbcon_blank(int blank, struct fb_info *info)
+static void atyfbcon_blank(int blank, struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
u8 gen_cntl;
- gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info2);
+ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
if (blank > 0)
switch (blank-1) {
case VESA_NO_BLANKING:
}
else
gen_cntl &= ~(0x4c);
- aty_st_8(CRTC_GEN_CNTL, gen_cntl, info2);
+ aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
}
*/
static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
+ u_int *transp, struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
if (regno > 255)
return 1;
- *red = info2->palette[regno].red;
- *green = info2->palette[regno].green;
- *blue = info2->palette[regno].blue;
+ *red = info->palette[regno].red;
+ *green = info->palette[regno].green;
+ *blue = info->palette[regno].blue;
return 0;
}
*/
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
+ u_int transp, struct fb_info *fb)
{
- struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
int i, scale;
if (regno > 255)
return 1;
- info2->palette[regno].red = red;
- info2->palette[regno].green = green;
- info2->palette[regno].blue = blue;
- i = aty_ld_8(DAC_CNTL, info2) & 0xfc;
- if (info2->chip_class == CLASS_GT)
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+ i = aty_ld_8(DAC_CNTL, info) & 0xfc;
+ if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == LG_CHIP_ID) ||
+ (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) ||
+ (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
- aty_st_8(DAC_CNTL, i, info2);
- aty_st_8(DAC_REGS + DAC_MASK, 0xff, info2);
+ aty_st_8(DAC_CNTL, i, info);
+ aty_st_8(DAC_REGS + DAC_MASK, 0xff, info);
eieio();
- scale = ((info2->chip_class != CLASS_GX) &&
- (info2->current_par.hw.gx.cmode == CMODE_16)) ? 3 : 0;
- info2->aty_cmap_regs->windex = regno << scale;
+ scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
+ (info->current_par.crtc.bpp == 16)) ? 3 : 0;
+ info->aty_cmap_regs->windex = regno << scale;
eieio();
- info2->aty_cmap_regs->lut = red << scale;
+ info->aty_cmap_regs->lut = red << scale;
eieio();
- info2->aty_cmap_regs->lut = green << scale;
+ info->aty_cmap_regs->lut = green << scale;
eieio();
- info2->aty_cmap_regs->lut = blue << scale;
+ info->aty_cmap_regs->lut = blue << scale;
eieio();
if (regno < 16) {
#ifdef FBCON_HAS_CFB16
fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
#endif
+#ifdef FBCON_HAS_CFB24
+ fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno;
+#endif
#ifdef FBCON_HAS_CFB32
fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) |
(regno << 8) | regno;
if (!width || !height)
return;
- pitch_value = info->current_par.vxres;
-#if 0
- if (par->hw.gx.cmode == CMODE_24) {
+ pitch_value = info->current_par.crtc.vxres;
+ if (info->current_par.crtc.bpp == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
/* horizontal coordinates and widths must be adjusted */
- pitch_value = pitch_value * 3;
+ pitch_value *= 3;
+ srcx *= 3;
+ dstx *= 3;
+ width *= 3;
}
-#endif
if (srcy < dsty) {
dsty += height - 1;
if (!width || !height)
return;
+ if (info->current_par.crtc.bpp == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ dstx *= 3;
+ width *= 3;
+ }
+
wait_for_fifo(3, info);
aty_st_le32(DP_FRGD_CLR, color, info);
aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
sx *= p->fontwidth;
sy *= p->fontheight;
dx *= p->fontwidth;
static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
int sx, int height, int width)
{
- u32 bgx = attr_bgcol_ec(p, conp);
+ u32 bgx;
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ bgx = attr_bgcol_ec(p, conp);
bgx |= (bgx << 8);
bgx |= (bgx << 16);
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
int yy, int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb8_putc(conp, p, c, yy, xx);
}
static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
+ const unsigned short *s, int count, int yy,
+ int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
}
static struct display_switch fbcon_aty8 = {
fbcon_cfb8_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty8_putc,
fbcon_aty8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
- FONTWIDTH(8)
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
int yy, int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb16_putc(conp, p, c, yy, xx);
}
static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
+ const unsigned short *s, int count, int yy,
+ int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
}
static struct display_switch fbcon_aty16 = {
fbcon_cfb16_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty16_putc,
- fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb24_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty24 = {
+ fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_aty24_putc,
+ fbcon_aty24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
int yy, int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb32_putc(conp, p, c, yy, xx);
}
static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
+ const unsigned short *s, int count, int yy,
+ int xx)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
}
static struct display_switch fbcon_aty32 = {
fbcon_cfb32_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty32_putc,
- fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
--- /dev/null
+/* $Id: bwtwofb.c,v 1.1 1998/07/21 14:50:48 jj Exp $
+ * bwtwofb.c: BWtwo frame buffer driver
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 Pavel Machek (pavel@ucw.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+#ifndef __sparc_v9__
+#include <asm/sun4paddr.h>
+#endif
+
+#include "fbcon-mfb.h"
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bw2_regs {
+ struct bt_regs bt;
+ volatile u8 control;
+ volatile u8 status;
+ volatile u8 cursor_start;
+ volatile u8 cursor_end;
+ volatile u8 h_blank_start;
+ volatile u8 h_blank_end;
+ volatile u8 h_sync_start;
+ volatile u8 h_sync_end;
+ volatile u8 comp_sync_end;
+ volatile u8 v_blank_start_high;
+ volatile u8 v_blank_start_low;
+ volatile u8 v_blank_end;
+ volatile u8 v_sync_start;
+ volatile u8 v_sync_end;
+ volatile u8 xfer_holdoff_start;
+ volatile u8 xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK 0x70
+#define BWTWO_SR_1600_1280 0x50
+#define BWTWO_SR_1152_900_76_A 0x40
+#define BWTWO_SR_1152_900_76_B 0x60
+#define BWTWO_SR_ID_MASK 0x0f
+#define BWTWO_SR_ID_MONO 0x02
+#define BWTWO_SR_ID_MONO_ECL 0x03
+#define BWTWO_SR_ID_MSYNC 0x04
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS 0x80
+#define BWTWO_CTL_ENABLE_VIDEO 0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK 0x0C
+#define BWTWO_CTL_DIVISOR_MASK 0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT 0x80
+#define BWTWO_STAT_MSENSE_MASK 0x70
+#define BWTWO_STAT_ID_MASK 0x0f
+
+static struct sbus_mmap_map bw2_mmap_map[] = {
+ { 0, 0, SBUS_MMAP_FBSIZE(1) },
+ { 0, 0, 0 }
+};
+
+static void bw2_blank (struct fb_info_sbusfb *fb)
+{
+ fb->s.bw2.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_unblank (struct fb_info_sbusfb *fb)
+{
+ fb->s.bw2.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+ p->screen_base += ((y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin)) >> 3;
+}
+
+static u8 bw2regs_1600[] __initdata = {
+ 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
+ 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
+ 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x21, 0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+ 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
+ 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
+ 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
+ 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+ 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
+ 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x24, 0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
+{
+ struct fb_fix_screeninfo *fix = &fb->fix;
+ struct display *disp = &fb->disp;
+ struct fbtype *type = &fb->type;
+#ifdef CONFIG_SUN4
+ unsigned long phys = SUN4_300_BWTWO_PHYSADDR;
+#else
+ unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+#endif
+
+#ifndef FBCON_HAS_MFB
+ return NULL;
+#endif
+
+ if (!fb->s.bw2.regs) {
+ fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0,
+ sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0);
+ if (!prom_getbool(fb->prom_node, "width")) {
+ /* Ugh, broken PROM didn't initialize us.
+ * Let's deal with this ourselves.
+ */
+ u8 status, mon;
+ u8 *p;
+ int sizechange = 0;
+
+ status = fb->s.bw2.regs->status;
+ mon = status & BWTWO_SR_RES_MASK;
+ switch (status & BWTWO_SR_ID_MASK) {
+ case BWTWO_SR_ID_MONO_ECL:
+ if (mon == BWTWO_SR_1600_1280) {
+ p = bw2regs_1600;
+ fb->type.fb_width = 1600;
+ fb->type.fb_height = 1280;
+ sizechange = 1;
+ } else
+ p = bw2regs_ecl;
+ break;
+ case BWTWO_SR_ID_MONO:
+ p = bw2regs_analog;
+ break;
+ case BWTWO_SR_ID_MSYNC:
+ if (mon == BWTWO_SR_1152_900_76_A ||
+ mon == BWTWO_SR_1152_900_76_B)
+ p = bw2regs_76hz;
+ else
+ p = bw2regs_66hz;
+ break;
+ default:
+ prom_printf("bw2: can't handle SR %02x\n",
+ status);
+ prom_halt();
+ return NULL; /* fool gcc. */
+ }
+ for ( ; *p; p += 2)
+ ((u8 *)fb->s.bw2.regs)[p[0]] = p[1];
+ }
+ }
+
+ strcpy(fb->info.modename, "BWtwo");
+ strcpy(fix->id, "BWtwo");
+ fix->line_length = fb->var.xres_virtual>>3;
+
+ disp->scrollmode = SCROLL_YREDRAW;
+ if (!disp->screen_base)
+ disp->screen_base = (char *)sparc_alloc_io(phys, 0,
+ type->fb_size, "bw2_ram", fb->iospace, 0);
+ disp->screen_base += (fix->line_length * fb->y_margin + fb->x_margin) >> 3;
+ fb->dispsw = fbcon_mfb;
+ fix->visual = FB_VISUAL_MONO01;
+
+ fb->blank = bw2_blank;
+ fb->unblank = bw2_unblank;
+ fb->margins = bw2_margins;
+
+ fb->physbase = phys;
+ fb->mmap_map = bw2_mmap_map;
+
+#ifdef __sparc_v9__
+ sprintf(idstring, "bwtwo at %016lx", phys);
+#else
+ sprintf(idstring, "bwtwo at %x.%08lx", fb->iospace, phys);
+#endif
+
+ return idstring;
+}
-/* $Id: cgsixfb.c,v 1.4 1998/07/21 10:36:53 jj Exp $
+/* $Id: cgsixfb.c,v 1.7 1998/07/22 12:44:59 jj Exp $
* cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
do {
i = fbc->s;
} while (i & 0x10000000);
- fbc->fg = attr_bg_col_ec(conp);
- fbc->bg = attr_bg_col_ec(conp);
+ fbc->fg = attr_bgcol_ec(p,conp);
+ fbc->bg = attr_bgcol_ec(p,conp);
fbc->pixelm = ~(0);
fbc->alu = 0xea80ff00;
fbc->s = 0;
} while (i < 0 && (i & 0x20000000));
}
-static void cg6_fill(struct fb_info_sbusfb *fb, int s,
+static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
int count, unsigned short *boxes)
{
int i;
do {
i = fbc->s;
} while (i & 0x10000000);
- fbc->fg = attr_bg_col(s);
- fbc->bg = attr_bg_col(s);
+ fbc->fg = attr_bgcol(p,s);
+ fbc->bg = attr_bgcol(p,s);
fbc->pixelm = ~(0);
fbc->alu = 0xea80ff00;
fbc->s = 0;
if (p->fontheightlog) {
y = fb->y_margin + (yy << p->fontheightlog);
- i = ((c & 0xff) << p->fontheightlog);
+ i = ((c & p->charmask) << p->fontheightlog);
} else {
y = fb->y_margin + (yy * p->fontheight);
- i = (c & 0xff) * p->fontheight;
+ i = (c & p->charmask) * p->fontheight;
}
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ fd = p->fontdata + i;
+ x = fb->x_margin + xx * 8;
+#else
if (p->fontwidth <= 8)
fd = p->fontdata + i;
else
x = fb->x_margin + (xx << p->fontwidthlog);
else
x = fb->x_margin + (xx * p->fontwidth);
+#endif
do {
i = fbc->s;
} while (i & 0x10000000);
- fbc->fg = attr_fg_col(c);
- fbc->bg = attr_bg_col(c);
+ fbc->fg = attr_fgcol(p,c);
+ fbc->bg = attr_bgcol(p,c);
fbc->mode = 0x140000;
fbc->alu = 0xe880fc30;
fbc->pixelm = ~(0);
fbc->x0 = x;
fbc->x1 = x + p->fontwidth - 1;
fbc->y0 = y;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
for (i = 0; i < p->fontheight; i++)
fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
for (i = 0; i < p->fontheight; i++) {
fbc->font = *(u16 *)fd << 16;
fd += 2;
}
}
+#endif
}
static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
do {
i = fbc->s;
} while (i & 0x10000000);
- fbc->fg = attr_fg_col(*s);
- fbc->bg = attr_bg_col(*s);
+ fbc->fg = attr_fgcol(p,*s);
+ fbc->bg = attr_bgcol(p,*s);
fbc->mode = 0x140000;
fbc->alu = 0xe880fc30;
fbc->pixelm = ~(0);
fbc->pm = 0xff;
x = fb->x_margin;
y = fb->y_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ x += xx * 8;
+#else
if (p->fontwidthlog)
x += (xx << p->fontwidthlog);
else
x += xx * p->fontwidth;
+#endif
if (p->fontheightlog)
y += (yy << p->fontheightlog);
else
y += (yy * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
while (count >= 4) {
count -= 4;
fbc->incx = 0;
fbc->x1 = (x += 4 * p->fontwidth) - 1;
fbc->y0 = y;
if (p->fontheightlog) {
- fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+ fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
} else {
- fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+ fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth == 8) {
+#endif
for (i = 0; i < p->fontheight; i++)
fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
<< 8)) << 8)) << 8);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
for (i = 0; i < p->fontheight; i++)
fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
fbc->x1 = (x += 2 * p->fontwidth) - 1;
fbc->y0 = y;
if (p->fontheightlog) {
- fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
- fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+ fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+ fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
} else {
- fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
- fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+ fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+ fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
}
for (i = 0; i < p->fontheight; i++) {
fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
fd1 += 2; fd2 += 2;
}
}
+#endif
}
while (count) {
count--;
fbc->x1 = (x += p->fontwidth) - 1;
fbc->y0 = y;
if (p->fontheightlog)
- i = ((*s++ & 0xff) << p->fontheightlog);
+ i = ((*s++ & p->charmask) << p->fontheightlog);
else
- i = ((*s++ & 0xff) * p->fontheight);
+ i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
fd1 = p->fontdata + i;
for (i = 0; i < p->fontheight; i++)
fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
fd1 = p->fontdata + (i << 1);
for (i = 0; i < p->fontheight; i++) {
fd1 += 2;
}
}
+#endif
}
}
static void cg6_restore_palette (struct fb_info_sbusfb *fb)
{
struct bt_regs *bt = fb->s.cg6.bt;
- int i;
bt->addr = 0;
bt->color_map = 0xffffffff;
strcpy(fb->info.modename, "CGsix");
strcpy(fix->id, "CGsix");
- fix->smem_start = (char *)phys + CG6_RAM_OFFSET;
fix->line_length = fb->var.xres_virtual;
- fix->mmio_start = (char *)phys + CG6_FBC_OFFSET;
- fix->mmio_len = PAGE_SIZE;
fix->accel = FB_ACCEL_SUN_CGSIX;
var->accel_flags = FB_ACCELF_TEXT;
default: p = "i386"; break;
}
- sprintf(idstring, "cgsix at %02x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys,
+ sprintf(idstring,
+#ifdef __sparc_v9__
+ "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys,
+#else
+ "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys,
+#endif
(fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK,
p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK);
--- /dev/null
+/* $Id: cgthreefb.c,v 1.1 1998/07/21 14:50:47 jj Exp $
+ * cgthreefb.c: CGthree frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS 0x80
+#define CG3_CR_ENABLE_VIDEO 0x40
+#define CG3_CR_ENABLE_TIMING 0x20
+#define CG3_CR_ENABLE_CURCMP 0x10
+#define CG3_CR_XTAL_MASK 0x0c
+#define CG3_CR_DIVISOR_MASK 0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_RES_MASK 0x70
+#define CG3_SR_1152_900_76_A 0x40
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_MASK 0x0f
+#define CG3_SR_ID_COLOR 0x01
+#define CG3_SR_ID_MONO 0x02
+#define CG3_SR_ID_MONO_ECL 0x03
+
+enum cg3_type {
+ CG3_AT_66HZ = 0,
+ CG3_AT_76HZ,
+ CG3_RDI
+};
+
+struct cg3_regs {
+ struct bt_regs cmap;
+ volatile u8 control;
+ volatile u8 status;
+ volatile u8 cursor_start;
+ volatile u8 cursor_end;
+ volatile u8 h_blank_start;
+ volatile u8 h_blank_end;
+ volatile u8 h_sync_start;
+ volatile u8 h_sync_end;
+ volatile u8 comp_sync_end;
+ volatile u8 v_blank_start_high;
+ volatile u8 v_blank_start_low;
+ volatile u8 v_blank_end;
+ volatile u8 v_sync_start;
+ volatile u8 v_sync_end;
+ volatile u8 xfer_holdoff_start;
+ volatile u8 xfer_holdoff_end;
+};
+
+/* Offset of interesting structures in the OBIO space */
+#define CG3_REGS_OFFSET 0x400000
+#define CG3_RAM_OFFSET 0x800000
+
+static struct sbus_mmap_map cg3_mmap_map[] = {
+ { CG3_MMAP_OFFSET, CG3_RAM_OFFSET, SBUS_MMAP_FBSIZE(1) },
+ { 0, 0, 0 }
+};
+
+/* The cg3 palette is loaded with 4 color values at each time */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
+
+static void cg3_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+ struct bt_regs *bt = &fb->s.cg3.regs->cmap;
+ u32 *i;
+ int steps;
+
+ i = (((u32 *)fb->color_map) + D4M3(index));
+ steps = D4M3(index+count-1) - D4M3(index)+3;
+
+ *(volatile u8 *)&bt->addr = (u8)D4M4(index);
+ while (steps--)
+ bt->color_map = *i++;
+}
+
+static void cg3_blank (struct fb_info_sbusfb *fb)
+{
+ fb->s.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_unblank (struct fb_info_sbusfb *fb)
+{
+ fb->s.cg3.regs->control |= CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+ p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */
+ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
+ 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x20, 0
+};
+
+static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */
+ 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
+ 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
+ 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x24, 0
+};
+
+static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */
+ 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
+ 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
+ 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
+ 0x10, 0x22, 0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+ cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+ 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb))
+{
+ struct fb_fix_screeninfo *fix = &fb->fix;
+ struct display *disp = &fb->disp;
+ struct fbtype *type = &fb->type;
+ unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+ int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
+
+#ifndef FBCON_HAS_CFB8
+ return NULL;
+#endif
+
+ if (!fb->s.cg3.regs) {
+ fb->s.cg3.regs = (struct cg3_regs *)sparc_alloc_io(phys+CG3_REGS_OFFSET, 0,
+ sizeof(struct cg3_regs), "cg3_regs", fb->iospace, 0);
+ if (cgRDI) {
+ char buffer[40];
+ char *p;
+ int ww, hh;
+
+ *buffer = 0;
+ prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer));
+ if (*buffer) {
+ ww = simple_strtoul (buffer, &p, 10);
+ if (ww && *p == 'x') {
+ hh = simple_strtoul (p + 1, &p, 10);
+ if (hh && *p == '-') {
+ if (type->fb_width != ww || type->fb_height != hh) {
+ type->fb_width = ww;
+ type->fb_height = hh;
+ return SBUSFBINIT_SIZECHANGE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ strcpy(fb->info.modename, "CGthree");
+ strcpy(fix->id, "CGthree");
+ fix->line_length = fb->var.xres_virtual;
+
+ disp->scrollmode = SCROLL_YREDRAW;
+ if (!disp->screen_base)
+ disp->screen_base = (char *)sparc_alloc_io(phys+CG3_RAM_OFFSET, 0,
+ type->fb_size, "cg3_ram", fb->iospace, 0);
+ disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+ fb->dispsw = fbcon_cfb8;
+
+ fb->margins = cg3_margins;
+ fb->loadcmap = cg3_loadcmap;
+ fb->blank = cg3_blank;
+ fb->unblank = cg3_unblank;
+
+ fb->physbase = phys;
+ fb->mmap_map = cg3_mmap_map;
+
+#ifdef __sparc_v9__
+ sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
+#else
+ sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys);
+#endif
+
+ if (!prom_getbool(fb->prom_node, "width")) {
+ /* Ugh, broken PROM didn't initialize us.
+ * Let's deal with this ourselves.
+ */
+ enum cg3_type type;
+ u8 *p;
+
+ if (cgRDI)
+ type = CG3_RDI;
+ else {
+ u8 status = fb->s.cg3.regs->status, mon;
+ if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+ mon = status & CG3_SR_RES_MASK;
+ if (mon == CG3_SR_1152_900_76_A ||
+ mon == CG3_SR_1152_900_76_B)
+ type = CG3_AT_76HZ;
+ else
+ type = CG3_AT_66HZ;
+ } else {
+ prom_printf("cgthree: can't handle SR %02x\n",
+ status);
+ prom_halt();
+ return NULL; /* fool gcc. */
+ }
+ }
+
+ for (p = cg3_regvals[type]; *p; p += 2)
+ ((u8 *)fb->s.cg3.regs)[p[0]] = p[1];
+
+ for (p = cg3_dacvals; *p; p += 2) {
+ *(volatile u8 *)&fb->s.cg3.regs->cmap.addr = p[0];
+ *(volatile u8 *)&fb->s.cg3.regs->cmap.control = p[1];
+ }
+ }
+
+ return idstring;
+}
--- /dev/null
+/*
+ * Based on retz3fb.c and clgen.c
+ */
+
+#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/zorro.h>
+#include <linux/init.h>
+#include <asm/amigahw.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include "fbcon.h"
+
+#include "fbcon.h"
+#include "fbcon-mfb.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
+#include "fbcon-cfb32.h"
+
+#include "clgenfb.h"
+
+#define CLGEN_VERSION "1.4 ?"
+/* #define DEBUG if(1) */
+#define DEBUG if(0)
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+/* zorro IDs */
+#define ZORRO_PROD_HELFRICH_SD64_RAM 0x08930A00
+#define ZORRO_PROD_HELFRICH_SD64_REG 0x08930B00
+#define ZORRO_PROD_HELFRICH_PICCOLO_RAM 0x08930500
+#define ZORRO_PROD_HELFRICH_PICCOLO_REG 0x08930600
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM 0x08770B00
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG 0x08770C00
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM 0x08910200
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG 0x08910100
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 0x08771800
+
+/* board types */
+#define BT_NONE 0
+#define BT_SD64 1
+#define BT_PICCOLO 2
+#define BT_PICASSO 3
+#define BT_SPECTRUM 4
+#define BT_PICASSO4 5
+
+#define MAX_NUM_BOARDS 7
+
+#define TRUE 1
+#define FALSE 0
+
+struct clgenfb_par
+{
+ struct fb_var_screeninfo var;
+
+ __u32 line_length; /* in BYTES! */
+ __u32 visual;
+ __u32 type;
+
+ long freq;
+ long nom;
+ long den;
+ long div;
+
+ long HorizRes; /* The x resolution in pixel */
+ long HorizTotal;
+ long HorizDispEnd;
+ long HorizBlankStart;
+ long HorizBlankEnd;
+ long HorizSyncStart;
+ long HorizSyncEnd;
+
+ long VertRes; /* the physical y resolution in scanlines */
+ long VertTotal;
+ long VertDispEnd;
+ long VertSyncStart;
+ long VertSyncEnd;
+ long VertBlankStart;
+ long VertBlankEnd;
+};
+
+/* info about board */
+struct clgenfb_info
+{
+ struct fb_info_gen gen;
+
+ int keyRAM; /* RAM, REG zorro board keys */
+ int keyREG;
+ unsigned long fbmem;
+ volatile unsigned char *regs;
+ unsigned long mem;
+ unsigned long size;
+ int btype;
+ int smallboard;
+ unsigned char SFR; /* Shadow of special function register */
+
+ struct clgenfb_par currentmode;
+};
+
+static struct display disp;
+
+static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */
+static struct clgenfb_info *fb_info=NULL; /* pointer to current board */
+
+/*
+ * Predefined Video Modes
+ */
+
+static struct fb_videomode clgenfb_predefined[] __initdata =
+{
+ { "Autodetect", /* autodetect mode */
+ { 0 }
+ },
+
+ { "640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
+ {
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, 40000, 32, 32, 33, 10, 96, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ },
+
+ /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
+ /*
+ Modeline from XF86Config:
+ Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
+ */
+ {
+ "1024x768",
+ {
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }
+};
+
+#define NUM_TOTAL_MODES arraysize(clgenfb_predefined)
+static struct fb_var_screeninfo clgenfb_default;
+
+/*
+ * Frame Buffer Name
+ */
+
+static char clgenfb_name[16] = "CLgen";
+
+/****************************************************************************/
+/**** BEGIN PROTOTYPES ******************************************************/
+
+/*--- Interface used by the world ------------------------------------------*/
+void clgenfb_init(void);
+void clgenfb_setup(char *options, int *ints);
+int clgenfb_open(struct fb_info *info, int user);
+int clgenfb_release(struct fb_info *info, int user);
+int clgenfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+/* function table of the above functions */
+static struct fb_ops clgenfb_ops =
+{
+ clgenfb_open,
+ clgenfb_release,
+ fbgen_get_fix, /* using the generic functions */
+ fbgen_get_var, /* makes things much easier... */
+ fbgen_set_var,
+ fbgen_get_cmap,
+ fbgen_set_cmap,
+ fbgen_pan_display,
+ clgenfb_ioctl,
+ NULL
+};
+
+/*--- Hardware Specific Routines -------------------------------------------*/
+static void clgen_detect(void);
+static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+ struct fb_info_gen *info);
+static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+ struct fb_info_gen *info);
+static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+ struct fb_info_gen *info);
+static void clgen_get_par(void *par, struct fb_info_gen *info);
+static void clgen_set_par(const void *par, struct fb_info_gen *info);
+static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *info);
+static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info);
+static int clgen_pan_display(const struct fb_var_screeninfo *var,
+ struct fb_info_gen *info);
+static int clgen_blank(int blank_mode, struct fb_info_gen *info);
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+ struct fb_info_gen *info);
+
+/* function table of the above functions */
+static struct fbgen_hwswitch clgen_hwswitch =
+{
+ clgen_detect,
+ clgen_encode_fix,
+ clgen_decode_var,
+ clgen_encode_var,
+ clgen_get_par,
+ clgen_set_par,
+ clgen_getcolreg,
+ clgen_setcolreg,
+ clgen_pan_display,
+ clgen_blank,
+ clgen_get_dispsw
+};
+
+/* Text console acceleration */
+
+#ifdef FBCON_HAS_CFB8
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx,
+ int dy, int dx, int height, int width);
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width);
+
+static struct display_switch fbcon_clgen_8 = {
+ fbcon_cfb8_setup,
+ fbcon_clgen8_bmove,
+ fbcon_clgen8_clear,
+ fbcon_cfb8_putc,
+ fbcon_cfb8_putcs,
+ fbcon_cfb8_revc,
+ NULL,
+ NULL,
+ fbcon_cfb8_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+
+
+/*--- Internal routines ----------------------------------------------------*/
+static void init_vgachip(void);
+static void switch_monitor(int on);
+
+static void WGen( int regnum, unsigned char val );
+static unsigned char RGen( int regnum );
+static void WSeq( unsigned char regnum, unsigned char val );
+static unsigned char RSeq( unsigned char regnum );
+static void WCrt( unsigned char regnum, unsigned char val );
+static unsigned char RCrt( unsigned char regnum );
+static void WGfx( unsigned char regnum, unsigned char val );
+static unsigned char RGfx( unsigned char regnum );
+static void WAttr( unsigned char regnum, unsigned char val );
+static void AttrOn( void );
+static unsigned char RAttr( unsigned char regnum );
+static void WHDR( unsigned char val );
+static unsigned char RHDR( void );
+static void WSFR( unsigned char val );
+static void WSFR2( unsigned char val );
+static void WClut( unsigned char regnum, unsigned char red,
+ unsigned char green,
+ unsigned char blue );
+static void RClut( unsigned char regnum, unsigned char *red,
+ unsigned char *green,
+ unsigned char *blue );
+static void clgen_WaitBLT( void );
+static void clgen_BitBLT (u_short curx, u_short cury,
+ u_short destx, u_short desty,
+ u_short width, u_short height,
+ u_short line_length);
+static void clgen_RectFill (u_short x, u_short y,
+ u_short width, u_short height,
+ u_char color, u_short line_length);
+
+static void bestclock(long freq, long *best,
+ long *nom, long *den,
+ long *div, long maxfreq);
+
+/*** END PROTOTYPES ********************************************************/
+/*****************************************************************************/
+/*** BEGIN Interface Used by the World ***************************************/
+
+static int opencount = 0;
+
+/*--- Open /dev/fbx ---------------------------------------------------------*/
+int clgenfb_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ if (opencount++ == 0) switch_monitor(1);
+ return 0;
+}
+
+/*--- Close /dev/fbx --------------------------------------------------------*/
+int clgenfb_release(struct fb_info *info, int user)
+{
+ if (--opencount == 0) switch_monitor(0);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*--- handle /dev/fbx ioctl calls ------------------------------------------*/
+int clgenfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ printk(">clgenfb_ioctl()\n");
+ /* Nothing exciting here... */
+ printk("<clgenfb_ioctl()\n");
+ return -EINVAL;
+}
+
+/**** END Interface used by the World *************************************/
+/****************************************************************************/
+/**** BEGIN Hardware specific Routines **************************************/
+
+static void clgen_detect(void)
+{
+ printk(">clgen_detect()\n");
+ printk("<clgen_detect()\n");
+}
+
+static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+ struct fb_info_gen *info)
+{
+ struct clgenfb_par *_par = (struct clgenfb_par*) par;
+ struct clgenfb_info *_info = (struct clgenfb_info*)info;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, clgenfb_name);
+
+ fix->smem_start = (char*)_info->fbmem;
+
+ /* monochrome: only 1 memory plane */
+ /* 8 bit and above: Use whole memory area */
+ fix->smem_len = _par->var.bits_per_pixel == 1 ? _info->size / 4
+ : _info->size;
+ fix->type = _par->type;
+ fix->type_aux = 0;
+ fix->visual = _par->visual;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = _par->line_length;
+ fix->mmio_start = (char *)_info->regs;
+ fix->mmio_len = 0x10000;
+ fix->accel = FB_ACCEL_NONE;
+
+ return 0;
+}
+
+static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+ struct fb_info_gen *info)
+{
+ long freq;
+ int xres, hfront, hsync, hback;
+ int yres, vfront, vsync, vback;
+ int nom,den; /* translyting from pixels->bytes */
+ int i;
+ static struct
+ {
+ int xres,yres;
+ }
+ modes[] = { {1600,1280}, {1280,1024}, {1024,768},
+ {800,600}, {640,480}, {-1,-1} };
+
+ struct clgenfb_par *_par = (struct clgenfb_par *)par;
+
+ fb_info = (struct clgenfb_info*)info;
+ printk("clgen_decode_var()\n");
+
+ printk("Requested: %dx%dx%d\n", var->xres,var->yres,var->bits_per_pixel);
+ printk(" virtual: %dx%d\n", var->xres_virtual,var->yres_virtual);
+ printk(" offset: (%d,%d)\n", var->xoffset, var->yoffset);
+ printk("grayscale: %d\n", var->grayscale);
+#if 0
+ printk(" activate: 0x%x\n", var->activate);
+ printk(" pixclock: %d\n", var->pixclock);
+ printk(" htiming: %d;%d %d\n", var->left_margin,var->right_margin,var->hsync_len);
+ printk(" vtiming: %d;%d %d\n", var->upper_margin,var->lower_margin,var->vsync_len);
+ printk(" sync: 0x%x\n", var->sync);
+ printk(" vmode: 0x%x\n", var->vmode);
+#endif
+
+ _par->var = *var;
+
+ switch (var->bits_per_pixel)
+ {
+ case 1: nom = 4; den = 8; break; /* 8 pixel per byte, only 1/4th of mem usable */
+ case 8: nom = 1; den = 1; break; /* 1 pixel == 1 byte */
+ case 16: nom = 2; den = 1; break; /* 2 bytes per pixel */
+ case 24: nom = 3; den = 1; break; /* 3 bytes per pixel */
+ case 32: nom = 4; den = 1; break; /* 4 bytes per pixel */
+ default:
+ printk("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if (_par->var.xres*nom/den * _par->var.yres > fb_info->size)
+ {
+ printk("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* use highest possible virtual resolution */
+ if (_par->var.xres_virtual == -1 &&
+ _par->var.xres_virtual == -1)
+ {
+ printk("clgen: using maximum available virtual resolution\n");
+ for (i=0; modes[i].xres != -1; i++)
+ {
+ if (modes[i].xres*nom/den * modes[i].yres < fb_info->size/2)
+ break;
+ }
+ if (modes[i].xres == -1)
+ {
+ printk("clgen: could not find a virtual resolution that fits into video memory!!\n");
+ return -EINVAL;
+ }
+ _par->var.xres_virtual = modes[i].xres;
+ _par->var.yres_virtual = modes[i].yres;
+
+ printk("clgen: virtual resolution set to maximum of %dx%d\n",
+ _par->var.xres_virtual, _par->var.yres_virtual);
+ }
+ else if (_par->var.xres_virtual == -1)
+ {
+ }
+ else if (_par->var.yres_virtual == -1)
+ {
+ }
+
+ if (_par->var.xoffset < 0) _par->var.xoffset = 0;
+ if (_par->var.yoffset < 0) _par->var.yoffset = 0;
+
+ /* truncate xoffset and yoffset to maximum if too high */
+ if (_par->var.xoffset > _par->var.xres_virtual-_par->var.xres)
+ _par->var.xoffset = _par->var.xres_virtual-_par->var.xres -1;
+
+ if (_par->var.yoffset > _par->var.yres_virtual-_par->var.yres)
+ _par->var.yoffset = _par->var.yres_virtual-_par->var.yres -1;
+
+ switch (var->bits_per_pixel)
+ {
+ case 1:
+ _par->line_length = _par->var.xres_virtual / 8;
+ _par->visual = FB_VISUAL_MONO10;
+ break;
+
+ case 8:
+ _par->line_length = _par->var.xres_virtual;
+ _par->visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+
+ case 16:
+ _par->line_length = _par->var.xres_virtual * 2;
+ _par->visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+
+ case 24:
+ _par->line_length = _par->var.xres_virtual * 3;
+ _par->visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+
+ case 32:
+ _par->line_length = _par->var.xres_virtual * 4;
+ _par->visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+ }
+ _par->type = FB_TYPE_PACKED_PIXELS;
+
+ /* convert from ps to kHz */
+ freq = 1000000000 / var->pixclock;
+
+ DEBUG printk("desired pixclock: %ld kHz\n", freq);
+
+ /* the SD64/P4 have a higher max. videoclock */
+ bestclock(freq, &_par->freq, &_par->nom, &_par->den, &_par->div,
+ fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4
+ ? 140000 : 90000);
+
+ DEBUG printk("Best possible values for given frequency: best: %ld kHz nom: %ld den: %ld div: %ld\n",
+ _par->freq, _par->nom, _par->den, _par->div);
+
+ xres = _par->var.xres;
+ hfront = _par->var.right_margin;
+ hsync = _par->var.hsync_len;
+ hback = _par->var.left_margin;
+
+ yres = _par->var.yres;
+ vfront = _par->var.lower_margin;
+ vsync = _par->var.vsync_len;
+ vback = _par->var.upper_margin;
+
+ if (_par->var.vmode & FB_VMODE_DOUBLE)
+ {
+ yres *= 2;
+ vfront *= 2;
+ vsync *= 2;
+ vback *= 2;
+ }
+ else if (_par->var.vmode & FB_VMODE_INTERLACED)
+ {
+ yres = ++yres / 2;
+ vfront = ++vfront / 2;
+ vsync = ++vsync / 2;
+ vback = ++vback / 2;
+ }
+
+ _par->HorizRes = xres;
+ _par->HorizTotal = (xres + hfront + hsync + hback)/8 - 5;
+ _par->HorizDispEnd = xres/8 - 1;
+ _par->HorizBlankStart = xres/8;
+ _par->HorizBlankEnd = _par->HorizTotal+5; /* does not count with "-5" */
+ _par->HorizSyncStart = (xres + hfront)/8 + 1;
+ _par->HorizSyncEnd = (xres + hfront + hsync)/8 + 1;
+
+ _par->VertRes = yres;
+ _par->VertTotal = yres + vfront + vsync + vback -2;
+ _par->VertDispEnd = yres - 1;
+ _par->VertBlankStart = yres;
+ _par->VertBlankEnd = _par->VertTotal;
+ _par->VertSyncStart = yres + vfront - 1;
+ _par->VertSyncEnd = yres + vfront + vsync - 1;
+
+ if (_par->VertTotal >= 1024)
+ {
+ printk(KERN_WARNING "clgen: ERROR: VerticalTotal >= 1024; special treatment required! (TODO)\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+ struct fb_info_gen *info)
+{
+ *var = ((struct clgenfb_par*)par)->var;
+ return 0;
+}
+
+/* get current video mode */
+static void clgen_get_par(void *par, struct fb_info_gen *info)
+{
+ struct clgenfb_par *_par = (struct clgenfb_par*)par;
+ struct clgenfb_info*_info = (struct clgenfb_info*)fb_info;
+
+ *_par = _info->currentmode;
+}
+
+/*************************************************************************
+ clgen_set_par()
+
+ actually writes the values for a new video mode into the hardware,
+**************************************************************************/
+static void clgen_set_par(const void *par, struct fb_info_gen *info)
+{
+ unsigned char tmp;
+ int offset = 0;
+ struct clgenfb_par *_par = (struct clgenfb_par*)par;
+
+ printk(KERN_INFO">clgen_set_par()\n");
+ printk(KERN_INFO"Requested mode: %dx%dx%d\n",
+ _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
+ printk(KERN_INFO"pixclock: %d\n", _par->var.pixclock);
+
+ fb_info = (struct clgenfb_info *)info;
+
+ /* unlock register CRT0..CRT7 */
+ WCrt(CRT11, 0x20); /* previously: 0x00) */
+
+ /* if DEBUG is set, all parameters get output before writing */
+ DEBUG printk("CRT0: %ld\n", _par->HorizTotal);
+ WCrt(CRT0, _par->HorizTotal);
+
+ DEBUG printk("CRT1: %ld\n", _par->HorizDispEnd);
+ WCrt(CRT1, _par->HorizDispEnd);
+
+ DEBUG printk("CRT2: %ld\n", _par->HorizBlankStart);
+ WCrt(CRT2, _par->HorizBlankStart);
+
+ DEBUG printk("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /* + 128: Compatible read */
+ WCrt(CRT3, 128 + (_par->HorizBlankEnd % 32));
+
+ DEBUG printk("CRT4: %ld\n", _par->HorizSyncStart);
+ WCrt(CRT4, _par->HorizSyncStart);
+
+ tmp = _par->HorizSyncEnd % 32;
+ if (_par->HorizBlankEnd & 32)
+ tmp += 128;
+ DEBUG printk("CRT5: %d\n", tmp);
+ WCrt(CRT5, tmp);
+
+ DEBUG printk("CRT6: %ld\n", _par->VertTotal & 0xff);
+ WCrt(CRT6, (_par->VertTotal & 0xff));
+
+ tmp = 16; /* LineCompare bit #9 */
+ if (_par->VertTotal & 256) tmp |= 1;
+ if (_par->VertDispEnd & 256) tmp |= 2;
+ if (_par->VertSyncStart & 256) tmp |= 4;
+ if (_par->VertBlankStart & 256) tmp |= 8;
+ if (_par->VertTotal & 512) tmp |= 32;
+ if (_par->VertDispEnd & 512) tmp |= 64;
+ if (_par->VertSyncStart & 512) tmp |= 128;
+ DEBUG printk("CRT7: %d\n", tmp);
+ WCrt(CRT7, tmp);
+
+ tmp = 0x40; /* LineCompare bit #8 */
+ if (_par->VertBlankStart & 512) tmp |= 0x20;
+ if (_par->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80;
+ DEBUG printk("CRT9: %d\n", tmp);
+ WCrt(CRT9, tmp);
+
+ DEBUG printk("CRT10: %ld\n", _par->VertSyncStart & 0xff);
+ WCrt(CRT10, (_par->VertSyncStart & 0xff));
+
+ DEBUG printk("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
+ WCrt(CRT11, (_par->VertSyncEnd % 16 + 64 + 32));
+
+ DEBUG printk("CRT12: %ld\n", _par->VertDispEnd & 0xff);
+ WCrt(CRT12, (_par->VertDispEnd & 0xff));
+
+ DEBUG printk("CRT15: %ld\n", _par->VertBlankStart & 0xff);
+ WCrt(CRT15, (_par->VertBlankStart & 0xff));
+
+ DEBUG printk("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
+ WCrt(CRT16, (_par->VertBlankEnd & 0xff));
+
+ DEBUG printk("CRT18: 0xff\n");
+ WCrt(CRT18, 0xff);
+
+ tmp = 0;
+ if (_par->var.vmode & FB_VMODE_INTERLACED) tmp |= 1;
+ if (_par->HorizBlankEnd & 64) tmp |= 16;
+ if (_par->HorizBlankEnd & 128) tmp |= 32;
+ if (_par->VertBlankEnd & 256) tmp |= 64;
+ if (_par->VertBlankEnd & 512) tmp |= 128;
+
+ DEBUG printk("CRT1a: %d\n", tmp);
+ WCrt(CRT1A, tmp);
+
+ /* set VCLK0 */
+ /* hardware RefClock: 14.31818 MHz */
+ /* formula: VClk = (OSC * N) / (D * (1+P)) */
+ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
+
+ WSeq(SEQRB, _par->nom);
+ tmp = _par->den<<1;
+ if (_par->div != 0) tmp |= 1;
+
+ if (fb_info->btype == BT_SD64)
+ tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+
+ WSeq(SEQR1B, tmp);
+
+ WCrt(CRT17, 0xc3); /* mode control: CRTC enable, ROTATE(?), 16bit address wrap, no compat. */
+
+/* HAEH? WCrt(CRT11, 0x20); * previously: 0x00 unlock CRT0..CRT7 */
+
+ /* don't know if it would hurt to also program this if no interlaced */
+ /* mode is used, but I feel better this way.. :-) */
+ if (_par->var.vmode & FB_VMODE_INTERLACED)
+ WCrt(CRT19, _par->HorizTotal / 2);
+ else
+ WCrt(CRT19, 0x00); /* interlace control */
+
+ WSeq(SEQR3, 0);
+
+ /* adjust horizontal/vertical sync type (low/high) */
+ tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
+ if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40;
+ if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80;
+ WGen(MISC_W, tmp);
+
+ WCrt(CRT8, 0); /* Screen A Preset Row-Scan register */
+ WCrt(CRTA, 0); /* text cursor on and start line */
+ WCrt(CRTB, 31); /* text cursor end line */
+
+ /* programming for different color depths */
+ if (_par->var.bits_per_pixel == 1)
+ {
+ DEBUG printk(KERN_INFO "clgen: preparing for 1 bit deep display\n");
+#if 0
+ /* restore first 2 color registers for mono mode */
+ WClut( 0, 0x00, 0x00, 0x00); /* background: black */
+ WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */
+#endif
+ WGfx(GR5, 0); /* mode register */
+
+ /* Extended Sequencer Mode */
+ switch(fb_info->btype)
+ {
+ case BT_SD64:
+ /* setting the SEQRF on SD64 is not necessary (only during init) */
+ DEBUG printk(KERN_INFO "(for SD64)\n");
+ WSeq(SEQR7, 0xf0);
+ WSeq(SEQR1F, 0x1a); /* MCLK select */
+ break;
+
+ case BT_PICCOLO:
+ DEBUG printk(KERN_INFO "(for Piccolo)\n");
+ WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+ WSeq(SEQR1F, 0x22); /* ##vorher 1c MCLK select */
+ WSeq(SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+ break;
+
+ case BT_PICASSO:
+ DEBUG printk(KERN_INFO "(for Picasso)\n");
+ WSeq(SEQR7, 0x20);
+ WSeq(SEQR1F, 0x22); /* ##vorher 22 MCLK select */
+ WSeq(SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
+ break;
+
+ case BT_SPECTRUM:
+ DEBUG printk(KERN_INFO "(for Spectrum)\n");
+ WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+ WSeq(SEQR1F, 0x22); /* ##vorher 1c MCLK select */
+ WSeq(SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
+ break;
+
+ case BT_PICASSO4:
+ DEBUG printk(KERN_INFO "(for Picasso 4)\n");
+ WSeq(SEQR7, 0x20);
+/* WSeq(SEQR1F, 0x1c); */
+/* SEQRF not being set here... WSeq(SEQRF, 0xd0); */
+ break;
+
+ default:
+ printk(KERN_WARNING "clgen: unknown Board\n");
+ break;
+ }
+
+ WGen(M_3C6,0x01); /* pixel mask: pass-through for first plane */
+ WHDR(0); /* hidden dac reg: nothing special */
+ WSeq(SEQR4, 0x06); /* memory mode: odd/even, ext. memory */
+ WSeq(SEQR2, 0x01); /* plane mask: only write to first plane */
+ offset = _par->var.xres_virtual / 16;
+ }
+ else if (_par->var.bits_per_pixel == 8)
+ {
+ DEBUG printk(KERN_INFO "clgen: preparing for 8 bit deep display\n");
+ switch(fb_info->btype)
+ {
+ case BT_SD64:
+ WSeq(SEQR7, 0xf1); /* Extended Sequencer Mode: 256c col. mode */
+ WSeq(SEQR1F, 0x1d); /* MCLK select */
+ break;
+
+ case BT_PICCOLO:
+ WSeq(SEQR7, 0x81);
+ WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ break;
+
+ case BT_PICASSO:
+ WSeq(SEQR7, 0x21);
+ WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ break;
+
+ case BT_SPECTRUM:
+ WSeq(SEQR7, 0x81);
+ WSeq(SEQR1F, 0x22); /* ### vorher 1c MCLK select */
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ break;
+
+ case BT_PICASSO4:
+ WSeq(SEQR7, 0x21);
+ WSeq(SEQRF, 0xb8); /* ### INCOMPLETE!! */
+/* WSeq(SEQR1F, 0x1c); */
+ break;
+
+ default:
+ printk(KERN_WARNING "clgen: unknown Board\n");
+ break;
+ }
+
+ WGfx(GR5, 64); /* mode register: 256 color mode */
+ WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */
+ WHDR(0); /* hidden dac reg: nothing special */
+ WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */
+ WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */
+ offset = _par->var.xres_virtual / 8;
+ }
+ else if (_par->var.bits_per_pixel == 16)
+ {
+ DEBUG printk(KERN_INFO "clgen: preparing for 16 bit deep display\n");
+ switch(fb_info->btype)
+ {
+ case BT_SD64:
+ WSeq(SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
+ WSeq(SEQR1F, 0x1e); /* MCLK select */
+ break;
+
+ case BT_PICCOLO:
+ WSeq(SEQR7, 0x87);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_PICASSO:
+ WSeq(SEQR7, 0x27);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_SPECTRUM:
+ WSeq(SEQR7, 0x87);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_PICASSO4:
+ WSeq(SEQR7, 0x27);
+/* WSeq(SEQR1F, 0x1c); */
+ break;
+
+ default:
+ printk(KERN_WARNING "CLGEN: unknown Board\n");
+ break;
+ }
+
+ WGfx(GR5, 64); /* mode register: 256 color mode */
+ WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */
+ WHDR(0xa0); /* hidden dac reg: nothing special */
+ WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */
+ WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */
+ offset = _par->var.xres_virtual / 4;
+ }
+ else if (_par->var.bits_per_pixel == 32)
+ {
+ DEBUG printk(KERN_INFO "clgen: preparing for 24/32 bit deep display\n");
+ switch(fb_info->btype)
+ {
+ case BT_SD64:
+ WSeq(SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
+ WSeq(SEQR1F, 0x1e); /* MCLK select */
+ break;
+
+ case BT_PICCOLO:
+ WSeq(SEQR7, 0x85);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_PICASSO:
+ WSeq(SEQR7, 0x25);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_SPECTRUM:
+ WSeq(SEQR7, 0x85);
+ WSeq(SEQRF, 0xb0); /* Fast Page-Mode writes */
+ WSeq(SEQR1F, 0x22); /* MCLK select */
+ break;
+
+ case BT_PICASSO4:
+ WSeq(SEQR7, 0x25);
+/* WSeq(SEQR1F, 0x1c); */
+ break;
+
+ default:
+ printk(KERN_WARNING "clgen: unknown Board\n");
+ break;
+ }
+
+ WGfx(GR5, 64); /* mode register: 256 color mode */
+ WGen(M_3C6,0xff); /* pixel mask: pass-through all planes */
+ WHDR(0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
+ WSeq(SEQR4, 0x0a); /* memory mode: chain4, ext. memory */
+ WSeq(SEQR2, 0xff); /* plane mask: enable writing to all 4 planes */
+ offset = _par->var.xres_virtual / 4;
+ }
+ else
+ printk(KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
+ _par->var.bits_per_pixel);
+
+ WCrt(CRT13, offset & 0xff);
+ tmp = 0x22;
+ if (offset & 0x100) tmp |= 0x10; /* offset overflow bit */
+
+ WCrt(CRT1B,tmp); /* screen start addr #16-18, fastpagemode cycles */
+
+ if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4)
+ WCrt(CRT1D, 0x00); /* screen start address bit 19 */
+
+ WCrt(CRTE, 0); /* text cursor location high */
+ WCrt(CRTF, 0); /* text cursor location low */
+ WCrt(CRT14, 0); /* underline row scanline = at very bottom */
+
+ WAttr(AR10, 1); /* controller mode */
+ WAttr(AR11, 0); /* overscan (border) color */
+ WAttr(AR12, 15); /* color plane enable */
+ WAttr(AR33, 0); /* pixel panning */
+ WAttr(AR14, 0); /* color select */
+
+ /* [ EGS: SetOffset(); ] */
+ /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
+ AttrOn();
+
+ WGfx(GR0, 0); /* set/reset register */
+ WGfx(GR1, 0); /* set/reset enable */
+ WGfx(GR2, 0); /* color compare */
+ WGfx(GR3, 0); /* data rotate */
+ WGfx(GR4, 0); /* read map select */
+ WGfx(GR6, 1); /* miscellaneous register */
+ WGfx(GR7, 15); /* color don't care */
+ WGfx(GR8, 255); /* bit mask */
+
+ WSeq(SEQR12, 0x0); /* graphics cursor attributes: nothing special */
+
+ /* finally, turn on everything - turn off "FullBandwidth" bit */
+ /* also, set "DotClock%2" bit where requested */
+ tmp = 0x01;
+
+/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
+ if (var->vmode & FB_VMODE_CLOCK_HALVE)
+ tmp |= 0x08;
+*/
+
+ WSeq(SEQR1, tmp);
+ DEBUG printk("SEQR1: %d\n", tmp);
+
+#if 0
+ DEBUG printk(KERN_INFO "clgen: clearing display...");
+ clgen_RectFill(0, 0, _par->HorizRes, _par->VertRes, 0, _par->line_length);
+ clgen_WaitBLT();
+ DEBUG printk("done.\n");
+#endif
+
+ fb_info->currentmode = *_par;
+
+ printk("virtual offset: (%d,%d)\n", _par->var.xoffset,_par->var.yoffset);
+ /* pan to requested offset */
+ clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen*)fb_info);
+
+ DEBUG printk("<clgen_set_par()\n");
+ return;
+}
+
+static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *info)
+{
+ unsigned char bred, bgreen, bblue;
+
+ if (regno > 255 || regno < 0)
+ return (1);
+
+ fb_info = (struct clgenfb_info *)info;
+
+ RClut(regno, &bred, &bgreen, &bblue);
+
+ *red = (u_int)bred;
+ *green = (u_int)bgreen;
+ *blue = (u_int)bblue;
+ *transp = 0;
+ return (0);
+}
+
+static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ if (regno > 255 || regno < 0)
+ return (1);
+
+ fb_info = (struct clgenfb_info *)info;
+
+ /* "transparent" stuff is completely ignored. */
+ WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff));
+
+ return (0);
+}
+
+/*************************************************************************
+ clgen_pan_display()
+
+ performs display panning - provided hardware permits this
+**************************************************************************/
+static int clgen_pan_display(const struct fb_var_screeninfo *var,
+ struct fb_info_gen *info)
+{
+ int xoffset = 0;
+ int yoffset = 0;
+ unsigned long base;
+ unsigned char tmp = 0, tmp2 = 0, xpix;
+
+ fb_info = (struct clgenfb_info*)fb_info;
+
+ /* no range checks for xoffset and yoffset, */
+ /* as fbgen_pan_display has already done this */
+
+ fb_info->currentmode.var.xoffset = var->xoffset;
+ fb_info->currentmode.var.yoffset = var->yoffset;
+
+ xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
+ yoffset = var->yoffset;
+
+ base = yoffset * fb_info->currentmode.line_length + xoffset;
+
+ if (fb_info->currentmode.var.bits_per_pixel == 1)
+ {
+ /* base is already correct */
+ xpix = (unsigned char)(var->xoffset % 8);
+ }
+ else
+ {
+ base /= 4;
+ xpix = (unsigned char)((xoffset % 4) * 2);
+ }
+
+ /* lower 8 + 8 bits of screen start address */
+ WCrt(CRTD, (unsigned char)(base & 0xff));
+ WCrt(CRTC, (unsigned char)(base >> 8));
+
+ /* construct bits 16, 17 and 18 of screen start address */
+ if (base & 0x10000) tmp |= 0x01;
+ if (base & 0x20000) tmp |= 0x04;
+ if (base & 0x40000) tmp |= 0x08;
+
+ tmp2 = (RCrt(CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
+ WCrt(CRT1B, tmp2);
+ /* construct bit 19 of screen start address (only on SD64) */
+ if (fb_info->btype == BT_SD64 ||
+ fb_info->btype == BT_PICASSO4)
+ {
+ tmp2 = 0;
+ if (base & 0x80000) tmp2 = 0x80;
+ WCrt(CRT1D, tmp2);
+ }
+
+ /* write pixel panning value to AR33; this does not quite work in 8bpp */
+ /* ### Piccolo..? Will this work? */
+ if (fb_info->currentmode.var.bits_per_pixel == 1)
+ WAttr(AR33, xpix);
+
+ return(0);
+}
+
+
+static int clgen_blank(int blank_mode, struct fb_info_gen *info)
+{
+ unsigned char val;
+ printk(">clgen_blank(%d)\n",blank_mode);
+
+ fb_info = (struct clgenfb_info *)info;
+
+ val = RSeq(SEQR1);
+ if (blank_mode)
+ WSeq(SEQR1, val | 0x20); /* set "FullBandwidth" bit */
+ else
+ WSeq(SEQR1, val & 0xdf); /* clear "FullBandwidth" bit */
+
+ printk("<clgen_blank()\n");
+ return 0;
+}
+
+/**** END Hardware specific Routines **************************************/
+/****************************************************************************/
+/**** BEGIN Internal Routines ***********************************************/
+
+static void init_vgachip(void)
+{
+ printk(">init_vgachip()\n");
+
+ /* reset board globally */
+ switch(fb_info->btype)
+ {
+ case BT_SD64: WSFR(0x1f); udelay(500); WSFR(0x4f); udelay(500); break;
+ case BT_PICCOLO: WSFR(0x01); udelay(500); WSFR(0x51); udelay(500); break;
+ case BT_PICASSO: WSFR2(0xff); udelay(500); break;
+ case BT_SPECTRUM: WSFR(0x1f); udelay(500); WSFR(0x4f); udelay(500); break;
+ case BT_PICASSO4:
+ WCrt(CRT51, 0x00); /* disable flickerfixer */
+ udelay(100000);
+ WGfx(GR2F, 0x00); /* from Klaus' NetBSD driver: */
+ WGfx(GR33, 0x00); /* put blitter into 542x compat */
+ WGfx(GR31, 0x00); /* mode */
+ break;
+
+ default:
+ printk(KERN_ERR "clgen: Warning: Unknown board type\n");
+ break;
+ }
+
+ /* "pre-set" a RAMsize; if the test succeeds, double it */
+ if (fb_info->btype == BT_SD64 ||
+ fb_info->btype == BT_PICASSO4)
+ fb_info->size = 0x400000;
+ else
+ fb_info->size = 0x200000;
+
+ /* assume it's a "large memory" board (2/4 MB) */
+ fb_info->smallboard = FALSE;
+
+ /* the P4 is not fully initialized here; I rely on it having been */
+ /* inited under AmigaOS already, which seems to work just fine */
+ /* (Klaus advised to do it this way) */
+
+ if (fb_info->btype != BT_PICASSO4)
+ {
+ WGen(VSSM, 0x10); /* EGS: 0x16 */
+ WGen(POS102, 0x01);
+ WGen(VSSM, 0x08); /* EGS: 0x0e */
+
+ if(fb_info->btype != BT_SD64)
+ WGen(VSSM2, 0x01);
+
+ WSeq(SEQR0, 0x03); /* reset sequencer logic */
+
+ WSeq(SEQR1, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
+ WGen(MISC_W, 0xc1); /* polarity (-/-), disable access to display memory, CRTC base address: color */
+
+/* WGfx(GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
+ WSeq(SEQR6, 0x12); /* unlock all extension registers */
+
+ WGfx(GR31, 0x04); /* reset blitter */
+
+ if (fb_info->btype == BT_SD64)
+ {
+ WSeq(SEQRF, 0xb8); /* 4 MB Ram SD64, disable CRT fifo(!), 64 bit bus */
+ }
+ else
+ {
+ WSeq(SEQR16, 0x0f); /* Perf. Tuning: Fix value..(?) */
+ WSeq(SEQRF, 0xb0); /* 2 MB DRAM, 8level write buffer, 32bit bus */
+ }
+ }
+
+ WSeq(SEQR2, 0xff); /* plane mask: nothing */
+ WSeq(SEQR3, 0x00); /* character map select: doesn't even matter in gx mode */
+ WSeq(SEQR4, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
+
+ /* controller-internal base address of video memory */
+ switch(fb_info->btype)
+ {
+ case BT_SD64: WSeq(SEQR7, 0xf0); break;
+ case BT_PICCOLO: WSeq(SEQR7, 0x80); break;
+ case BT_SPECTRUM: WSeq(SEQR7, 0x80); break;
+ case BT_PICASSO: WSeq(SEQR7, 0x20); break;
+ case BT_PICASSO4: WSeq(SEQR7, 0x20); break;
+ }
+
+/* WSeq(SEQR8, 0x00);*/ /* EEPROM control: shouldn't be necessary to write to this at all.. */
+
+ WSeq(SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
+ WSeq(SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
+ WSeq(SEQR12, 0x00); /* graphics cursor attributes */
+ WSeq(SEQR13, 0x00); /* graphics cursor pattern address */
+
+ /* writing these on a P4 might give problems.. */
+ if (fb_info->btype != BT_PICASSO4)
+ {
+ WSeq(SEQR17, 0x00); /* configuration readback and ext. color */
+ WSeq(SEQR18, 0x02); /* signature generator */
+ }
+
+ /* MCLK select etc. */
+ switch(fb_info->btype)
+ {
+ case BT_PICCOLO:
+ case BT_PICASSO:
+ case BT_SPECTRUM: WSeq(SEQR1F, 0x22); break;
+ case BT_SD64: WSeq(SEQR1F, 0x20); break;
+ case BT_PICASSO4:/*WSeq(SEQR1F, 0x1c); */ break;
+ }
+
+ WCrt(CRT8, 0x00); /* Screen A preset row scan: none */
+ WCrt(CRTA, 0x20); /* Text cursor start: disable text cursor */
+ WCrt(CRTB, 0x00); /* Text cursor end: - */
+ WCrt(CRTC, 0x00); /* Screen start address high: 0 */
+ WCrt(CRTD, 0x00); /* Screen start address low: 0 */
+ WCrt(CRTE, 0x00); /* text cursor location high: 0 */
+ WCrt(CRTF, 0x00); /* text cursor location low: 0 */
+
+ WCrt(CRT14, 0x00); /* Underline Row scanline: - */
+ WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
+ WCrt(CRT18, 0x00); /* Line Compare: not needed */
+ /* ### add 0x40 for text modes with > 30 MHz pixclock */
+ WCrt(CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
+
+ WGfx(GR0, 0x00); /* Set/Reset registes: - */
+ WGfx(GR1, 0x00); /* Set/Reset enable: - */
+ WGfx(GR2, 0x00); /* Color Compare: - */
+ WGfx(GR3, 0x00); /* Data Rotate: - */
+ WGfx(GR4, 0x00); /* Read Map Select: - */
+ WGfx(GR5, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
+ WGfx(GR6, 0x01); /* Miscellaneous: memory map base address, graphics mode */
+ WGfx(GR7, 0x0f); /* Color Don't care: involve all planes */
+ WGfx(GR8, 0xff); /* Bit Mask: no mask at all */
+ WGfx(GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
+
+ WGfx(GRC, 0xff); /* Color Key compare: - */
+ WGfx(GRD, 0x00); /* Color Key compare mask: - */
+ WGfx(GRE, 0x00); /* Miscellaneous control: - */
+/* WGfx(GR10, 0x00);*/ /* Background color byte 1: - */
+/* WGfx(GR11, 0x00); */
+
+ WAttr(AR0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
+ WAttr(AR1, 0x01);
+ WAttr(AR2, 0x02);
+ WAttr(AR3, 0x03);
+ WAttr(AR4, 0x04);
+ WAttr(AR5, 0x05);
+ WAttr(AR6, 0x06);
+ WAttr(AR7, 0x07);
+ WAttr(AR8, 0x08);
+ WAttr(AR9, 0x09);
+ WAttr(ARA, 0x0a);
+ WAttr(ARB, 0x0b);
+ WAttr(ARC, 0x0c);
+ WAttr(ARD, 0x0d);
+ WAttr(ARE, 0x0e);
+ WAttr(ARF, 0x0f);
+
+ WAttr(AR10, 0x01); /* Attribute Controller mode: graphics mode */
+ WAttr(AR11, 0x00); /* Overscan color reg.: reg. 0 */
+ WAttr(AR12, 0x0f); /* Color Plane enable: Enable all 4 planes */
+/* ### WAttr(AR33, 0x00); * Pixel Panning: - */
+ WAttr(AR14, 0x00); /* Color Select: - */
+
+ WGen(M_3C6, 0xff); /* Pixel mask: no mask */
+
+ WGen(MISC_W, 0xc3); /* polarity (-/-), enable display mem, CRTC i/o base = color */
+
+ WGfx(GR31, 0x04); /* BLT Start/status: Blitter reset */
+ WGfx(GR31, 0x00); /* - " - : "end-of-reset" */
+
+ /* CLUT setup */
+ WClut( 0, 0x00, 0x00, 0x00); /* background: black */
+ WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */
+ WClut( 2, 0x00, 0x80, 0x00);
+ WClut( 3, 0x00, 0x80, 0x80);
+ WClut( 4, 0x80, 0x00, 0x00);
+ WClut( 5, 0x80, 0x00, 0x80);
+ WClut( 6, 0x80, 0x40, 0x00);
+ WClut( 7, 0x80, 0x80, 0x80);
+ WClut( 8, 0x40, 0x40, 0x40);
+ WClut( 9, 0x40, 0x40, 0xc0);
+ WClut(10, 0x40, 0xc0, 0x40);
+ WClut(11, 0x40, 0xc0, 0xc0);
+ WClut(12, 0xc0, 0x40, 0x40);
+ WClut(13, 0xc0, 0x40, 0xc0);
+ WClut(14, 0xc0, 0xc0, 0x40);
+ WClut(15, 0xc0, 0xc0, 0xc0);
+
+ /* the rest a grey ramp */
+ {
+ int i;
+
+ for (i = 16; i < 256; i++)
+ WClut(i, i, i, i);
+ }
+
+
+ /* misc... */
+ WHDR(0); /* Hidden DAC register: - */
+
+#if 0
+ /* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */
+ /* DRAM register has already been pre-set for "large", so it is*/
+ /* only modified if we find that this is a "small" version */
+ {
+ unsigned volatile char *ram = fb_info->fbmem;
+ int i, flag = 0;
+
+ ram += (fb_info->size >> 1);
+
+ for (i = 0; i < 256; i++)
+ ram[i] = (unsigned char)i;
+
+ for (i = 0; i < 256; i++)
+ {
+ if (ram[i] != i)
+ flag = 1;
+ }
+
+ /* if the DRAM test failed, halve RAM value */
+ if (flag)
+ {
+ fb_info->size /= 2;
+ fb_info->smallboard = TRUE;
+ switch(fb_info->btype)
+ {
+ case BT_SD64: WSeq(SEQRF, 0x38); break; /* 2 MB Ram SD64 */
+ case BT_PICASSO4: WSeq(SEQRF, 0x38); break; /* ### like SD64? */
+ case BT_PICCOLO:
+ case BT_PICASSO:
+ case BT_SPECTRUM: WSeq(SEQRF, 0x30); break; /* 1 MB DRAM */
+ default:
+ printk(KERN_WARNING "clgen: Uuhh..could not determine RAM size!\n");
+ }
+ }
+
+ }
+#endif
+ printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
+ printk("<init_vgachip()\n");
+ return;
+}
+
+static void switch_monitor(int on)
+{
+ static int IsOn = 0; /* XXX not ok for multiple boards */
+
+ if (fb_info->btype == BT_PICASSO4) return; /* nothing to switch */
+ if (fb_info->btype == BT_PICASSO)
+ {
+ if ((on && !IsOn) || (!on && IsOn))
+ WSFR(0xff);
+ return;
+ }
+ if (on)
+ switch(fb_info->btype)
+ {
+ case BT_SD64: WSFR(fb_info->SFR | 0x21); break;
+ case BT_PICCOLO: WSFR(fb_info->SFR | 0x28); break;
+ case BT_SPECTRUM: WSFR(0x6f); break;
+ }
+ else
+ switch(fb_info->btype)
+ {
+ case BT_SD64: WSFR(fb_info->SFR & 0xde); break;
+ case BT_PICCOLO: WSFR(fb_info->SFR & 0xd7); break;
+ case BT_SPECTRUM: WSFR(0x4f); break;
+ }
+}
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+ struct fb_info_gen *info)
+{
+ struct clgenfb_par *_par = (struct clgenfb_par*) par;
+
+ printk("clgen_get_dispsw(): ");
+ switch (_par->var.bits_per_pixel)
+ {
+#ifdef FBCON_HAS_MFB
+ case 1:
+ printk("monochrome\n");
+ return &fbcon_mfb;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ printk("8 bit color depth\n");
+ return &fbcon_clgen_8;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ printk("16 bit color depth\n");
+ return &fbcon_cfb16;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ printk("24 bit color depth\n");
+ return &fbcon_cfb24;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ printk("32 bit color depth\n");
+ return &fbcon_cfb32;
+#endif
+
+ default:
+ printk("unsupported color depth\n");
+ return NULL;
+ }
+}
+
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx,
+ int dy, int dx, int height, int width)
+{
+ sx *= p->fontwidth;
+ sy *= p->fontheight;
+ dx *= p->fontwidth;
+ dy *= p->fontheight;
+ width *= p->fontwidth;
+ height *= p->fontheight;
+
+ fb_info = (struct clgenfb_info*)p->fb_info;
+
+ clgen_BitBLT((unsigned short)sx, (unsigned short)sy,
+ (unsigned short)dx, (unsigned short)dy,
+ (unsigned short)width, (unsigned short)height,
+ fb_info->currentmode.line_length);
+ clgen_WaitBLT();
+}
+
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width)
+{
+ unsigned short col;
+
+ fb_info = (struct clgenfb_info*)p->fb_info;
+
+ sx *= p->fontwidth;
+ sy *= p->fontheight;
+ width *= p->fontwidth;
+ height *= p->fontheight;
+
+ col = attr_bgcol_ec(p, conp);
+ col &= 0xff;
+
+ clgen_RectFill((unsigned short)sx, (unsigned short)sy,
+ (unsigned short)width,(unsigned short)height,
+ col, fb_info->currentmode.line_length);
+ clgen_WaitBLT();
+}
+
+
+/********************************************************************/
+/* clgenfb_init() - master initialization function */
+/********************************************************************/
+__initfunc(void clgenfb_init(void))
+{
+ const struct ConfigDev *cd = NULL;
+ const struct ConfigDev *cd2 = NULL;
+ int err;
+ int btype;
+ int key,key2;
+ unsigned long board_addr,board_size;
+
+ printk(">clgenfb_init()\n");
+ printk(KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
+
+ btype = -1;
+
+ if ((key = zorro_find(ZORRO_PROD_HELFRICH_SD64_RAM, 0, 0)))
+ {
+ key2 = zorro_find(ZORRO_PROD_HELFRICH_SD64_REG, 0, 0);
+ btype = BT_SD64;
+ printk(KERN_INFO "clgen: SD64 board detected; ");
+ }
+ else if ((key = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_RAM, 0, 0)))
+ {
+ key2 = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_REG, 0, 0);
+ btype = BT_PICCOLO;
+ printk(KERN_INFO "clgen: Piccolo board detected; ");
+ }
+ else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, 0, 0)))
+ {
+ key2 = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, 0, 0);
+ btype = BT_PICASSO;
+ printk(KERN_INFO "clgen: Picasso II board detected; ");
+ }
+ else if ((key = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, 0, 0)))
+ {
+ key2 = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, 0, 0);
+ btype = BT_SPECTRUM;
+ printk(KERN_INFO "clgen: Spectrum board detected; ");
+ }
+ else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, 0, 0)))
+ {
+ btype = BT_PICASSO4;
+ printk(KERN_INFO "clgen: Picasso 4 board detected; ");
+ }
+ else
+ {
+ printk(KERN_NOTICE "clgen: no supported board found.\n");
+ return;
+ }
+
+ fb_info = &boards[0]; /* FIXME support multiple boards ...*/
+
+ fb_info->keyRAM = key;
+ fb_info->keyREG = key2;
+ fb_info->btype = btype;
+
+ cd = zorro_get_board(key);
+ board_addr = (unsigned long)cd->cd_BoardAddr;
+ board_size = (unsigned long)cd->cd_BoardSize;
+ printk(" RAM (%lu MB) at $%lx, ", board_size/0x100000, board_addr);
+
+ if (btype == BT_PICASSO4)
+ {
+ printk(" REG at $%lx\n", board_addr + 0x600000);
+
+ /* To be precise, for the P4 this is not the */
+ /* begin of the board, but the begin of RAM. */
+ /* for P4, map in its address space in 2 chunks (### TEST! ) */
+ /* (note the ugly hardcoded 16M number) */
+ fb_info->regs = (unsigned char *)kernel_map(board_addr, 16777216,
+ KERNELMAP_NOCACHE_SER, NULL);
+ DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
+ fb_info->regs += 0x600000;
+
+ fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216,
+ KERNELMAP_NOCACHE_SER, NULL);
+ DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
+ }
+ else
+ {
+ cd2 = zorro_get_board(key2);
+ printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
+
+ if (board_addr > 0x01000000)
+ fb_info->fbmem = kernel_map(board_addr, board_size,
+ KERNELMAP_NOCACHE_SER, NULL);
+ else
+ fb_info->fbmem = ZTWO_VADDR(board_addr);
+
+ /* set address for REG area of board */
+ fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr);
+
+ DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs);
+ DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
+ }
+
+ init_vgachip();
+
+ /* set up a few more things, register framebuffer driver etc */
+ fb_info->gen.parsize = sizeof(struct clgenfb_par);
+ fb_info->gen.fbhw = &clgen_hwswitch;
+ strcpy (fb_info->gen.info.modename, clgenfb_name);
+ fb_info->gen.info.node = -1;
+ fb_info->gen.info.fbops = &clgenfb_ops;
+ fb_info->gen.info.disp = &disp;
+ fb_info->gen.info.changevar = NULL;
+ fb_info->gen.info.switch_con = &fbgen_switch;
+ fb_info->gen.info.updatevar = &fbgen_update_var;
+ fb_info->gen.info.blank = &fbgen_blank;
+
+ /* mark this board as "autoconfigured" */
+ zorro_config_board(key, 0);
+ if (btype != BT_PICASSO4)
+ zorro_config_board(key2, 0);
+
+ /* now that we know the board has been registered n' stuff, we */
+ /* can finally initialize it to a default mode (640x480) */
+ clgenfb_default = clgenfb_predefined[1].var;
+ clgenfb_default.activate = FB_ACTIVATE_NOW;
+ clgenfb_default.yres_virtual = 480*3; /* for fast scrolling (YPAN-Mode) */
+ err = fbgen_do_set_var(&clgenfb_default, 1, &fb_info->gen);
+
+ if (err)
+ return;
+
+ disp.var = clgenfb_default;
+ fbgen_set_disp(-1, &fb_info->gen);
+ fbgen_install_cmap(0, &fb_info->gen);
+
+ err = register_framebuffer(&fb_info->gen.info);
+ if (err)
+ {
+ printk(KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
+ return;
+ }
+
+ printk("<clgenfb_init()\n");
+ return;
+}
+
+ /*
+ * Cleanup
+ */
+
+void clgenfb_cleanup(struct clgenfb_info *info)
+{
+ printk(">clgenfb_cleanup()\n");
+
+ fb_info = info;
+
+ switch_monitor(0);
+
+ zorro_unconfig_board(info->keyRAM, 0);
+ if (fb_info->btype != BT_PICASSO4)
+ zorro_unconfig_board(info->keyREG, 0);
+
+ unregister_framebuffer(&info->gen.info);
+ printk("Framebuffer unregistered\n");
+ printk("<clgenfb_cleanup()\n");
+}
+
+
+/* A strtok which returns empty strings, too */
+static char *strtoke(char *s,const char *ct)
+{
+ char *sbegin, *send;
+ static char *ssave = NULL;
+
+ sbegin = s ? s : ssave;
+ if (!sbegin)
+ return NULL;
+ if (*sbegin == '\0') {
+ ssave = NULL;
+ return NULL;
+ }
+ send = strpbrk(sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ssave = send;
+ return sbegin;
+}
+
+/*****************************************************************/
+/* clgenfb_setup() might be used later for parsing possible */
+/* arguments to the video= bootstrap parameter. Right now, there */
+/* is nothing I do here. */
+/*****************************************************************/
+__initfunc(void clgenfb_setup(char *options, int *ints))
+{
+// char *this_opt;
+
+// printk("clgenfb_setup(): options: %s\n", options);
+}
+
+
+ /*
+ * Modularization
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ printk("init_module()\n");
+ clgenfb_init(0);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ printk("module_cleanup()\n");
+ clgenfb_cleanup(fb_info);
+}
+#endif /* MODULE */
+
+
+
+/**********************************************************************/
+/* about the following functions - I have used the same names for the */
+/* functions as Markus Wild did in his Retina driver for NetBSD as */
+/* they just made sense for this purpose. Apart from that, I wrote */
+/* these functions myself. */
+/**********************************************************************/
+
+/*** WGen() - write into one of the external/general registers ***/
+void WGen(int regnum, unsigned char val)
+{
+ unsigned volatile char *reg = fb_info->regs + regnum;
+
+ if(fb_info->btype == BT_PICASSO)
+ {
+ /* Picasso II specific hack */
+/* if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+ if (regnum == M_3C7_W || regnum == M_3C9)
+ reg += 0xfff;
+ }
+
+ *reg = val;
+}
+
+/*** RGen() - read out one of the external/general registers ***/
+unsigned char RGen(int regnum)
+{
+ unsigned volatile char *reg = fb_info->regs + regnum;
+
+ if(fb_info->btype == BT_PICASSO)
+ {
+ /* Picasso II specific hack */
+/* if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+ if (regnum == M_3C7_W || regnum == M_3C9)
+ reg += 0xfff;
+ }
+
+ return *reg;
+}
+
+/*** WSeq() - write into a register of the sequencer ***/
+void WSeq(unsigned char regnum, unsigned char val)
+{
+ fb_info->regs[SEQRX] = regnum;
+ fb_info->regs[SEQRX+1] = val;
+}
+
+/*** RSeq() - read out one of the Sequencer registers ***/
+unsigned char RSeq(unsigned char regnum)
+{
+ fb_info->regs[SEQRX] = regnum;
+ return fb_info->regs[SEQRX+1];
+}
+
+/*** WCrt() - write into a register of the CRT controller ***/
+void WCrt(unsigned char regnum, unsigned char val)
+{
+ fb_info->regs[CRTX] = regnum;
+ fb_info->regs[CRTX+1] = val;
+}
+
+/*** RCrt() - read out one of the CRT controller registers ***/
+unsigned char RCrt(unsigned char regnum)
+{
+ fb_info->regs[CRTX] = regnum;
+ return fb_info->regs[CRTX+1];
+}
+
+/*** WGfx() - write into a register of the Gfx controller ***/
+void WGfx(unsigned char regnum, unsigned char val)
+{
+ fb_info->regs[GRX] = regnum;
+ fb_info->regs[GRX+1] = val;
+}
+
+/*** RGfx() - read out one of the Gfx controller registers ***/
+unsigned char RGfx(unsigned char regnum)
+{
+ fb_info->regs[GRX] = regnum;
+ return fb_info->regs[GRX+1];
+}
+
+/*** WAttr() - write into a register of the Attribute controller ***/
+void WAttr(unsigned char regnum, unsigned char val)
+{
+ /* if the next access to the attribute controller is a data write access, */
+ /* simply write back the information that was already there before, so that */
+ /* the next write access after that will be an index write. */
+ if (RCrt(CRT24) & 0x80)
+ /* can't use WAttr() here - we would go into a recursive loop otherwise */
+ fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+ if (RCrt(CRT24) & 0x80)
+ printk(KERN_WARNING "clgen: *** AttrIdx BAD!***\n");
+
+ /* now, first set index and after that the value - both to the same address (!) */
+ fb_info->regs[ARX] = regnum;
+ fb_info->regs[ARX] = val;
+}
+
+/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
+void AttrOn()
+{
+ if (RCrt(CRT24) & 0x80)
+ /* if we're just in "write value" mode, write back the */
+ /* same value as before to not modify anything */
+ fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+ /* turn on video bit */
+/* fb_info->regs[ARX] = 0x20; */
+ fb_info->regs[ARX] = 0x33;
+
+ /* dummy write on Reg0 to be on "write index" mode next time */
+ fb_info->regs[ARX] = 0x00;
+}
+
+/*** RAttr() - read out a register of the Attribute controller ***/
+unsigned char RAttr(unsigned char regnum)
+{
+ /* (explanation see above in WAttr() ) */
+ if (RCrt(CRT24) & 0x80)
+ fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+ fb_info->regs[ARX] = regnum;
+ return fb_info->regs[ARX+1];
+}
+
+
+/*** WHDR() - write into the Hidden DAC register ***/
+/* as the HDR is the only extension register that requires special treatment
+ * (the other extension registers are accessible just like the "ordinary"
+ * registers of their functional group) here is a specialized routine for
+ * accessing the HDR
+ */
+void WHDR(unsigned char val)
+{
+ unsigned char dummy;
+
+ if(fb_info->btype == BT_PICASSO)
+ {
+ /* Klaus' hint for correct access to HDR on some boards */
+ /* first write 0 to pixel mask (3c6) */
+ WGen(M_3C6, 0x00); udelay(200);
+ /* next read dummy from pixel address (3c8) */
+ dummy = RGen(M_3C8); udelay(200);
+ }
+
+ /* now do the usual stuff to access the HDR */
+
+ dummy = RGen(M_3C6); udelay(200);
+ dummy = RGen(M_3C6); udelay(200);
+ dummy = RGen(M_3C6); udelay(200);
+ dummy = RGen(M_3C6); udelay(200);
+
+ WGen(M_3C6, val); udelay(200);
+
+ if(fb_info->btype == BT_PICASSO)
+ {
+ /* now first reset HDR access counter */
+ dummy = RGen(M_3C8); udelay(200);
+
+ /* and at the end, restore the mask value */
+ /* ## is this mask always 0xff? */
+ WGen(M_3C6, 0xff); udelay(200);
+ }
+}
+
+/*** RHDR() - read out the Hidden DAC register ***/
+/* I hope this does not break on the GD5428 - cannot test it. */
+/* (Is there any board for the Amiga that uses the 5428 ?) */
+unsigned char RHDR()
+{
+ unsigned char dummy;
+
+ dummy = RGen(M_3C6);
+ dummy = RGen(M_3C6);
+ dummy = RGen(M_3C6);
+ dummy = RGen(M_3C6);
+
+ return RGen(M_3C6);
+}
+
+
+/*** WSFR() - write to the "special function register" (SFR) ***/
+void WSFR(unsigned char val)
+{
+ fb_info->SFR = val;
+ fb_info->regs[0x8000] = val;
+}
+
+/* The Picasso has a second register for switching the monitor bit */
+void WSFR2(unsigned char val)
+{
+ /* writing an arbitrary value to this one causes the monitor switcher */
+ /* to flip to Amiga display */
+ fb_info->SFR = val;
+ fb_info->regs[0x9000] = val;
+}
+
+/*** WClut - set CLUT entry (range: 0..255 is automat. shifted to 0..63) ***/
+void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue)
+{
+ unsigned int data = 0x3c9;
+
+ /* address write mode register is not translated.. */
+ fb_info->regs[0x3c8] = regnum;
+
+ if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+ {
+ /* but DAC data register IS, at least for Picasso II */
+ if(fb_info->btype == BT_PICASSO)
+ data += 0xfff;
+ fb_info->regs[data] = (red >> 2);
+ fb_info->regs[data] = (green >> 2);
+ fb_info->regs[data] = (blue >> 2);
+ }
+ else
+ {
+ fb_info->regs[data] = (blue >> 2);
+ fb_info->regs[data] = (green >> 2);
+ fb_info->regs[data] = (red >> 2);
+ }
+}
+
+/*** RClut - read CLUT entry and convert to 0..255 range ***/
+void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue)
+{
+ unsigned int data = 0x3c9;
+
+ fb_info->regs[0x3c7] = regnum;
+
+ if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+ {
+ if(fb_info->btype == BT_PICASSO)
+ data += 0xfff;
+ *red = fb_info->regs[data] << 2;
+ *green = fb_info->regs[data] << 2;
+ *blue = fb_info->regs[data] << 2;
+ }
+ else
+ {
+ *blue = fb_info->regs[data] << 2;
+ *green = fb_info->regs[data] << 2;
+ *red = fb_info->regs[data] << 2;
+ }
+}
+
+
+/*******************************************************************
+ clgen_WaitBLT()
+
+ Wait for the BitBLT engine to complete a possible earlier job
+*********************************************************************/
+
+void clgen_WaitBLT()
+{
+ /* now busy-wait until we're done */
+ while (RGfx(GR31) & 0x08)
+ ;
+}
+
+/*******************************************************************
+ clgen_BitBLT()
+
+ perform accelerated "scrolling"
+********************************************************************/
+
+void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
+ u_short width, u_short height, u_short line_length)
+{
+ u_short nwidth, nheight;
+ u_long nsrc, ndest;
+ u_char bltmode;
+
+ nwidth = width - 1;
+ nheight = height - 1;
+
+ bltmode = 0x00;
+ /* if source adr < dest addr, do the Blt backwards */
+ if (cury <= desty)
+ {
+ if (cury == desty)
+ {
+ /* if src and dest are on the same line, check x */
+ if (curx < destx)
+ bltmode |= 0x01;
+ }
+ else
+ bltmode |= 0x01;
+ }
+
+ if (!bltmode)
+ {
+ /* standard case: forward blitting */
+ nsrc = (cury * line_length) + curx;
+ ndest = (desty * line_length) + destx;
+ }
+ else
+ {
+ /* this means start addresses are at the end, counting backwards */
+ nsrc = cury * line_length + curx + nheight * line_length + nwidth;
+ ndest = desty * line_length + destx + nheight * line_length + nwidth;
+ }
+
+// clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+ /*
+ run-down of registers to be programmed:
+ destination pitch
+ source pitch
+ BLT width/height
+ source start
+ destination start
+ BLT mode
+ BLT ROP
+ GR0 / GR1: "fill color"
+ start/stop
+ */
+
+ /* pitch: set to line_length */
+ WGfx(GR24, line_length & 0xff); /* dest pitch low */
+ WGfx(GR25, (line_length >> 8)); /* dest pitch hi */
+ WGfx(GR26, line_length & 0xff); /* source pitch low */
+ WGfx(GR27, (line_length >> 8)); /* source pitch hi */
+
+ /* BLT width: actual number of pixels - 1 */
+ WGfx(GR20, nwidth & 0xff); /* BLT width low */
+ WGfx(GR21, (nwidth >> 8)); /* BLT width hi */
+
+ /* BLT height: actual number of lines -1 */
+ WGfx(GR22, nheight & 0xff); /* BLT height low */
+ WGfx(GR23, (nheight >> 8)); /* BLT width hi */
+
+ /* BLT destination */
+ WGfx(GR28, (u_char)(ndest & 0xff)); /* BLT dest low */
+ WGfx(GR29, (u_char)(ndest >> 8)); /* BLT dest mid */
+ WGfx(GR2A, (u_char)(ndest >> 16)); /* BLT dest hi */
+
+ /* BLT source */
+ WGfx(GR2C, (u_char)(nsrc & 0xff)); /* BLT src low */
+ WGfx(GR2D, (u_char)(nsrc >> 8)); /* BLT src mid */
+ WGfx(GR2E, (u_char)(nsrc >> 16)); /* BLT src hi */
+
+ /* BLT mode */
+ WGfx(GR30, bltmode); /* BLT mode */
+
+ /* BLT ROP: SrcCopy */
+ WGfx(GR32, 0x0d); /* BLT ROP */
+
+ /* and finally: GO! */
+ WGfx(GR31, 0x02); /* BLT Start/status */
+}
+
+/*******************************************************************
+ clgen_RectFill()
+
+ perform accelerated rectangle fill
+********************************************************************/
+
+void clgen_RectFill (u_short x, u_short y, u_short width, u_short height,
+ u_char color, u_short line_length)
+{
+ u_short nwidth, nheight;
+ u_long ndest;
+
+ nwidth = width - 1;
+ nheight = height - 1;
+
+ ndest = (y * line_length) + x;
+
+// clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+ /* pitch: set to line_length */
+ WGfx(GR24, line_length & 0xff); /* dest pitch low */
+ WGfx(GR25, (line_length >> 8)); /* dest pitch hi */
+ WGfx(GR26, line_length & 0xff); /* source pitch low */
+ WGfx(GR27, (line_length >> 8)); /* source pitch hi */
+
+ /* BLT width: actual number of pixels - 1 */
+ WGfx(GR20, nwidth & 0xff); /* BLT width low */
+ WGfx(GR21, (nwidth >> 8)); /* BLT width hi */
+
+ /* BLT height: actual number of lines -1 */
+ WGfx(GR22, nheight & 0xff); /* BLT height low */
+ WGfx(GR23, (nheight >> 8)); /* BLT width hi */
+
+ /* BLT destination */
+ WGfx(GR28, (u_char)(ndest & 0xff)); /* BLT dest low */
+ WGfx(GR29, (u_char)(ndest >> 8)); /* BLT dest mid */
+ WGfx(GR2A, (u_char)(ndest >> 16)); /* BLT dest hi */
+
+ /* BLT source: set to 0 (is a dummy here anyway) */
+ WGfx(GR2C, 0x00); /* BLT src low */
+ WGfx(GR2D, 0x00); /* BLT src mid */
+ WGfx(GR2E, 0x00); /* BLT src hi */
+
+ /* This is a ColorExpand Blt, using the */
+ /* same color for foreground and background */
+ WGfx(GR0, color); /* foreground color */
+ WGfx(GR1, color); /* background color */
+
+ /* BLT mode: color expand, Enable 8x8 copy (faster?) */
+ WGfx(GR30, 0xc0); /* BLT mode */
+
+ /* BLT ROP: SrcCopy */
+ WGfx(GR32, 0x0d); /* BLT ROP */
+
+ /* and finally: GO! */
+ WGfx(GR31, 0x02); /* BLT Start/status */
+}
+
+/**************************************************************************
+ * bestclock() - determine closest possible clock lower(?) than the
+ * desired pixel clock
+ **************************************************************************/
+#define abs(x) ((x)<0 ? -(x) : (x))
+static void bestclock(long freq, long *best, long *nom,
+ long *den, long *div, long maxfreq)
+{
+ long n, h, d, f;
+
+ *nom = 0;
+ *den = 0;
+ *div = 0;
+
+ if (freq < 8000)
+ freq = 8000;
+
+ if (freq > maxfreq)
+ freq = maxfreq;
+
+ *best = 0;
+ f = freq * 10;
+
+ for(n = 32; n < 128; n++)
+ {
+ d = (143181 * n) / f;
+ if ( (d >= 7) && (d <= 63) )
+ {
+ if (d > 31)
+ d = (d / 2) * 2;
+ h = (14318 * n) / d;
+ if ( abs(h - freq) < abs(*best - freq) )
+ {
+ *best = h;
+ *nom = n;
+ if (d < 32)
+ {
+ *den = d;
+ *div = 0;
+ }
+ else
+ {
+ *den = d / 2;
+ *div = 1;
+ }
+ }
+ }
+ d = ( (143181 * n)+f-1) / f;
+ if ( (d >= 7) && (d <= 63) )
+ {
+ if (d > 31)
+ d = (d / 2) * 2;
+ h = (14318 * n) / d;
+ if ( abs(h - freq) < abs(*best - freq) )
+ {
+ *best = h;
+ *nom = n;
+ if (d < 32)
+ {
+ *den = d;
+ *div = 0;
+ }
+ else
+ {
+ *den = d / 2;
+ *div = 1;
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+
+/* definitions for Piccolo/SD64 VGA controller chip */
+/* these definitions might most of the time also work */
+/* for other CL-GD542x/543x based boards.. */
+
+/*** External/General Registers ***/
+#define POS102 0x102 /* POS102 register */
+#define VSSM 0x46e8 /* Adapter Sleep */
+#define VSSM2 0x3c3 /* Motherboard Sleep */
+#define MISC_W 0x3c2 /* Miscellaneous Output register, write */
+#define MISC_R 0x3cc /* Miscellaneous Output register, read */
+#define FC_W 0x3da /* Feature Control Register, write (color) */
+#define FC_R 0x3ca /* Feature Control Register, read */
+#define FEAT 0x3c2 /* Input Status Register 0 */
+#define STAT 0x3da /* Input Status Register 1, read-only */
+#define M_3C6 0x3c6 /* Pixel Mask */
+#define M_3C7_W 0x3c7 /* Pixel Address Read Mode (write) */
+#define M_3C7_R 0x3c7 /* DAC State (read-only */
+#define M_3C8 0x3c8 /* Pixel Address Write Mode */
+#define M_3C9 0x3c9 /* Pixel Data */
+
+/*** VGA Sequencer Registers ***/
+#define SEQRX 0x3c4 /* Sequencer Index */
+#define SEQR0 0x0 /* Reset */
+#define SEQR1 0x1 /* Clocking Mode */
+#define SEQR2 0x2 /* Plane Mask / Write Pixel Extension */
+#define SEQR3 0x3 /* Character Map Select */
+#define SEQR4 0x4 /* Memory Mode */
+/* the following are from the "extension registers" group */
+#define SEQR6 0x6 /* Unlock ALL Extensions */
+#define SEQR7 0x7 /* Extended Sequencer Mode */
+#define SEQR8 0x8 /* EEPROM Control */
+#define SEQR9 0x9 /* Scratch Pad 0 (do not access!) */
+#define SEQRA 0xa /* Scratch Pad 1 (do not access!) */
+#define SEQRB 0xb /* VCLK0 Numerator */
+#define SEQRC 0xc /* VCLK1 Numerator */
+#define SEQRD 0xd /* VCLK2 Numerator */
+#define SEQRE 0xe /* VCLK3 Numerator */
+#define SEQRF 0xf /* DRAM Control */
+#define SEQR10 0x10 /* Graphics Cursor X Position */
+#define SEQR11 0x11 /* Graphics Cursor Y Position */
+#define SEQR12 0x12 /* Graphics Cursor Attributes */
+#define SEQR13 0x13 /* Graphics Cursor Pattern Address Offset */
+#define SEQR14 0x14 /* Scratch Pad 2 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR15 0x15 /* Scratch Pad 3 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR16 0x16 /* Performance Tuning (CL-GD5424/'26/'28 Only) */
+#define SEQR17 0x17 /* Configuration ReadBack and Extended Control (CL-GF5428 Only) */
+#define SEQR18 0x18 /* Signature Generator Control (Not CL-GD5420) */
+#define SEQR19 0x19 /* Signature Generator Result Low Byte (Not CL-GD5420) */
+#define SEQR1A 0x1a /* Signature Generator Result High Byte (Not CL-GD5420) */
+#define SEQR1B 0x1b /* VCLK0 Denominator and Post-Scalar Value */
+#define SEQR1C 0x1c /* VCLK1 Denominator and Post-Scalar Value */
+#define SEQR1D 0x1d /* VCLK2 Denominator and Post-Scalar Value */
+#define SEQR1E 0x1e /* VCLK3 Denominator and Post-Scalar Value */
+#define SEQR1F 0x1f /* BIOS ROM write enable and MCLK Select */
+
+/*** CRT Controller Registers ***/
+#define CRTX 0x3d4 /* CRTC Index */
+#define CRT0 0x0 /* Horizontal Total */
+#define CRT1 0x1 /* Horizontal Display End */
+#define CRT2 0x2 /* Horizontal Blanking Start */
+#define CRT3 0x3 /* Horizontal Blabking End */
+#define CRT4 0x4 /* Horizontal Sync Start */
+#define CRT5 0x5 /* Horizontal Sync End */
+#define CRT6 0x6 /* Vertical Total */
+#define CRT7 0x7 /* Overflow */
+#define CRT8 0x8 /* Screen A Preset Row Scan */
+#define CRT9 0x9 /* Character Cell Height */
+#define CRTA 0xa /* Text Cursor Start */
+#define CRTB 0xb /* Text Cursor End */
+#define CRTC 0xc /* Screen Start Address High */
+#define CRTD 0xd /* Screen Start Address Low */
+#define CRTE 0xe /* Text Cursor Location High */
+#define CRTF 0xf /* Text Cursor Location Low */
+#define CRT10 0x10 /* Vertical Sync Start */
+#define CRT11 0x11 /* Vertical Sync End */
+#define CRT12 0x12 /* Vertical Display End */
+#define CRT13 0x13 /* Offset */
+#define CRT14 0x14 /* Underline Row Scan */
+#define CRT15 0x15 /* Vertical Blanking Start */
+#define CRT16 0x16 /* Vertical Blanking End */
+#define CRT17 0x17 /* Mode Control */
+#define CRT18 0x18 /* Line Compare */
+#define CRT22 0x22 /* Graphics Data Latches ReadBack */
+#define CRT24 0x24 /* Attribute Controller Toggle ReadBack */
+#define CRT26 0x26 /* Attribute Controller Index ReadBack */
+/* the following are from the "extension registers" group */
+#define CRT19 0x19 /* Interlace End */
+#define CRT1A 0x1a /* Interlace Control */
+#define CRT1B 0x1b /* Extended Display Controls */
+#define CRT1C 0x1c /* Sync adjust and genlock register */
+#define CRT1D 0x1d /* Overlay Extended Control register */
+#define CRT25 0x25 /* Part Status Register */
+#define CRT27 0x27 /* ID Register */
+#define CRT51 0x51 /* P4 disable "flicker fixer" */
+
+/*** Graphics Controller Registers ***/
+#define GRX 0x3ce /* Graphics Controller Index */
+#define GR0 0x0 /* Set/Reset, Write Mode 5 Background Extension */
+#define GR1 0x1 /* Set/Reset Enable, Write Mode 4, 5 Foreground Ext. */
+#define GR2 0x2 /* Color Compare */
+#define GR3 0x3 /* Data Rotate */
+#define GR4 0x4 /* Read Map Select */
+#define GR5 0x5 /* Mode */
+#define GR6 0x6 /* Miscellaneous */
+#define GR7 0x7 /* Color Don't Care */
+#define GR8 0x8 /* Bit Mask */
+/* the following are from the "extension registers" group */
+#define GR9 0x9 /* Offset Register 0 */
+#define GRA 0xa /* Offset Register 1 */
+#define GRB 0xb /* Graphics Controller Mode Extensions */
+#define GRC 0xc /* Color Key (CL-GD5424/'26/'28 Only) */
+#define GRD 0xd /* Color Key Mask (CL-GD5424/'26/'28 Only) */
+#define GRE 0xe /* Miscellaneous Control (Cl-GD5428 Only) */
+#define GRF 0xf /* Display Compression Control register */
+#define GR10 0x10 /* 16-bit Pixel BG Color High Byte (Not CL-GD5420) */
+#define GR11 0x11 /* 16-bit Pixel FG Color High Byte (Not CL-GD5420) */
+#define GR12 0x12 /* Background Color Byte 2 Register */
+#define GR13 0x13 /* Foreground Color Byte 2 Register */
+#define GR14 0x14 /* Background Color Byte 3 Register */
+#define GR15 0x15 /* Foreground Color Byte 3 Register */
+/* the following are CL-GD5426/'28 specific blitter registers */
+#define GR20 0x20 /* BLT Width Low */
+#define GR21 0x21 /* BLT Width High */
+#define GR22 0x22 /* BLT Height Low */
+#define GR23 0x23 /* BLT Height High */
+#define GR24 0x24 /* BLT Destination Pitch Low */
+#define GR25 0x25 /* BLT Destination Pitch High */
+#define GR26 0x26 /* BLT Source Pitch Low */
+#define GR27 0x27 /* BLT Source Pitch High */
+#define GR28 0x28 /* BLT Destination Start Low */
+#define GR29 0x29 /* BLT Destination Start Mid */
+#define GR2A 0x2a /* BLT Destination Start High */
+#define GR2C 0x2c /* BLT Source Start Low */
+#define GR2D 0x2d /* BLT Source Start Mid */
+#define GR2E 0x2e /* BLT Source Start High */
+#define GR2F 0x2f /* Picasso IV Blitter compat mode..? */
+#define GR30 0x30 /* BLT Mode */
+#define GR31 0x31 /* BLT Start/Status */
+#define GR32 0x32 /* BLT Raster Operation */
+#define GR33 0x33 /* another P4 "compat" register.. */
+#define GR34 0x34 /* Transparent Color Select Low */
+#define GR35 0x35 /* Transparent Color Select High */
+#define GR38 0x38 /* Source Transparent Color Mask Low */
+#define GR39 0x39 /* Source Transparent Color Mask High */
+
+/*** Attribute Controller Registers ***/
+#define ARX 0x3c0 /* Attribute Controller Index */
+#define AR0 0x0 /* Attribute Controller Palette Register 0 */
+#define AR1 0x1 /* Attribute Controller Palette Register 1 */
+#define AR2 0x2 /* Attribute Controller Palette Register 2 */
+#define AR3 0x3 /* Attribute Controller Palette Register 3 */
+#define AR4 0x4 /* Attribute Controller Palette Register 4 */
+#define AR5 0x5 /* Attribute Controller Palette Register 5 */
+#define AR6 0x6 /* Attribute Controller Palette Register 6 */
+#define AR7 0x7 /* Attribute Controller Palette Register 7 */
+#define AR8 0x8 /* Attribute Controller Palette Register 8 */
+#define AR9 0x9 /* Attribute Controller Palette Register 9 */
+#define ARA 0xa /* Attribute Controller Palette Register 10 */
+#define ARB 0xb /* Attribute Controller Palette Register 11 */
+#define ARC 0xc /* Attribute Controller Palette Register 12 */
+#define ARD 0xd /* Attribute Controller Palette Register 13 */
+#define ARE 0xe /* Attribute Controller Palette Register 14 */
+#define ARF 0xf /* Attribute Controller Palette Register 15 */
+#define AR10 0x10 /* Attribute Controller Mode Register */
+#define AR11 0x11 /* Overscan (Border) Color Register */
+#define AR12 0x12 /* Color Plane Enable Register */
+#define AR13 0x13 /* Pixel Panning Register */
+#define AR14 0x14 /* Color Select Register */
+#define AR33 0x33 /* The "real" Pixel Panning register (?) */
+#define AR34 0x34 /* *TEST* */
+
+/*** Extension Registers ***/
+#define HDR 0x3c6 /* Hidden DAC Register (Not CL-GD5420) */
+
--- /dev/null
+/*
+ * controlfb.c -- frame buffer device for the PowerMac 'control' display
+ *
+ * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ * Copyright (C) 1998 Dan Jacobowitz
+ *
+ * Frame buffer structure from:
+ * drivers/video/chipsfb.c -- frame buffer device for
+ * Chips & Technologies 65550 chip.
+ *
+ * Copyright (C) 1998 Paul Mackerras
+ *
+ * This file is derived from the Powermac "chips" driver:
+ * Copyright (C) 1997 Fabio Riccardi.
+ * And from the frame buffer device for Open Firmware-initialized devices:
+ * Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ * Hardware information from:
+ * control.c: Console support for PowerMac "control" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "controlfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_control {
+ int vmode, cmode;
+ int xres, yres;
+ int vxres, vyres;
+ int xoffset, yoffset;
+};
+
+struct fb_info_control {
+ struct fb_info info;
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ struct display disp;
+ struct fb_par_control par;
+ struct {
+ __u8 red, green, blue;
+ } palette[256];
+
+ struct cmap_regs *cmap_regs;
+ unsigned long cmap_regs_phys;
+
+ struct control_regs *control_regs;
+ unsigned long control_regs_phys;
+
+ __u8 *frame_buffer;
+ unsigned long frame_buffer_phys;
+
+ int sense, control_use_bank2;
+ unsigned long total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void control_init(void);
+void control_of_init(struct device_node *dp);
+
+static int control_open(struct fb_info *info, int user);
+static int control_release(struct fb_info *info, int user);
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+static int read_control_sense(struct fb_info_control *p);
+static inline int control_vram_reqd(int video_mode, int color_mode);
+static void set_control_clock(unsigned char *params);
+static void control_set_hardware(struct fb_info_control *p);
+static void control_par_to_all(struct fb_info_control *p, int init);
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);
+static int control_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_control *par, const struct fb_info *fb_info);
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p);
+static void control_par_to_display(struct fb_par_control *par,
+ struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+static void control_init_display(struct display *disp);
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+ struct fb_info_control *p);
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+
+static struct fb_ops controlfb_ops = {
+ control_open,
+ control_release,
+ control_get_fix,
+ control_get_var,
+ control_set_var,
+ control_get_cmap,
+ control_set_cmap,
+ control_pan_display,
+ control_ioctl
+};
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+ u_int *blue, u_int *transp, struct fb_info *info);
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+
+__openfirmware
+
+
+static int control_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int control_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct fb_info_control *cp = (struct fb_info_control *) info;
+
+ *fix = cp->fix;
+ return 0;
+}
+
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_control *cp = (struct fb_info_control *) info;
+
+ *var = cp->var;
+ return 0;
+}
+
+/* Sets everything according to var */
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_control *p = (struct fb_info_control *) info;
+ struct display *disp;
+ struct fb_par_control par;
+ int depthchange, err;
+
+ disp = (con >= 0) ? &fb_display[con] : &p->disp;
+ if((err = control_var_to_par(var, &par, info))) {
+ printk (KERN_ERR "Error in control_set_var, calling control_var_to_par: %d.\n", err);
+ return err;
+ }
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+ printk("Not activating, in control_set_var.\n");
+ control_par_to_var(&par, var);
+ return 0;
+ }
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+ depthchange = DIRTY(bits_per_pixel);
+ if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+ !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+ control_par_to_var(&par, var);
+ p->var = disp->var = *var;
+ return 0;
+ }
+printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+ /* OK, we're getting here at the right times... */
+ p->par = par;
+ control_par_to_var(&par, var);
+ p->var = *var;
+ control_par_to_fix(&par, &p->fix, p);
+ control_par_to_display(&par, disp, &p->fix, p);
+ p->disp = *disp;
+
+ if(info->changevar && !switching) /* Don't want to do this if just switching consoles. */
+ (*info->changevar)(con);
+ if(con == currcon)
+ control_set_hardware(p);
+ if(depthchange)
+ if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+ return err;
+ if(depthchange || switching)
+ do_install_cmap(con, info);
+ return 0;
+}
+
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xoffset != 0 || var->yoffset != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+ controlfb_getcolreg, info);
+ if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
+ return 0;
+}
+
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ struct display *disp = &fb_display[con];
+ int err;
+
+ if (disp->cmap.len == 0) {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ err = fb_alloc_cmap(&disp->cmap, size, 0);
+ if (err)
+ return err;
+ }
+
+ if (con == currcon)
+ return fb_set_cmap(cmap, &disp->var, kspc, controlfb_setcolreg,
+ info);
+ fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+static int controlfb_switch(int con, struct fb_info *info)
+{
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap,
+ &fb_display[currcon].var, 1, controlfb_getcolreg,
+ info);
+ currcon = con;
+#if 0
+ control_var_to_par(&fb_display[currcon].var, &par, info);
+ control_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+ do_install_cmap(con, info);
+#else
+ /* I see no reason not to do this. Minus info->changevar(). */
+ /* DOH. This makes control_set_var compare, you guessed it, */
+ /* fb_display[con].var (first param), and fb_display[con].var! */
+ /* Perhaps I just fixed that... */
+ switching = 1;
+ control_set_var(&fb_display[con].var, con, info);
+ switching = 0;
+#endif
+ return 0;
+}
+
+static int controlfb_updatevar(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static void controlfb_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ * then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ * to e.g. a video mode which doesn't support it. Implements VESA suspend
+ * and powerdown modes on hardware that supports disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+ struct fb_info_control *p = (struct fb_info_control *) info;
+ int ctrl;
+
+ ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33;
+ if (blank_mode)
+ --blank_mode;
+ if (blank_mode & VESA_VSYNC_SUSPEND)
+ ctrl &= ~3;
+ if (blank_mode & VESA_HSYNC_SUSPEND)
+ ctrl &= ~0x30;
+ out_le32(&p->control_regs->ctrl.r, ctrl);
+
+/* TODO: Figure out how the heck to powerdown this thing! */
+
+ return;
+}
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+ u_int *blue, u_int *transp, struct fb_info *info)
+{
+ struct fb_info_control *p = (struct fb_info_control *) info;
+
+ if (regno > 255)
+ return 1;
+ *red = p->palette[regno].red;
+ *green = p->palette[regno].green;
+ *blue = p->palette[regno].blue;
+ return 0;
+}
+
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct fb_info_control *p = (struct fb_info_control *) info;
+
+ if (regno > 255 || regno < 0)
+ return 1;
+ p->palette[regno].red = red;
+ p->palette[regno].green = green;
+ p->palette[regno].blue = blue;
+
+ out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */
+ out_8(&p->cmap_regs->lut, red); /* send one color channel at */
+ out_8(&p->cmap_regs->lut, green); /* a time... */
+ out_8(&p->cmap_regs->lut, blue);
+
+ if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+ /* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+ /* I think. */
+#endif
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+ controlfb_setcolreg, info);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+ controlfb_setcolreg, info);
+ }
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+ struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int control_vram_reqd(int video_mode, int color_mode)
+{
+ return control_reg_init[video_mode-1]->vres
+ * control_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+static void set_control_clock(unsigned char *params)
+{
+ struct adb_request req;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x50, i + 1, params[i]);
+ while (!req.complete)
+ cuda_poll();
+ }
+}
+
+
+__initfunc(static void init_control(struct fb_info_control *p))
+{
+ struct fb_par_control *par = &p->par;
+
+ p->sense = read_control_sense(p);
+ printk("Monitor sense value = 0x%x, ", p->sense);
+ /* Try to pick a video mode out of NVRAM if we have one. */
+ par->vmode = nvram_read_byte(NV_VMODE);
+ if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1])
+ par->vmode = VMODE_CHOOSE;
+ if(par->vmode == VMODE_CHOOSE)
+ par->vmode = mac_map_monitor_sense(p->sense);
+ if(!control_reg_init[par->vmode - 1])
+ par->vmode = VMODE_640_480_60;
+
+ par->cmode = nvram_read_byte(NV_CMODE);
+ if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+ par->cmode = CMODE_8;
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+ par->cmode--;
+
+ printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+
+ par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres;
+ par->vyres = par->yres = control_reg_init[par->vmode - 1]->vres;
+ par->xoffset = par->yoffset = 0;
+
+ control_par_to_all(p, 1);
+
+ if (register_framebuffer(&p->info) < 0) {
+ kfree(p);
+ return;
+ }
+ control_set_hardware(p);
+
+ printk("fb%d: control display adapter\n", GET_FB_IDX(p->info.node));
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void control_set_hardware(struct fb_info_control *p)
+{
+ struct control_regvals *init;
+ struct preg *rp;
+ int flags, ctrl, i;
+ int vmode, cmode;
+
+ vmode = p->par.vmode;
+ cmode = p->par.cmode;
+
+ init = control_reg_init[vmode - 1];
+
+ if (control_vram_reqd(vmode, cmode) > 0x200000)
+ flags = 0x51;
+ else if (p->control_use_bank2)
+ flags = 0x39;
+ else
+ flags = 0x31;
+ if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16)
+ ctrl = 0x7f;
+ else
+ ctrl = 0x3b;
+
+ /* Initialize display timing registers */
+ out_le32(&p->control_regs->ctrl.r, 0x43b);
+
+ set_control_clock(init->clock_params);
+
+ p->cmap_regs->addr = 0x20; p->cmap_regs->d2 = init->radacal_ctrl[cmode];
+ p->cmap_regs->addr = 0x21; p->cmap_regs->d2 = p->control_use_bank2 ? 0: 1;
+ p->cmap_regs->addr = 0x10; p->cmap_regs->d2 = 0;
+ p->cmap_regs->addr = 0x11; p->cmap_regs->d2 = 0;
+
+ rp = &p->control_regs->vswin;
+ for (i = 0; i < 16; ++i, ++rp)
+ out_le32(&rp->r, init->regs[i]);
+
+ out_le32(&p->control_regs->pitch.r, init->pitch[cmode]);
+ out_le32(&p->control_regs->mode.r, init->mode[cmode]);
+ out_le32(&p->control_regs->flags.r, flags);
+ out_le32(&p->control_regs->start_addr.r, 0);
+ out_le32(&p->control_regs->reg18.r, 0x1e5);
+ out_le32(&p->control_regs->reg19.r, 0);
+
+ for (i = 0; i < 16; ++i) {
+ controlfb_setcolreg(color_table[i], default_red[i], default_grn[i],
+ default_blu[i], 0, (struct fb_info *)p);
+ }
+/* Does the above need to be here each time? -- danj */
+
+ /* Turn on display */
+ out_le32(&p->control_regs->ctrl.r, ctrl);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ /* And let the world know the truth. */
+ if (!console_fb_info || console_fb_info == &p->info) {
+ display_info.height = p->var.yres;
+ display_info.width = p->var.xres;
+ display_info.depth = (cmode == CMODE_32) ? 32 :
+ ((cmode == CMODE_16) ? 16 : 8);
+ display_info.pitch = p->fix.line_length;
+ display_info.mode = vmode;
+ strncpy(display_info.name, "control",
+ sizeof(display_info.name));
+ display_info.fb_address = p->frame_buffer_phys
+ + control_reg_init[vmode-1]->offset[cmode];
+ display_info.cmap_adr_address = p->cmap_regs_phys;
+ display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+ display_info.disp_reg_address = p->control_regs_phys;
+ console_fb_info = &p->info;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void control_init(void))
+{
+#ifndef CONFIG_FB_OF
+ struct device_node *dp;
+
+ dp = find_devices("control");
+ if (dp != 0)
+ control_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void control_of_init(struct device_node *dp))
+{
+ struct fb_info_control *p;
+ unsigned long addr, size;
+ int i, bank1, bank2;
+
+ if(dp->next != 0)
+ printk("Warning: only using first control display device.\n");
+ /* danj: I have a feeling this no longer applies - if we somehow *
+ * had two of them, they'd be two framebuffers, right? */
+ if(dp->n_addrs != 2)
+ panic("expecting 2 address for control (got %d)", dp->n_addrs);
+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ if (p == 0)
+ return;
+
+ /* Map in frame buffer and registers */
+ for (i = 0; i < dp->n_addrs; ++i) {
+ addr = dp->addrs[i].address;
+ size = dp->addrs[i].size;
+ if (size >= 0x800000) {
+ /* use the big-endian aperture (??) */
+ addr += 0x800000;
+ /* map at most 8MB for the frame buffer */
+ p->frame_buffer_phys = addr;
+ p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
+ } else {
+ p->control_regs_phys = addr;
+ p->control_regs = ioremap(addr, size);
+ }
+ }
+ p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
+ p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+ /* Work out which banks of VRAM we have installed. */
+ /* danj: I guess the card just ignores writes to nonexistant VRAM... */
+ p->frame_buffer[0] = 0x5a;
+ p->frame_buffer[1] = 0xc7;
+ bank1 = p->frame_buffer[0] == 0x5a && p->frame_buffer[1] == 0xc7;
+ p->frame_buffer[0x600000] = 0xa5;
+ p->frame_buffer[0x600001] = 0x38;
+ bank2 = p->frame_buffer[0x600000] == 0xa5 && p->frame_buffer[0x600001] == 0x38;
+ p->total_vram = (bank1 + bank2) * 0x200000;
+ /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+ p->control_use_bank2 = !bank1;
+ if (p->control_use_bank2)
+ p->frame_buffer += 0x600000;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+ console_set_cmap_ptr = control_set_cmap;
+ console_setmode_ptr = control_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+ init_control(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ *
+ * Hmm - looking at platinum, should we be calling eieio() here?
+ */
+static int read_control_sense(struct fb_info_control *p)
+{
+ int sense;
+
+ out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */
+ __delay(200);
+ out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
+ __delay(2000);
+ sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */
+ __delay(2000);
+ sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2;
+ out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */
+ __delay(2000);
+ sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5)
+ | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4);
+ out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */
+ __delay(2000);
+ sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7;
+
+ out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
+
+ return sense;
+}
+
+#if 1
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_control *par, const struct fb_info *fb_info)
+{
+ int xres = var->xres;
+ int yres = var->yres;
+ int bpp = var->bits_per_pixel;
+
+ struct control_regvals *init;
+ struct fb_info_control *p = (struct fb_info_control *) fb_info;
+
+ /*
+ * Get the video params out of 'var'. If a value doesn't fit, round it up,
+ * if it's too big, return -EINVAL.
+ *
+ * Suggestion: Round up in the following order: bits_per_pixel, xres,
+ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ * bitfields, horizontal timing, vertical timing.
+ */
+ /* swiped by jonh from atyfb.c */
+ if (xres <= 512 && yres <= 384)
+ par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */
+ else if (xres <= 640 && yres <= 480)
+ par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */
+ else if (xres <= 640 && yres <= 870)
+ par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
+ else if (xres <= 768 && yres <= 576)
+ par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */
+ else if (xres <= 800 && yres <= 600)
+ par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */
+ else if (xres <= 832 && yres <= 624)
+ par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */
+ else if (xres <= 1024 && yres <= 768)
+ par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
+ else if (xres <= 1152 && yres <= 870)
+ par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
+ else if (xres <= 1280 && yres <= 960)
+ par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
+ else if (xres <= 1280 && yres <= 1024)
+ par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
+ else
+ return -EINVAL;
+
+ xres = control_reg_init[par->vmode-1]->hres;
+ yres = control_reg_init[par->vmode-1]->vres;
+
+/*
+ if (var->xres_virtual <= xres)
+ par->vxres = xres;
+ else
+ par->vxres = (var->xres_virtual+7) & ~7;
+ if (var->yres_virtual <= yres)
+ par->vyres = yres;
+ else
+ par->vyres = var->yres_virtual;
+
+ par->xoffset = (var->xoffset+7) & ~7;
+ par->yoffset = var->yoffset;
+ if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+ return -EINVAL;
+*/
+
+ /* I'm too chicken to think about virtual */
+ /* resolutions just yet. Bok bok. */
+
+ /* And I'm too chicken to even figure out what they are. Awk awk. [danj] */
+ if (var->xres_virtual > xres || var->yres_virtual > yres
+ || var->xoffset != 0 || var->yoffset != 0) {
+ return -EINVAL;
+ }
+
+ par->xres = xres;
+ par->yres = yres;
+ par->vxres = xres;
+ par->vyres = yres;
+ par->xoffset = 0;
+ par->yoffset = 0;
+
+ if (bpp <= 8)
+ par->cmode = CMODE_8;
+ else if (bpp <= 16)
+ par->cmode = CMODE_16;
+ else if (bpp <= 32)
+ par->cmode = CMODE_32;
+ else
+ return -EINVAL;
+
+ if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+ return -EINVAL;
+
+ /* Check if we know about the wanted video mode */
+ init = control_reg_init[par->vmode-1];
+ if (init == NULL) {
+ /* I'm not sure if control has any specific requirements -- */
+ /* if we have a regvals struct, we're good to go? */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_control *par, const struct fb_info *fb_info)
+{
+ struct fb_info_control *p = (struct fb_info_control *) fb_info;
+
+ if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+ return -EINVAL;
+ par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+ par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+ par->xoffset = par->yoffset = 0;
+
+ if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+ return -EINVAL;
+
+ /* Check if we know about the wanted video mode */
+ if(!control_reg_init[par->vmode-1]) {
+ /* I'm not sure if control has any specific requirements -- */
+ /* if we have a regvals struct, we're good to go? */
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+#if 1
+static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+ memset(var, 0, sizeof(*var));
+ var->xres = control_reg_init[par->vmode - 1]->hres;
+ var->yres = control_reg_init[par->vmode - 1]->vres;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres; /* For now. */
+ var->xoffset = par->xoffset;
+ var->yoffset = par->yoffset;
+ var->grayscale = 0;
+
+ if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+ printk(KERN_ERR "Bad color mode in control_par_to_var()!\n");
+ par->cmode = CMODE_8;
+ }
+ switch(par->cmode) {
+ case CMODE_8:
+ var->bits_per_pixel = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CMODE_16: /* RGB 555 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CMODE_32: /* RGB 888 */
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->height = -1;
+ var->width = -1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ /* these are total guesses, copied right out of atyfb.c */
+ var->left_margin = var->right_margin = 64;
+ var->upper_margin = var->lower_margin = 32;
+ var->hsync_len = /*64*/8;
+ var->vsync_len = /*2*/8;
+ var->sync = 0;
+
+#if 0
+/* jonh's pixclocks...*/
+ /* no long long support in the kernel :-( */
+ /* this splittig trick will work if xres > 232 */
+ var->pixclock = 1000000000/
+ (var->left_margin+var->xres+var->right_margin+var->hsync_len);
+ var->pixclock *= 1000;
+ var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+ (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+ /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+ /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+ /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+ var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0];
+ var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1];
+ var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+ mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+ memset(fix, 0, sizeof(*fix));
+ strcpy(fix->id, "control");
+ fix->mmio_start = (char *)p->control_regs_phys;
+ fix->mmio_len = sizeof(struct control_regs);
+ fix->type = FB_TYPE_PACKED_PIXELS;
+
+ /*
+ fix->type_aux = 0;
+ fix->ywrapstep = 0;
+ fix->ypanstep = 0;
+ fix->xpanstep = 0;
+ */
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+ struct fb_info_control *p)
+{
+ fix->smem_start = (void *)(p->frame_buffer_phys
+ + control_reg_init[par->vmode-1]->offset[par->cmode]);
+ p->fix.smem_len = control_vram_reqd(par->vmode, par->cmode);
+ /* Hmm, jonh used total_vram here. */
+ p->fix.visual = (par->cmode == CMODE_8) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ p->fix.line_length = par->vxres << par->cmode;
+ /* ywrapstep, xpanstep, ypanstep */
+}
+
+static void control_init_display(struct display *disp)
+{
+ memset(disp, 0, sizeof(*disp));
+ disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+ disp->can_soft_blank = 1;
+ disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+ disp->type_aux = fix->type_aux;
+ disp->cmap.red = NULL; /* ??? danj */
+ disp->cmap.green = NULL;
+ disp->cmap.blue = NULL;
+ disp->cmap.transp = NULL;
+ /* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void control_par_to_display(struct fb_par_control *par,
+ struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+ disp->var = p->var;
+ disp->screen_base = (char *) p->frame_buffer
+ + control_reg_init[par->vmode-1]->offset[par->cmode];
+ disp->visual = fix->visual;
+ disp->line_length = fix->line_length;
+
+if(disp->scrollmode != SCROLL_YREDRAW) {
+ printk(KERN_ERR "Scroll mode not YREDRAW in control_par_to_display!!\n");
+ disp->scrollmode = SCROLL_YREDRAW;
+}
+ disp->dispsw = (par->cmode == CMODE_32) ? &fbcon_cfb32 :
+ ((par->cmode == CMODE_16) ? &fbcon_cfb16 : &fbcon_cfb8);
+}
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p)
+{
+ strcpy(info->modename, p->fix.id);
+ info->node = -1; /* ??? danj */
+ info->fbops = &controlfb_ops;
+ info->disp = &p->disp;
+ info->fontname[0] = 0;
+ info->changevar = NULL;
+ info->switch_con = &controlfb_switch;
+ info->updatevar = &controlfb_updatevar;
+ info->blank = &controlfb_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void control_par_to_all(struct fb_info_control *p, int init)
+{
+ if(init) {
+ control_init_fix(&p->fix, p);
+ }
+ control_par_to_fix(&p->par, &p->fix, p);
+
+ control_par_to_var(&p->par, &p->var);
+
+ if(init) {
+ control_init_display(&p->disp);
+ }
+ control_par_to_display(&p->par, &p->disp, &p->fix, p);
+
+ if(init) {
+ control_init_info(&p->info, p);
+ }
+}
+
+#if 0
+__initfunc(void controlfb_setup(char *options, int *ints))
+{
+ /* Parse user speficied options (`video=controlfb:') */
+ FUNCID;
+}
+
+static int controlfb_pan_display(struct fb_var_screeninfo *var,
+ struct controlfb_par *par,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * `xoffset' and `yoffset' fields of the `var' structure.
+ * If the values don't fit, return -EINVAL.
+ */
+
+ FUNCID;
+
+ return 0;
+}
+
+#endif
--- /dev/null
+/*
+ * controlfb_hw.h: Constants of all sorts for controlfb
+ *
+ * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on an awful lot of code, including:
+ *
+ * control.c: Console support for PowerMac "control" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * The so far unpublished platinumfb.c
+ * Copyright (C) 1998 Jon Howell
+ */
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+ unsigned char addr;
+ char pad1[15];
+ unsigned char d1;
+ char pad2[15];
+ unsigned char d2;
+ char pad3[15];
+ unsigned char lut;
+ char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor.
+ */
+#define PAD(x) char x[12]
+
+struct preg { /* padded register */
+ unsigned r;
+ char pad[12];
+};
+
+struct control_regs {
+ struct preg vcount; /* vertical counter */
+ /* Vertical parameters are in units of 1/2 scan line */
+ struct preg vswin; /* between vsblank and vssync */
+ struct preg vsblank; /* vert start blank */
+ struct preg veblank; /* vert end blank (display start) */
+ struct preg vewin; /* between vesync and veblank */
+ struct preg vesync; /* vert end sync */
+ struct preg vssync; /* vert start sync */
+ struct preg vperiod; /* vert period */
+ struct preg reg8;
+ /* Horizontal params are in units of 2 pixels */
+ struct preg hperiod; /* horiz period - 2 */
+ struct preg hsblank; /* horiz start blank */
+ struct preg heblank; /* horiz end blank */
+ struct preg hesync; /* horiz end sync */
+ struct preg hssync; /* horiz start sync */
+ struct preg rege;
+ struct preg regf;
+ struct preg reg10;
+ struct preg reg11;
+ struct preg ctrl; /* display control */
+ struct preg start_addr; /* start address: 5 lsbs zero */
+ struct preg pitch; /* addrs diff between scan lines */
+ struct preg mon_sense; /* monitor sense bits */
+ struct preg flags;
+ struct preg mode;
+ struct preg reg18;
+ struct preg reg19;
+ struct preg res[6];
+};
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+ int pitch[3]; /* bytes/line, indexed by color_mode */
+ int offset[3]; /* first pixel address */
+ unsigned regs[16]; /* for vswin .. reg10 */
+ unsigned char mode[3]; /* indexed by color_mode */
+ unsigned char radacal_ctrl[3];
+ unsigned char clock_params[3];
+ int hres;
+ int vres;
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+ { 1280, 2560, 0 },
+ { 0x10, 0x20, 0 },
+ { 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+ 420, 411, 91, 35, 421, 18, 211, 386, },
+ { 1, 1, 1},
+ { 0x50, 0x64, 0x64 },
+ { 13, 56, 3 }, /* pixel clock = 134.61MHz for V=74.81Hz */
+ 1280, 1024
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+ { 1280, 2560, 0 },
+ { 0x10, 0x20, 0 },
+ { 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+ 418, 409, 89, 35, 419, 18, 210, 384, },
+ { 1, 1, 1 },
+ { 0x50, 0x64, 0x64 },
+ { 31, 125, 3 }, /* pixel clock = 126.01MHz for V=75.01 Hz */
+ 1280, 960
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+ { 1152, 2304, 4608 },
+ { 0x10, 0x28, 0x50 },
+ { 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+ 726, 705, 129, 63, 727, 32, 364, 664 },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 19, 61, 3 }, /* pixel clock = 100.33MHz for V=75.31Hz */
+ 1152, 870
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+ 662, 641, 129, 47, 663, 24, 332, 616 },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 11, 28, 3 }, /* pixel clock = 79.55MHz for V=74.50Hz */
+ 1024, 768
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+ 670, 653, 141, 67, 671, 34, 336, 604, },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 12, 30, 3 }, /* pixel clock = 78.12MHz for V=72.12Hz */
+ 1024, 768
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+ { 1024, 2048, 4096 },
+ { 0x10, 0x28, 0x50 },
+ { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+ 670, 653, 141, 67, 671, 34, 336, 604, },
+ { 2, 1, 1 },
+ { 0x10, 0x14, 0x28 },
+ { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */
+ 1024, 768
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+ { 832, 1664, 3328 },
+ { 0x10, 0x28, 0x50 },
+ { 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+ 574, 553, 137, 31, 575, 16, 288, 544 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */
+ 832, 624
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+ 526, 513, 113, 39, 527, 20, 264, 488, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 7, 11, 3 }, /* pixel clock = 49.11MHz for V=74.40Hz */
+ 800, 600
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+ 518, 485, 85, 59, 519, 30, 260, 460, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
+ 800, 600
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+ { 800, 1600, 3200 },
+ { 0x10, 0x28, 0x50 },
+ { 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+ 518, 485, 85, 59, 519, 30, 260, 460, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 20, 53, 2 }, /* pixel clock = 41.41MHz for V=59.78Hz */
+ 800, 600
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+ { 640, 1280, 2560 },
+ { 0x10, 0x30, 0x68 },
+ { 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+ 0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 9, 33, 2 }, /* pixel clock = 57.29MHz for V=75.01Hz */
+ 640, 870
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+ { 640, 1280, 2560 },
+ { 0, 8, 0x10 },
+ { 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+ 430, 393, 73, 31, 431, 16, 216, 400 },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */
+ 640, 480
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+ { 640, 1280, 2560 },
+ { 0x10, 0x28, 0x50 },
+ { 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+ 398, 385, 65, 47, 399, 24, 200, 352, },
+ { 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+ { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */
+ 640, 480
+};
+
+static struct control_regvals *control_reg_init[VMODE_MAX] = {
+ NULL, NULL, NULL, NULL,
+ &control_reg_init_5,
+ &control_reg_init_6,
+ &control_reg_init_7,
+ NULL, NULL,
+ &control_reg_init_10,
+ &control_reg_init_11,
+ &control_reg_init_12,
+ &control_reg_init_13,
+ &control_reg_init_14,
+ &control_reg_init_15,
+ NULL,
+ &control_reg_init_17,
+ &control_reg_init_18,
+ &control_reg_init_19,
+ &control_reg_init_20
+};
-/* $Id: creatorfb.c,v 1.7 1998/07/21 10:36:48 jj Exp $
+/* $Id: creatorfb.c,v 1.10 1998/07/25 22:54:37 davem Exp $
* creatorfb.c: Creator/Creator3D frame buffer driver
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
int x, y, w, h;
fbc->ppc = 0x1803;
- fbc->fg = ffb_cmap[attr_bg_col_ec(conp)];
+ fbc->fg = ffb_cmap[attr_bgcol_ec(p,conp)];
fbc->fbc = 0x2000707f;
fbc->rop = 0x83;
fbc->pmask = 0xffffffff;
fbc->bw = w;
}
-static void ffb_fill(struct fb_info_sbusfb *fb, int s,
+static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
int count, unsigned short *boxes)
{
register struct ffb_fbc *fbc = fb->s.ffb.fbc;
fbc->ppc = 0x1803;
- fbc->fg = ffb_cmap[attr_bg_col(s)];
+ fbc->fg = ffb_cmap[attr_bgcol(p,s)];
fbc->fbc = 0x2000707f;
fbc->rop = 0x83;
fbc->pmask = 0xffffffff;
if (p->fontheightlog) {
xy = (yy << (16 + p->fontheightlog));
- i = ((c & 0xff) << p->fontheightlog);
+ i = ((c & p->charmask) << p->fontheightlog);
} else {
xy = ((yy * p->fontheight) << 16);
- i = (c & 0xff) * p->fontheight;
+ i = (c & p->charmask) * p->fontheight;
}
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ fd = p->fontdata + i;
+ xy += (xx * 8) + fb->s.ffb.xy_margin;
+#else
if (p->fontwidth <= 8)
fd = p->fontdata + i;
else
xy += (xx << p->fontwidthlog) + fb->s.ffb.xy_margin;
else
xy += (xx * p->fontwidth) + fb->s.ffb.xy_margin;
+#endif
fbc->ppc = 0x203;
- fbc->fg = ffb_cmap[attr_fg_col(c)];
+ fbc->fg = ffb_cmap[attr_fgcol(p,c)];
fbc->fbc = 0x2000707f;
fbc->rop = 0x83;
fbc->pmask = 0xffffffff;
- fbc->bg = ffb_cmap[attr_bg_col(c)];
+ fbc->bg = ffb_cmap[attr_bgcol(p,c)];
fbc->fontw = p->fontwidth;
fbc->fontinc = 0x10000;
fbc->fontxy = xy;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
for (i = 0; i < p->fontheight; i++)
fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
for (i = 0; i < p->fontheight; i++) {
fbc->font = *(u16 *)fd << 16;
fd += 2;
}
}
+#endif
}
static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
u8 *fd1, *fd2, *fd3, *fd4;
fbc->ppc = 0x203;
- fbc->fg = ffb_cmap[attr_fg_col(*s)];
+ fbc->fg = ffb_cmap[attr_fgcol(p,*s)];
fbc->fbc = 0x2000707f;
fbc->rop = 0x83;
fbc->pmask = 0xffffffff;
- fbc->bg = ffb_cmap[attr_bg_col(*s)];
+ fbc->bg = ffb_cmap[attr_bgcol(p,*s)];
xy = fb->s.ffb.xy_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ xy += xx * 8;
+#else
if (p->fontwidthlog)
xy += (xx << p->fontwidthlog);
else
xy += xx * p->fontwidth;
+#endif
if (p->fontheightlog)
xy += (yy << (16 + p->fontheightlog));
else
xy += ((yy * p->fontheight) << 16);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
while (count >= 4) {
count -= 4;
fbc->fontw = 4 * p->fontwidth;
fbc->fontinc = 0x10000;
fbc->fontxy = xy;
if (p->fontheightlog) {
- fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
- fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+ fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+ fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
} else {
- fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
- fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+ fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+ fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth == 8) {
+#endif
for (i = 0; i < p->fontheight; i++)
fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
<< 8)) << 8)) << 8);
xy += 32;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
for (i = 0; i < p->fontheight; i++)
fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
fbc->fontinc = 0x10000;
fbc->fontxy = xy;
if (p->fontheightlog) {
- fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
- fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+ fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+ fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
} else {
- fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
- fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+ fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+ fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
}
for (i = 0; i < p->fontheight; i++) {
fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
}
xy += 2 * p->fontwidth;
}
+#endif
}
while (count) {
count--;
fbc->fontinc = 0x10000;
fbc->fontxy = xy;
if (p->fontheightlog)
- i = ((*s++ & 0xff) << p->fontheightlog);
+ i = ((*s++ & p->charmask) << p->fontheightlog);
else
- i = ((*s++ & 0xff) * p->fontheight);
+ i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
if (p->fontwidth <= 8) {
+#endif
fd1 = p->fontdata + i;
for (i = 0; i < p->fontheight; i++)
fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
} else {
fd1 = p->fontdata + (i << 1);
for (i = 0; i < p->fontheight; i++) {
fd1 += 2;
}
}
+#endif
xy += p->fontwidth;
}
}
strcpy(fb->info.modename, "Creator");
strcpy(fix->id, "Creator");
- fix->smem_start = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF;
fix->visual = FB_VISUAL_DIRECTCOLOR;
fix->line_length = 8192;
- fix->mmio_start = (char *)(regs[0].phys_addr) + FFB_FBC_REGS_POFF;
- fix->mmio_len = PAGE_SIZE;
fix->accel = FB_ACCEL_SUN_CREATOR;
var->bits_per_pixel = 32;
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
+#include <linux/config.h>
#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/segment.h>
* available, usually until fbcon takes console over.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/tty.h>
* Dummy console driver
*/
-#ifdef __sparc__
-/* Some reasonable defaults, so that we don't loose any text */
-#define DUMMY_COLUMNS 128
-#define DUMMY_ROWS 54
-#elif defined(CONFIG_ARM)
+#if defined(CONFIG_ARM)
#define DUMMY_COLUMNS ORIG_VIDEO_COLS
#define DUMMY_ROWS ORIG_VIDEO_LINES
#else
int fg, bg;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
- cdat0 = p->fontdata+(c&0xff)*p->fontheight;
+ cdat0 = p->fontdata+(c&p->charmask)*p->fontheight;
fg = attr_fgcol(p,c);
bg = attr_bgcol(p,c);
u8 *dest, *dest0, *dest1, *expand;
u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
u_short i, j;
- u8 c1, c2, c3, c4;
+ u16 c1, c2, c3, c4;
int fg0, bg0, fg, bg;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
while (count--)
if (xx&3 || count < 3) { /* Slow version */
- c1 = *s++;
+ c1 = *s++ & p->charmask;
dest1 = dest0++;
xx++;
dest1 += p->next_plane;
} while (--i);
} else { /* Fast version */
- c1 = s[0];
- c2 = s[1];
- c3 = s[2];
- c4 = s[3];
+ c1 = s[0] & p->charmask;
+ c2 = s[1] & p->charmask;
+ c3 = s[2] & p->charmask;
+ c4 = s[3] & p->charmask;
dest1 = dest0;
cdat10 = p->fontdata+c1*p->fontheight;
* Amiga bitplanes (afb)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE)
#define FBCON_HAS_AFB
int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
u8 *src, *dst;
- if (sx == 0 && dx == 0 && width * 16 == bytes)
+ if (sx == 0 && dx == 0 && width * p->fontwidth * 2 == bytes) {
mymemmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
- else if (dy < sy || (dy == sy && dx < sx)) {
- src = p->screen_base + sy * linesize + sx * 16;
- dst = p->screen_base + dy * linesize + dx * 16;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 16);
+ return;
+ }
+ if (p->fontwidthlog) {
+ sx <<= p->fontwidthlog+1;
+ dx <<= p->fontwidthlog+1;
+ width <<= p->fontwidthlog+1;
+ } else {
+ sx *= p->fontwidth*2;
+ dx *= p->fontwidth*2;
+ width *= p->fontwidth*2;
+ }
+ if (dy < sy || (dy == sy && dx < sx)) {
+ src = p->screen_base + sy * linesize + sx;
+ dst = p->screen_base + dy * linesize + dx;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src += bytes;
dst += bytes;
}
} else {
- src = p->screen_base + (sy+height) * linesize + sx * 16 - bytes;
- dst = p->screen_base + (dy+height) * linesize + dx * 16 - bytes;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 16);
+ src = p->screen_base + (sy+height) * linesize + sx - bytes;
+ dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
int bytes = p->next_line, lines = height * p->fontheight, rows, i;
u32 bgx;
- dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 2;
bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
bgx |= (bgx << 16);
- if (sx == 0 && width * 16 == bytes)
- for (i = 0 ; i < lines * width ; i++) {
+ width *= p->fontwidth/4;
+ if (sx == 0 && width * 8 == bytes)
+ for (i = 0; i < lines * width; i++) {
((u32 *)dest)[0] = bgx;
((u32 *)dest)[1] = bgx;
- ((u32 *)dest)[2] = bgx;
- ((u32 *)dest)[3] = bgx;
- dest += 16;
+ dest += 8;
}
else {
dest0 = dest;
- for (rows = lines; rows-- ; dest0 += bytes) {
+ for (rows = lines; rows--; dest0 += bytes) {
dest = dest0;
- for (i = 0 ; i < width ; i++) {
+ for (i = 0; i < width; i++) {
((u32 *)dest)[0] = bgx;
((u32 *)dest)[1] = bgx;
- ((u32 *)dest)[2] = bgx;
- ((u32 *)dest)[3] = bgx;
- dest += 16;
+ dest += 8;
}
}
}
void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
int xx)
{
- u8 *dest, *cdat;
+ u8 *dest, *cdat, bits;
int bytes = p->next_line, rows;
u32 eorx, fgx, bgx;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
fgx = fbcon_cfb16_cmap[attr_fgcol(p, c)];
bgx = fbcon_cfb16_cmap[attr_bgcol(p, c)];
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ switch (p->fontwidth) {
+ case 4:
+ case 8:
+#endif
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+ bits = *cdat++;
+ ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth == 8)
+#endif
+ {
+ ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ }
+ }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ break;
+ case 12:
+ case 16:
+ cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+ for (rows = p->fontheight; rows--; dest += bytes) {
+ bits = *cdat++;
+ ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ bits = *cdat++;
+ ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ if (p->fontwidth == 16) {
+ ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ break;
}
+#endif
}
-void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
+void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0;
+ u16 c;
int rows, bytes = p->next_line;
u32 eorx, fgx, bgx;
- dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
fgx = fbcon_cfb16_cmap[attr_fgcol(p, *s)];
bgx = fbcon_cfb16_cmap[attr_bgcol(p, *s)];
fgx |= (fgx << 16);
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
- while (count--) {
- c = *s++;
- cdat = p->fontdata + c * p->fontheight;
- for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ switch (p->fontwidth) {
+ case 4:
+ case 8:
+#endif
+ while (count--) {
+ c = *s++ & p->charmask;
+ cdat = p->fontdata + c * p->fontheight;
+ for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+ u8 bits = *cdat++;
+ ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth == 8)
+#endif
+ {
+
+ ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ dest0 += p->fontwidth*2;;
}
- dest0 += 16;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ break;
+ case 12:
+ case 16:
+ while (count--) {
+ c = *s++ & p->charmask;
+ cdat = p->fontdata + (c * p->fontheight << 1);
+ for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+ u8 bits = *cdat++;
+ ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ bits = *cdat++;
+ ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+ ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ if (p->fontwidth == 16) {
+ ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ dest0 += p->fontwidth*2;
+ }
+ break;
}
+#endif
}
void fbcon_cfb16_revc(struct display *p, int xx, int yy)
u8 *dest;
int bytes = p->next_line, rows;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0] ^= 0xffffffff;
- ((u32 *)dest)[1] ^= 0xffffffff;
- ((u32 *)dest)[2] ^= 0xffffffff;
- ((u32 *)dest)[3] ^= 0xffffffff;
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth*2;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+#else
+ switch (p->fontwidth) {
+ case 16:
+ ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 12:
+ ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 8:
+ ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 4:
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ }
+#endif
+ }
+}
+
+void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p)
+{
+ u8 *dest0;
+ u32 *dest;
+ int bytes = p->next_line;
+ u32 bgx;
+ int i, j;
+
+ unsigned int right_start = conp->vc_cols*p->fontwidth;
+ unsigned int right_width = p->var.xres_virtual-right_start;
+ unsigned int bottom_start = conp->vc_rows*p->fontheight;
+ unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+ bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
+ bgx |= (bgx << 16);
+
+ if (right_width) {
+ dest0 = p->screen_base+right_start*2;
+ for (i = 0; i < bottom_start; i++, dest0 += bytes) {
+ for (j = 0, dest = (u32 *)dest0; j < right_width/2; j++)
+ *dest++ = bgx;
+ if (right_width & 1)
+ *(u16 *)dest = bgx;
+ }
+ }
+ if (bottom_width) {
+ dest = (u32 *)(p->screen_base+bottom_start*bytes);
+ for (i = 0; i < bytes*bottom_width/4; i++)
+ *dest++ = bgx;
+ if ((bytes*bottom_width) & 2)
+ *(u16 *)dest = bgx;
}
}
struct display_switch fbcon_cfb16 = {
fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
- fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
* 16 bpp packed pixel (cfb16)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE)
#define FBCON_HAS_CFB16
extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx);
extern void fbcon_cfb16_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p);
u32 eorx,fgx,bgx;
dest = p->screen_base + yy * p->fontheight * bytes + xx * 2;
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
fgx=3;/*attr_fgcol(p,c);*/
bgx=attr_bgcol(p,c);
void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0;
+ u16 c;
int rows,bytes=p->next_line;
u32 eorx, fgx, bgx;
bgx |= (bgx << 4);
eorx = fgx ^ bgx;
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
* 2 bpp packed pixel (cfb2)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE)
#define FBCON_HAS_CFB2
int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
u8 *src, *dst;
- if (sx == 0 && dx == 0 && width * 24 == bytes)
+ if (sx == 0 && dx == 0 && width * p->fontwidth * 3 == bytes) {
mymemmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
- else if (dy < sy || (dy == sy && dx < sx)) {
- src = p->screen_base + sy * linesize + sx * 24;
- dst = p->screen_base + dy * linesize + dx * 24;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 24);
+ return;
+ }
+ if (p->fontwidthlog) {
+ sx <<= p->fontwidthlog;
+ dx <<= p->fontwidthlog;
+ width <<= p->fontwidthlog;
+ } else {
+ sx *= p->fontwidth;
+ dx *= p->fontwidth;
+ width *= p->fontwidth;
+ }
+ sx *= 3; dx *= 3; width *= 3;
+ if (dy < sy || (dy == sy && dx < sx)) {
+ src = p->screen_base + sy * linesize + sx;
+ dst = p->screen_base + dy * linesize + dx;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src += bytes;
dst += bytes;
}
} else {
- src = p->screen_base + (sy+height) * linesize + sx * 24 - bytes;
- dst = p->screen_base + (dy+height) * linesize + dx * 24 - bytes;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 24);
+ src = p->screen_base + (sy+height) * linesize + sx - bytes;
+ dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
}
}
+static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
+{
+#if defined(__BIG_ENDIAN)
+ *dest++ = (d1<<8) | (d2>>16);
+ *dest++ = (d2<<16) | (d3>>8);
+ *dest++ = (d3<<24) | d4;
+#elif defined(__LITTLE_ENDIAN)
+ *dest++ = (d1<<8) | (d2>>16);
+ *dest++ = (d2<<16) | (d3>>8);
+ *dest++ = (d3<<24) | d4;
+#else
+#error FIXME: No endianness??
+#endif
+}
+
void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx,
int height, int width)
{
int bytes = p->next_line, lines = height * p->fontheight, rows, i;
u32 bgx;
- dest = p->screen_base + sy * p->fontheight * bytes + sx * 24;
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 3;
bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
- if (sx == 0 && width * 24 == bytes)
- for (i = 0 ; i < lines * width ; i++) {
- ((u32 *)dest)[0] = bgx;
- ((u32 *)dest)[1] = bgx;
- ((u32 *)dest)[2] = bgx;
- ((u32 *)dest)[3] = bgx;
- ((u32 *)dest)[4] = bgx;
- ((u32 *)dest)[5] = bgx;
- dest += 24;
+ width *= p->fontwidth/4;
+ if (sx == 0 && width * 12 == bytes)
+ for (i = 0; i < lines * width; i++) {
+ store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+ dest += 12;
}
else {
dest0 = dest;
- for (rows = lines; rows-- ; dest0 += bytes) {
+ for (rows = lines; rows--; dest0 += bytes) {
dest = dest0;
- for (i = 0 ; i < width ; i++) {
- ((u32 *)dest)[0] = bgx;
- ((u32 *)dest)[1] = bgx;
- ((u32 *)dest)[2] = bgx;
- ((u32 *)dest)[3] = bgx;
- ((u32 *)dest)[4] = bgx;
- ((u32 *)dest)[5] = bgx;
- dest += 24;
+ for (i = 0; i < width; i++) {
+ store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+ dest += 12;
}
}
}
}
-static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
-{
-#if defined(__BIG_ENDIAN)
- *dest++ = (d1<<8) | (d2>>16);
- *dest++ = (d2<<16) | (d3>>8);
- *dest++ = (d3<<24) | d4;
-#elif defined(__LITTLE_ENDIAN)
- *dest++ = (d1<<8) | (d2>>16);
- *dest++ = (d2<<16) | (d3>>8);
- *dest++ = (d3<<24) | d4;
-#else
-#error FIXME: No endianness??
-#endif
-}
-
void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy,
int xx)
{
- u8 *dest, *cdat;
+ u8 *dest, *cdat, bits;
int bytes = p->next_line, rows;
- u32 eorx, fgx, bgx;
+ u32 eorx, fgx, bgx, d1, d2, d3, d4;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+ if (p->fontwidth <= 8)
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+ else
+ cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
fgx = fbcon_cfb24_cmap[attr_fgcol(p, c)];
bgx = fbcon_cfb24_cmap[attr_bgcol(p, c)];
eorx = fgx ^ bgx;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
- u32 d1, d2, d3, d4;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+ bits = *cdat++;
d1 = (-(bits >> 7) & eorx) ^ bgx;
d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 8)
+ continue;
+#endif
d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
d4 = (-(bits & 1) & eorx) ^ bgx;
store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 12)
+ continue;
+ bits = *cdat++;
+ d1 = (-(bits >> 7) & eorx) ^ bgx;
+ d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+ d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+ d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+ if (p->fontwidth < 16)
+ continue;
+ d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+ d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+ d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+ d4 = (-(bits & 1) & eorx) ^ bgx;
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
}
}
-void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
+void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0, bits;
+ u16 c;
int rows, bytes = p->next_line;
- u32 eorx, fgx, bgx;
+ u32 eorx, fgx, bgx, d1, d2, d3, d4;
- dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
fgx = fbcon_cfb24_cmap[attr_fgcol(p, *s)];
bgx = fbcon_cfb24_cmap[attr_bgcol(p, *s)];
eorx = fgx ^ bgx;
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
cdat = p->fontdata + c * p->fontheight;
-
- for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
- u32 d1, d2, d3, d4;
+#else
+ if (p->fontwidth <= 8)
+ cdat = p->fontdata + c * p->fontheight;
+
+ else
+ cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+ for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+ bits = *cdat++;
d1 = (-(bits >> 7) & eorx) ^ bgx;
d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 8)
+ continue;
+#endif
d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
d4 = (-(bits & 1) & eorx) ^ bgx;
store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 12)
+ continue;
+ bits = *cdat++;
+ d1 = (-(bits >> 7) & eorx) ^ bgx;
+ d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+ d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+ d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+ if (p->fontwidth < 16)
+ continue;
+ d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+ d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+ d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+ d4 = (-(bits & 1) & eorx) ^ bgx;
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
}
- dest0 += 24;
+ dest0 += p->fontwidth*3;
}
}
u8 *dest;
int bytes = p->next_line, rows;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0] ^= 0xffffffff;
- ((u32 *)dest)[1] ^= 0xffffffff;
- ((u32 *)dest)[2] ^= 0xffffffff;
- ((u32 *)dest)[3] ^= 0xffffffff;
- ((u32 *)dest)[4] ^= 0xffffffff;
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
((u32 *)dest)[5] ^= 0xffffffff;
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff;
+#else
+ switch (p->fontwidth) {
+ case 16:
+ ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff;
+ ((u32 *)dest)[11] ^= 0xffffffff; /* FALL THROUGH */
+ case 12:
+ ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ ((u32 *)dest)[8] ^= 0xffffffff; /* FALL THROUGH */
+ case 8:
+ ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
+ ((u32 *)dest)[5] ^= 0xffffffff; /* FALL THROUGH */
+ case 4:
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff;
+ }
+#endif
+ }
+}
+
+void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p)
+{
+ u8 *dest0, *dest;
+ int bytes = p->next_line;
+ u32 bgx;
+ int i, j;
+
+ unsigned int right_start = conp->vc_cols*p->fontwidth;
+ unsigned int right_width = p->var.xres_virtual-right_start;
+ unsigned int bottom_start = conp->vc_rows*p->fontheight;
+ unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+ bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
+
+ if (right_width) {
+ dest0 = p->screen_base+right_start*3;
+ for (i = 0; i < bottom_start; i++, dest0 += bytes)
+ for (j = 0, dest = dest0; j < right_width/4; j++) {
+ store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+ dest += 12;
+ }
+ }
+ if (bottom_width) {
+ dest = p->screen_base+bottom_start*bytes;
+ for (i = 0; i < bytes*bottom_width/12; i++) {
+ store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+ dest += 12;
+ }
}
}
struct display_switch fbcon_cfb24 = {
fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
- fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
* 24 bpp packed pixel (cfb24)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE)
#define FBCON_HAS_CFB24
extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx);
extern void fbcon_cfb24_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p);
int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
u8 *src, *dst;
- if (sx == 0 && dx == 0 && width * 32 == bytes)
+ if (sx == 0 && dx == 0 && width * p->fontwidth * 4 == bytes) {
mymemmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
- else if (dy < sy || (dy == sy && dx < sx)) {
- src = p->screen_base + sy * linesize + sx * 32;
- dst = p->screen_base + dy * linesize + dx * 32;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 32);
+ return;
+ }
+ if (p->fontwidthlog) {
+ sx <<= p->fontwidthlog+2;
+ dx <<= p->fontwidthlog+2;
+ width <<= p->fontwidthlog+2;
+ } else {
+ sx *= p->fontwidth*4;
+ dx *= p->fontwidth*4;
+ width *= p->fontwidth*4;
+ }
+ if (dy < sy || (dy == sy && dx < sx)) {
+ src = p->screen_base + sy * linesize + sx;
+ dst = p->screen_base + dy * linesize + dx;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src += bytes;
dst += bytes;
}
} else {
- src = p->screen_base + (sy+height) * linesize + sx * 32 - bytes;
- dst = p->screen_base + (dy+height) * linesize + dx * 32 - bytes;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 32);
+ src = p->screen_base + (sy+height) * linesize + sx - bytes;
+ dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+ for (rows = height * p->fontheight; rows--;) {
+ mymemmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
int bytes = p->next_line, lines = height * p->fontheight, rows, i;
u32 bgx;
- dest = p->screen_base + sy * p->fontheight * bytes + sx * 32;
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 4;
bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
- if (sx == 0 && width * 32 == bytes)
- for (i = 0 ; i < lines * width ; i++) {
+ width *= p->fontwidth/4;
+ if (sx == 0 && width * 16 == bytes)
+ for (i = 0; i < lines * width; i++) {
((u32 *)dest)[0] = bgx;
((u32 *)dest)[1] = bgx;
((u32 *)dest)[2] = bgx;
((u32 *)dest)[3] = bgx;
- ((u32 *)dest)[4] = bgx;
- ((u32 *)dest)[5] = bgx;
- ((u32 *)dest)[6] = bgx;
- ((u32 *)dest)[7] = bgx;
- dest += 32;
+ dest += 16;
}
else {
dest0 = dest;
- for (rows = lines; rows-- ; dest0 += bytes) {
+ for (rows = lines; rows--; dest0 += bytes) {
dest = dest0;
- for (i = 0 ; i < width ; i++) {
+ for (i = 0; i < width; i++) {
((u32 *)dest)[0] = bgx;
((u32 *)dest)[1] = bgx;
((u32 *)dest)[2] = bgx;
((u32 *)dest)[3] = bgx;
- ((u32 *)dest)[4] = bgx;
- ((u32 *)dest)[5] = bgx;
- ((u32 *)dest)[6] = bgx;
- ((u32 *)dest)[7] = bgx;
- dest += 32;
+ dest += 16;
}
}
}
void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
int xx)
{
- u8 *dest, *cdat;
+ u8 *dest, *cdat, bits;
int bytes = p->next_line, rows;
u32 eorx, fgx, bgx;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
-
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+#else
+ if (p->fontwidth <= 8)
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+ else
+ cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+#endif
fgx = fbcon_cfb32_cmap[attr_fgcol(p, c)];
bgx = fbcon_cfb32_cmap[attr_bgcol(p, c)];
eorx = fgx ^ bgx;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+ bits = *cdat++;
((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 8)
+ continue;
+#endif
((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 12)
+ continue;
+ bits = *cdat++;
+ ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+ ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ if (p->fontwidth < 16)
+ continue;
+ ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
}
}
-void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
+void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0, bits;
+ u16 c;
int rows, bytes = p->next_line;
u32 eorx, fgx, bgx;
- dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
fgx = fbcon_cfb32_cmap[attr_fgcol(p, *s)];
bgx = fbcon_cfb32_cmap[attr_bgcol(p, *s)];
eorx = fgx ^ bgx;
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
cdat = p->fontdata + c * p->fontheight;
-
- for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- u8 bits = *cdat++;
+#else
+ if (p->fontwidth <= 8)
+ cdat = p->fontdata + c * p->fontheight;
+ else
+ cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+ for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+ bits = *cdat++;
((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 8)
+ continue;
+#endif
((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth < 12)
+ continue;
+ bits = *cdat++;
+ ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+ ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ if (p->fontwidth < 16)
+ continue;
+ ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+ ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
}
- dest0 += 32;
+ dest0 += p->fontwidth*4;
}
}
u8 *dest;
int bytes = p->next_line, rows;
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0] ^= 0xffffffff;
- ((u32 *)dest)[1] ^= 0xffffffff;
- ((u32 *)dest)[2] ^= 0xffffffff;
- ((u32 *)dest)[3] ^= 0xffffffff;
- ((u32 *)dest)[4] ^= 0xffffffff;
- ((u32 *)dest)[5] ^= 0xffffffff;
- ((u32 *)dest)[6] ^= 0xffffffff;
- ((u32 *)dest)[7] ^= 0xffffffff;
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+ for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+ ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+#else
+ switch (p->fontwidth) {
+ case 16:
+ ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff;
+ ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 12:
+ ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff;
+ ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 8:
+ ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+ ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 4:
+ ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+ /* FALL THROUGH */
+ }
+#endif
+ }
+}
+
+void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p)
+{
+ u8 *dest0;
+ u32 *dest;
+ int bytes = p->next_line;
+ u32 bgx;
+ int i, j;
+
+ unsigned int right_start = conp->vc_cols*p->fontwidth;
+ unsigned int right_width = p->var.xres_virtual-right_start;
+ unsigned int bottom_start = conp->vc_rows*p->fontheight;
+ unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+ bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
+
+ if (right_width) {
+ dest0 = p->screen_base+right_start*4;
+ for (i = 0; i < bottom_start; i++, dest0 += bytes)
+ for (j = 0, dest = (u32 *)dest0; j < right_width; j++)
+ *dest++ = bgx;
+ }
+ if (bottom_width) {
+ dest = (u32 *)(p->screen_base+bottom_start*bytes);
+ for (i = 0; i < bytes*bottom_width/4; i++)
+ *dest++ = bgx;
}
}
struct display_switch fbcon_cfb32 = {
fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
- fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+ fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
* 32 bpp packed pixel (cfb32)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE)
#define FBCON_HAS_CFB32
extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx);
extern void fbcon_cfb32_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p);
u32 eorx,fgx,bgx;
dest = p->screen_base + yy * p->fontheight * bytes + xx * 4;
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
fgx=15;/*attr_fgcol(p,c);*/
bgx=attr_bgcol(p,c);
void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0;
+ u16 c;
int rows,bytes=p->next_line;
u32 eorx, fgx, bgx;
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
* 4 bpp packed pixel (cfb4)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE)
#define FBCON_HAS_CFB4
dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
if (p->fontwidth <= 8)
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
else
- cdat = p->fontdata + ((c & 0xff) * p->fontheight << 1);
+ cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
fgx=attr_fgcol(p,c);
bgx=attr_bgcol(p,c);
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
switch (p->fontwidth) {
case 4:
for (rows = p->fontheight ; rows-- ; dest += bytes)
((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
break;
case 8:
+#endif
for (rows = p->fontheight ; rows-- ; dest += bytes) {
((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
break;
case 12:
case 16:
}
break;
}
+#endif
}
void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
- u8 *cdat, c, *dest, *dest0;
+ u8 *cdat, *dest, *dest0;
+ u16 c;
int rows,bytes=p->next_line;
u32 eorx, fgx, bgx;
bgx |= (bgx << 8);
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
switch (p->fontwidth) {
case 4:
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes)
}
break;
case 8:
+#endif
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
}
dest0+=8;
}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
break;
case 12:
case 16:
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + (c * p->fontheight << 1);
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
}
break;
}
+#endif
}
void fbcon_cfb8_revc(struct display *p, int xx, int yy)
dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
for (rows = p->fontheight ; rows-- ; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ ((u32 *)dest)[1] ^= 0x0f0f0f0f;
+ ((u32 *)dest)[0] ^= 0x0f0f0f0f;
+#else
switch (p->fontwidth) {
case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */
case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */
case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f; /* FALL THROUGH */
default: break;
}
+#endif
}
}
* 8 bpp packed pixel (cfb8)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE)
#define FBCON_HAS_CFB8
int fg0, bg0, fg, bg;
dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
- cdat = p->fontdata+(c&0xff)*p->fontheight;
+ cdat = p->fontdata+(c&p->charmask)*p->fontheight;
fg0 = attr_fgcol(p,c);
bg0 = attr_bgcol(p,c);
{
u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
u_int rows, i;
- u8 c1, c2, c3, c4;
+ u16 c1, c2, c3, c4;
u32 d;
int fg0, bg0, fg, bg;
while (count--)
if (xx&3 || count < 3) { /* Slow version */
- c1 = *s++;
+ c1 = *s++ & p->charmask;
dest = dest0++;
xx++;
}
}
} else { /* Fast version */
- c1 = s[0];
- c2 = s[1];
- c3 = s[2];
- c4 = s[3];
+ c1 = s[0] & p->charmask;
+ c2 = s[1] & p->charmask;
+ c3 = s[2] & p->charmask;
+ c4 = s[3] & p->charmask;
dest = dest0;
cdat1 = p->fontdata+c1*p->fontheight;
* Amiga interleaved bitplanes (ilbm)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE)
#define FBCON_HAS_ILBM
u16 eorx, fgx, bgx, fdx;
dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1);
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
fgx = expand2w(COLOR_2P(attr_fgcol(p,c)));
bgx = expand2w(COLOR_2P(attr_bgcol(p,c)));
const unsigned short *s, int count, int yy, int xx)
{
u8 *dest, *dest0;
- u8 *cdat, c;
+ u8 *cdat;
+ u16 c;
int rows;
int bytes;
u16 eorx, fgx, bgx, fdx;
eorx = fgx ^ bgx;
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + (c * p->fontheight);
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
* Atari interleaved bitplanes (2 planes) (iplan2p2)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE)
#define FBCON_HAS_IPLAN2P2
u32 eorx, fgx, bgx, fdx;
dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1);
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
fgx = expand4l(attr_fgcol(p,c));
bgx = expand4l(attr_bgcol(p,c));
const unsigned short *s, int count, int yy, int xx)
{
u8 *dest, *dest0;
- u8 *cdat, c;
+ u8 *cdat;
+ u16 c;
int rows;
int bytes;
u32 eorx, fgx, bgx, fdx;
* cache :-(
*/
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + (c * p->fontheight);
for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
* Atari interleaved bitplanes (4 planes) (iplan2p4)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE)
#define FBCON_HAS_IPLAN2P4
u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1);
- cdat = p->fontdata + (c & 0xff) * p->fontheight;
+ cdat = p->fontdata + (c & p->charmask) * p->fontheight;
expand8dl(attr_fgcol(p,c), &fgx1, &fgx2);
expand8dl(attr_bgcol(p,c), &bgx1, &bgx2);
const unsigned short *s, int count, int yy, int xx)
{
u8 *dest, *dest0;
- u8 *cdat, c;
+ u8 *cdat;
+ u16 c;
int rows;
int bytes;
u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
* cache :-(
*/
- c = *s++;
+ c = *s++ & p->charmask;
cdat = p->fontdata + (c * p->fontheight);
for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
* Atari interleaved bitplanes (8 planes) (iplan2p8)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE)
#define FBCON_HAS_IPLAN2P8
u8 d;
int j;
- cdat = p->fontdata+(c&0xff)*p->fontheight;
+ cdat = p->fontdata+(c&p->charmask)*p->fontheight;
bold = attr_bold(p,c);
ch_reverse = attr_reverse(p,c);
ch_underline = attr_underline(p,c);
* Mac variable bpp packed pixels (mac)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE)
#define FBCON_HAS_MAC
u8 d;
dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
- cdat = p->fontdata+(c&0xff)*p->fontheight;
+ cdat = p->fontdata+(c&p->charmask)*p->fontheight;
bold = attr_bold(p,c);
revs = attr_reverse(p,c);
underl = attr_underline(p,c);
{
u8 *dest, *dest0, *cdat;
u_int rows, bold, revs, underl;
- u8 c, d;
+ u8 d;
+ u16 c;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
bold = attr_bold(p,*s);
underl = attr_underline(p,*s);
while (count--) {
- c = *s++;
+ c = *s++ & p->charmask;
dest = dest0++;
cdat = p->fontdata+c*p->fontheight;
for (rows = p->fontheight; rows--; dest += p->next_line) {
* Monochrome (mfb)
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE)
#define FBCON_HAS_MFB
* VGA characters/attributes
*/
-#include <linux/config.h>
-
#ifdef MODULE
#if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE)
#define FBCON_HAS_VGA
* Andreas Schwab
*
* Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
- * Smart redraw scrolling, arbitrary font width support added by
+ * Smart redraw scrolling, arbitrary font width support, 512char font support
+ * added by
* Jakub Jelinek (jj@ultra.linux.cz)
*
*
#define LOGO_LINE (LOGO_W/8)
struct display fb_display[MAX_NR_CONSOLES];
-
+static int logo_lines;
+static int logo_shown = -1;
/*
* Emmanuel: fbcon will now use a hardware cursor if the
int nr_rows, nr_cols;
int old_rows, old_cols;
unsigned short *save = NULL, *r, *q;
- int logo_lines = 0;
/* Only if not module */
extern int initmem_freed;
struct fbcon_font_desc *font;
-
if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
logo = 0;
}
p->vrows = p->var.yres_virtual/p->fontheight;
conp->vc_can_do_color = p->var.bits_per_pixel != 1;
+ p->fgshift = 8;
+ p->bgshift = 12;
+ p->charmask = 0xff;
+ conp->vc_hi_font_mask = 0;
if (!p->dispsw) {
printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
update_screen(con); /* So that we set origin correctly */
}
- if (logo)
+ if (logo) {
+ logo_shown = fg_console;
fbcon_show_logo(); /* This is protected above by initmem_freed */
+ conp->vc_top = logo_lines;
+ }
}
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
-
+
if (!p->can_soft_blank && console_blanked)
return;
return;
if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
- (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
- ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
- (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
+ (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
+ ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
+ (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
fbcon_cursor(conp, CM_ERASE);
/* Split blits that cross physical y_wrap case.
fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
}
-
static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
int height, int width, u_int y_break)
{
struct display *p = &fb_display[unit];
struct fb_info *info = p->fb_info;
+ if (logo_shown >= 0) {
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+ if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows)
+ conp2->vc_top = 0;
+ logo_shown = -1;
+ }
p->var.yoffset = p->yscroll*p->fontheight;
switch (p->scrollmode) {
case SCROLL_YWRAP:
static inline int fbcon_get_font(int unit, struct console_font_op *op)
{
struct display *p = &fb_display[unit];
- char *data = op->data;
+ u8 *data = op->data;
int i, j;
- if (p->fontwidth != 8) /* FIXME: Implement for wide fonts */
- return -EINVAL;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (p->fontwidth != 8) return -EINVAL;
+#endif
op->width = p->fontwidth;
op->height = p->fontheight;
- op->charcount = 256;
- for (i = 0; i < 256; i++)
- for (j = 0; j < p->fontheight; j++)
- data[i*32+j] = p->fontdata[i*p->fontheight+j];
+ op->charcount = (p->charmask == 0x1ff) ? 512 : 256;
+ if (!op->data) return 0;
+
+ if (op->width <= 8) {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < p->fontheight; j++)
+ *data++ = p->fontdata[i*p->fontheight+j];
+ data += 32 - p->fontheight;
+ }
+ }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ else if (op->width <= 16) {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < p->fontheight; j++) {
+ *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8;
+ *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j];
+ }
+ data += 2 * (32 - p->fontheight);
+ }
+ } else if (op->width <= 24) {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < p->fontheight; j++) {
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+ }
+ data += 3 * (32 - p->fontheight);
+ }
+ } else {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < p->fontheight; j++) {
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+ *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j];
+ }
+ data += 4 * (32 - p->fontheight);
+ }
+ }
+#endif
return 0;
}
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+#define FNTSUM(fd) (((int *)(fd))[-4])
static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont)
{
int resize;
int w = op->width;
int h = op->height;
+ int cnt;
char *old_data = NULL;
if (!fontwidthvalid(p,w)) {
resize = (w != p->fontwidth) || (h != p->fontheight);
if (p->userfont)
old_data = p->fontdata;
+ if (userfont)
+ cnt = FNTCHARCNT(data);
+ else
+ cnt = 256;
p->fontdata = data;
if ((p->userfont = userfont))
REFCOUNT(data)++;
p->fontwidth = w;
p->fontheight = h;
+ if (p->conp->vc_hi_font_mask && cnt == 256) {
+ p->conp->vc_hi_font_mask = 0;
+ p->conp->vc_complement_mask >>= 1;
+ p->fgshift--;
+ p->bgshift--;
+ p->charmask = 0xff;
+ } else if (!p->conp->vc_hi_font_mask && cnt == 512) {
+ p->conp->vc_hi_font_mask = 0x100;
+ p->conp->vc_complement_mask <<= 1;
+ p->fgshift++;
+ p->bgshift++;
+ p->charmask = 0x1ff;
+ }
fbcon_font_widths(p);
if (resize) {
update_screen( unit );
if (old_data && (--REFCOUNT(old_data) == 0))
- kfree( old_data - 2*sizeof(int) );
+ kfree( old_data - 4*sizeof(int) );
return 0;
}
od = &fb_display[h];
if (od->fontdata == p->fontdata)
return 0; /* already the same font... */
+ op->width = od->fontwidth;
+ op->height = od->fontheight;
return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);
}
{
int w = op->width;
int h = op->height;
- int size = (w+7)/8 * h * 256;
- int i, j;
- u8 *new_data, *data = op->data;
+ int size = h;
+ int i, j, k;
+ u8 *new_data, *data = op->data, c, *p;
+ u32 d;
- if (w != 8 || op->charcount != 256)
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+ if (w != 8)
+ return -EINVAL;
+#endif
+
+ if (w > 32 || (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
+
+ if (w > 8) {
+ if (w <= 16)
+ size *= 2;
+ else
+ size *= 4;
+ }
+ size *= op->charcount;
- if (!(new_data = kmalloc( 2*sizeof(int)+size, GFP_USER )))
+ if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER )))
return -ENOMEM;
- new_data += 2*sizeof(int);
+ new_data += 4*sizeof(int);
FNTSIZE(new_data) = size;
+ FNTCHARCNT(new_data) = op->charcount;
REFCOUNT(new_data) = 0; /* usage counter */
- for (i = 0; i < 256; i++)
- for (j = 0; j < h; j++)
- new_data[i*h+j] = data[i*32+j];
+ k = 0;
+ p = data;
+ if (w <= 8) {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < h; j++) {
+ c = *p++;
+ k += c;
+ new_data[i*h+j] = c;
+ }
+ p += 32 - h;
+ }
+ }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+ else if (w <= 16) {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < h; j++) {
+ d = (p[0] << 8) | p[1];
+ p += 2;
+ k += d;
+ ((u16 *)new_data)[i*h+j] = d;
+ }
+ p += 2*(32 - h);
+ }
+ } else {
+ for (i = 0; i < op->charcount; i++) {
+ for (j = 0; j < h; j++) {
+ if (w <= 24) {
+ d = (p[0] << 24) |
+ (p[1] << 16) |
+ (p[2] << 8);
+ p += 3;
+ } else {
+ d = (p[0] << 24) |
+ (p[1] << 16) |
+ (p[2] << 8) |
+ p[3];
+ p += 4;
+ }
+ k += d;
+ ((u32 *)new_data)[i*h+j] = d;
+ }
+ if (w <= 24)
+ p += 3*(32 - h);
+ else
+ p += 4*(32 - h);
+ }
+ }
+#endif
+ FNTSUM(new_data) = k;
+ /* Check if the same font is on some other console already */
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (fb_display[i].userfont &&
+ fb_display[i].fontdata &&
+ FNTSUM(fb_display[i].fontdata) == k &&
+ FNTSIZE(fb_display[i].fontdata) == size &&
+ !memcmp(fb_display[i].fontdata, new_data, size)) {
+ kfree(new_data - 4*sizeof(int));
+ new_data = fb_display[i].fontdata;
+ break;
+ }
+ }
return fbcon_do_set_font(unit, op, new_data, 1);
}
}
op->width = f->width;
op->height = f->height;
- op->charcount = 256;
return fbcon_do_set_font(unit, op, f->data, 0);
}
return 0;
}
-
__initfunc(static int fbcon_show_logo( void ))
{
struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
#ifndef __VIDEO_FBCON_H
#define __VIDEO_FBCON_H
+#include <linux/config.h>
#include <linux/console_struct.h>
unsigned int fontwidthmask; /* 1 at (1 << (width - 1)) if width is supported */
};
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+
+/* fontwidth w is supported by dispsw */
+#define FONTWIDTH(w) (1 << ((8) - 1))
+/* fontwidths w1-w2 inclusive are supported by dispsw */
+#define FONTWIDTHRANGE(w1,w2) FONTWIDTH(8)
+
+#else
+
/* fontwidth w is supported by dispsw */
#define FONTWIDTH(w) (1 << ((w) - 1))
/* fontwidths w1-w2 inclusive are supported by dispsw */
#define FONTWIDTHRANGE(w1,w2) (FONTWIDTH(w2+1) - FONTWIDTH(w1))
+#endif
/*
* Attribute Decoding
/* Color */
#define attr_fgcol(p,s) \
- (((s) >> ((p)->inverse ? 12 : 8)) & 0x0f)
+ (((s) >> ((p)->fgshift)) & 0x0f)
#define attr_bgcol(p,s) \
- (((s) >> ((p)->inverse ? 8 : 12)) & 0x0f)
+ (((s) >> ((p)->bgshift)) & 0x0f)
#define attr_bgcol_ec(p,conp) \
- (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
+ (((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f)
/* Monochrome */
#define attr_bold(p,s) \
#include <asm/uaccess.h>
-
static int currcon = 0;
-static struct display disp;
-
-
- /*
- * `Generic' versions of the frame buffer device operations
- */
-
-extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-extern int fbgen_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
-
-
- /*
- * Helper functions
- */
-
-int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
- struct fb_info_gen *info);
-void fbgen_set_disp(int con, struct fb_info_gen *info);
-void fbgen_install_cmap(int con, struct fb_info_gen *info);
-int fbgen_update_var(int con, struct fb_info *info);
-int fbgen_switch(int con, struct fb_info *info);
-void fbgen_blank(int blank, struct fb_info *info);
-
/* ---- `Generic' versions of the frame buffer device operations ----------- */
else
if (fb_display[con].cmap.len) /* non default colormap ? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
return 0;
}
int err;
if (!fb_display[con].cmap.len) { /* no colormap allocated ? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap,
- 1 << fb_display[con].var.bits_per_pixel, 0)))
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
return err;
}
if (con == currcon) /* current console ? */
if (con >= 0)
display = &fb_display[con];
else
- display = &disp; /* used during initialization */
+ display = info->info.disp; /* used during initialization */
if (con == -1)
fbhw->get_par(&par, info);
if (fb_display[con].cmap.len)
fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
fbhw->setcolreg, &info->info);
- else
- fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, fbhw->setcolreg, &info->info);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+ fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+ fbhw->setcolreg, &info->info);
+ }
}
/* Acorn-like font definition, with PC graphics characters */
-#include <linux/config.h>
#include "font.h"
static unsigned char acorndata_8x8[] = {
&font_vga_8x16,
#endif
#ifdef CONFIG_FONT_6x11
-#if !defined(CONFIG_MAC) && !defined(CONFIG_FB_SBUS)
+#if defined(CONFIG_MAC) || defined(CONFIG_FB_SBUS)
#undef NO_FONTS
#endif
&font_vga_6x11,
&font_sun_8x16,
#endif
#ifdef CONFIG_FONT_SUN12x22
-#if !defined(CONFIG_FB_SBUS) && !defined(CONFIG_FBCON_CFB8)
+#if defined(CONFIG_FB_SBUS) || defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB32)
#undef NO_FONTS
#endif
&font_sun_12x22,
* We've been given MAC frame buffer info by the booter. Now go set it up
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
{0,0,0}, /* transparency */
0, /* standard pixel format */
FB_ACTIVATE_NOW,
- 274,195, /* 14" monitor - the late Mikael Nykvist's anyway */
+ 274,195, /* 14" monitor *Mikael Nykvist's anyway* */
0, /* The only way to accelerate a mac is .. */
0L,0L,0L,0L,0L,
0L,0L,0, /* No sync info */
*/
+#include <linux/config.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/string.h>
extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
int *cmode);
extern int mac_map_monitor_sense(int sense);
+
+
+ /*
+ * Addresses in NVRAM where video mode and pixel size are stored.
+ */
+
+#define NV_VMODE 0x140f
+#define NV_CMODE 0x1410
#ifdef CONFIG_FB_CT65550
extern void chips_of_init(struct device_node *dp);
#endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+extern void control_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+extern void platinum_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_PLATINUM */
+
/*
* Initialisation
continue;
}
#endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+ if(!strcmp(dp->name, "control")) {
+ control_of_init(dp);
+ continue;
+ }
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+ if (!strncmp(dp->name, "platinum",8)) {
+ printk("jonh: offb_init sees device node %s\n", dp->name);
+ platinum_of_init(dp);
+ continue;
+ }
+#endif /* CONFIG_FB_PLATINUM */
}
info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
--- /dev/null
+/*
+ * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
+ *
+ * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ * Copyright (C) 1998 Dan Jacobowitz
+ *
+ * Frame buffer structure from:
+ * drivers/video/chipsfb.c -- frame buffer device for
+ * Chips & Technologies 65550 chip.
+ *
+ * Copyright (C) 1998 Paul Mackerras
+ *
+ * This file is derived from the Powermac "chips" driver:
+ * Copyright (C) 1997 Fabio Riccardi.
+ * And from the frame buffer device for Open Firmware-initialized devices:
+ * Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ * Hardware information from:
+ * platinum.c: Console support for PowerMac "platinum" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "platinumfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_platinum {
+ int vmode, cmode;
+ int xres, yres;
+ int vxres, vyres;
+ int xoffset, yoffset;
+};
+
+struct fb_info_platinum {
+ struct fb_info info;
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ struct display disp;
+ struct fb_par_platinum par;
+ struct {
+ __u8 red, green, blue;
+ } palette[256];
+
+ volatile struct cmap_regs *cmap_regs;
+ unsigned long cmap_regs_phys;
+
+ volatile struct platinum_regs *platinum_regs;
+ unsigned long platinum_regs_phys;
+
+ __u8 *frame_buffer;
+ __u8 *base_frame_buffer;
+ unsigned long frame_buffer_phys;
+
+ int sense;
+ unsigned long total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void platinum_init(void);
+void platinum_of_init(struct device_node *dp);
+
+static int platinum_open(struct fb_info *info, int user);
+static int platinum_release(struct fb_info *info, int user);
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+static int read_platinum_sense(struct fb_info_platinum *p);
+static inline int platinum_vram_reqd(int video_mode, int color_mode);
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *params);
+static void platinum_set_hardware(struct fb_info_platinum *p);
+static void platinum_par_to_all(struct fb_info_platinum *p, int init);
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var);
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_platinum *par, const struct fb_info *fb_info);
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p);
+static void platinum_par_to_display(struct fb_par_platinum *par,
+ struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+static void platinum_init_display(struct display *disp);
+static void platinum_par_to_fix(struct fb_par_platinum *par, struct fb_fix_screeninfo *fix,
+ struct fb_info_platinum *p);
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+
+static struct fb_ops platinumfb_ops = {
+ platinum_open,
+ platinum_release,
+ platinum_get_fix,
+ platinum_get_var,
+ platinum_set_var,
+ platinum_get_cmap,
+ platinum_set_cmap,
+ platinum_pan_display,
+ platinum_ioctl
+};
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+ u_int *blue, u_int *transp, struct fb_info *info);
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+#define FUNCID { printk(KERN_INFO "entering %s\n", __FUNCTION__); }
+
+__openfirmware
+
+
+static int platinum_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int platinum_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+ *fix = cp->fix;
+ return 0;
+}
+
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+ *var = cp->var;
+ return 0;
+}
+
+/* Sets everything according to var */
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+ struct display *disp;
+ struct fb_par_platinum par;
+ int depthchange, err;
+
+// FUNCID;
+ disp = (con >= 0) ? &fb_display[con] : &p->disp;
+ if((err = platinum_var_to_par(var, &par, info))) {
+ printk (KERN_ERR "Error in platinum_set_var, calling platinum_var_to_par: %d.\n", err);
+ return err;
+ }
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+ printk("Not activating, in platinum_set_var.\n");
+ platinum_par_to_var(&par, var);
+ return 0;
+ }
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+ depthchange = DIRTY(bits_per_pixel);
+ if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+ !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+ platinum_par_to_var(&par, var);
+ p->var = disp->var = *var;
+ return 0;
+ }
+ printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+ /* OK, we're getting here at the right times... */
+ p->par = par;
+ platinum_par_to_var(&par, var);
+ p->var = *var;
+ platinum_par_to_fix(&par, &p->fix, p);
+ platinum_par_to_display(&par, disp, &p->fix, p);
+ p->disp = *disp;
+
+ if(info->changevar && !switching) /* Don't want to do this if just switching consoles. */
+ (*info->changevar)(con);
+ if(con == currcon)
+ platinum_set_hardware(p);
+ if(depthchange)
+ if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+ return err;
+ if(depthchange || switching)
+ do_install_cmap(con, info);
+ return 0;
+}
+
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ /*
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * `xoffset' and `yoffset' fields of the `var' structure.
+ * If the values don't fit, return -EINVAL.
+ */
+
+// FUNCID;
+ if (var->xoffset != 0 || var->yoffset != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+// FUNCID;
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+ platinum_getcolreg, info);
+ if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
+ return 0;
+}
+
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ struct display *disp = &fb_display[con];
+ int err;
+
+// FUNCID;
+ if (disp->cmap.len == 0) {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ err = fb_alloc_cmap(&disp->cmap, size, 0);
+ if (err)
+ return err;
+ }
+
+ if (con == currcon)
+ return fb_set_cmap(cmap, &disp->var, kspc, platinum_setcolreg,
+ info);
+ fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+// FUNCID;
+ return -EINVAL;
+}
+
+static int platinum_switch(int con, struct fb_info *info)
+{
+// FUNCID;
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap,
+ &fb_display[currcon].var, 1, platinum_getcolreg,
+ info);
+ currcon = con;
+#if 0
+ platinum_var_to_par(&fb_display[currcon].var, &par, info);
+ platinum_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+ do_install_cmap(con, info);
+#else
+ /* I see no reason not to do this. Minus info->changevar(). */
+ /* DOH. This makes platinum_set_var compare, you guessed it, */
+ /* fb_display[con].var (first param), and fb_display[con].var! */
+ /* Perhaps I just fixed that... */
+ switching = 1;
+ platinum_set_var(&fb_display[con].var, con, info);
+ switching = 0;
+#endif
+ return 0;
+}
+
+static int platinum_updatevar(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static void platinum_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ * then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ * to e.g. a video mode which doesn't support it. Implements VESA suspend
+ * and powerdown modes on hardware that supports disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+/*
+ struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+ int ctrl;
+
+ ctrl = ld_le32(&p->platinum_regs->ctrl.r) | 0x33;
+ if (blank_mode)
+ --blank_mode;
+ if (blank_mode & VESA_VSYNC_SUSPEND)
+ ctrl &= ~3;
+ if (blank_mode & VESA_HSYNC_SUSPEND)
+ ctrl &= ~0x30;
+ out_le32(&p->platinum_regs->ctrl.r, ctrl);
+*/
+/* TODO: Figure out how the heck to powerdown this thing! */
+//FUNCID;
+ return;
+}
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+ u_int *blue, u_int *transp, struct fb_info *info)
+{
+ struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+// FUNCID;
+ if (regno > 255 || regno < 0)
+ return 1;
+ *red = p->palette[regno].red;
+ *green = p->palette[regno].green;
+ *blue = p->palette[regno].blue;
+ return 0;
+}
+
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+// FUNCID;
+ if (regno > 255 || regno < 0)
+ return 1;
+ p->palette[regno].red = red;
+ p->palette[regno].green = green;
+ p->palette[regno].blue = blue;
+
+ out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */
+ out_8(&p->cmap_regs->lut, red); /* send one color channel at */
+ out_8(&p->cmap_regs->lut, green); /* a time... */
+ out_8(&p->cmap_regs->lut, blue);
+
+ if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+ /* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+ /* I think. */
+#endif
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+// FUNCID;
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+ platinum_setcolreg, info);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+ platinum_setcolreg, info);
+ }
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+ struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int platinum_vram_reqd(int video_mode, int color_mode)
+{
+ return vmode_attrs[video_mode - 1].vres
+ * platinum_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+#define STORE_D2(a, d) { \
+ out_8(&p->cmap_regs->addr, (a+32)); \
+ out_8(&p->cmap_regs->d2, (d)); \
+}
+
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_params)
+{
+// FUNCID;
+ STORE_D2(6, 0xc6);
+ out_8(&p->cmap_regs->addr,3+32);
+ if (in_8(&p->cmap_regs->d2) == 2) {
+ STORE_D2(7, clock_params[0]);
+ STORE_D2(8, clock_params[1]);
+ STORE_D2(3, 3);
+ } else {
+ STORE_D2(4, clock_params[0]);
+ STORE_D2(5, clock_params[1]);
+ STORE_D2(3, 2);
+ }
+
+ __delay(5000);
+ STORE_D2(9, 0xa6);
+}
+
+
+__initfunc(static void init_platinum(struct fb_info_platinum *p))
+{
+ struct fb_par_platinum *par = &p->par;
+
+// FUNCID;
+ p->sense = read_platinum_sense(p);
+ printk("Monitor sense value = 0x%x, ", p->sense);
+ /* Try to pick a video mode out of NVRAM if we have one. */
+ par->vmode = nvram_read_byte(NV_VMODE);
+ if(par->vmode <= 0 || par->vmode > VMODE_MAX || !platinum_reg_init[par->vmode - 1])
+ par->vmode = VMODE_CHOOSE;
+ if(par->vmode == VMODE_CHOOSE)
+ par->vmode = mac_map_monitor_sense(p->sense);
+ if(!platinum_reg_init[par->vmode - 1])
+ par->vmode = VMODE_640_480_67;
+
+ par->cmode = nvram_read_byte(NV_CMODE);
+ if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+ par->cmode = CMODE_8;
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+ while(par->cmode > CMODE_8 && platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+ par->cmode--;
+
+ printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+
+ par->vxres = par->xres = vmode_attrs[par->vmode - 1].hres;
+ par->vyres = par->yres = vmode_attrs[par->vmode - 1].vres;
+ par->xoffset = par->yoffset = 0;
+
+ platinum_par_to_all(p, 1);
+
+ if (register_framebuffer(&p->info) < 0) {
+ kfree(p);
+ return;
+ }
+ platinum_set_hardware(p);
+
+ printk("fb%d: platinum display adapter\n", GET_FB_IDX(p->info.node));
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void platinum_set_hardware(struct fb_info_platinum *p)
+{
+ struct platinum_regvals *init;
+ int i, dtype, clkmode;
+ int vmode, cmode;
+
+// FUNCID;
+ vmode = p->par.vmode;
+ cmode = p->par.cmode;
+
+ init = platinum_reg_init[vmode - 1];
+
+ /* Initialize display timing registers */
+ out_be32(&p->platinum_regs->reg[24].r, 7); /* turn display off */
+
+ for (i = 0; i < 26; ++i)
+ out_be32(&p->platinum_regs->reg[i+32].r, init->regs[i]);
+ out_be32(&p->platinum_regs->reg[26+32].r, (p->total_vram == 0x100000 ?
+ init->offset[cmode] + 4 - cmode :
+ init->offset[cmode]));
+ out_be32(&p->platinum_regs->reg[16].r, (unsigned) p->frame_buffer_phys + init->fb_offset);
+ out_be32(&p->platinum_regs->reg[18].r, init->pitch[cmode]);
+ out_be32(&p->platinum_regs->reg[19].r, (p->total_vram == 0x100000 ?
+ init->mode[cmode+1] :
+ init->mode[cmode]));
+ out_be32(&p->platinum_regs->reg[20].r, (p->total_vram == 0x100000 ? 0x11 : 0x1011));
+ out_be32(&p->platinum_regs->reg[21].r, 0x100);
+ out_be32(&p->platinum_regs->reg[22].r, 1);
+ out_be32(&p->platinum_regs->reg[23].r, 1);
+ out_be32(&p->platinum_regs->reg[26].r, 0xc00);
+ out_be32(&p->platinum_regs->reg[27].r, 0x235);
+ /* out_be32(&p->platinum_regs->reg[27].r, 0x2aa); */
+
+ STORE_D2(0, (p->total_vram == 0x100000 ?
+ init->dacula_ctrl[cmode] & 0xf :
+ init->dacula_ctrl[cmode]));
+ STORE_D2(1, 4);
+ STORE_D2(2, 0);
+ /*
+ * Try to determine whether we have an old or a new DACula.
+ */
+ out_8(&p->cmap_regs->addr, 0x40);
+ dtype = in_8(&p->cmap_regs->d2);
+ switch (dtype) {
+ case 0x3c:
+ clkmode = 1;
+ break;
+ case 0x84:
+ clkmode = 0;
+ break;
+ default:
+ clkmode = 0;
+ printk("Unknown DACula type: %x\n", dtype);
+ }
+
+ set_platinum_clock(p, init->clock_params[clkmode]);
+
+ out_be32(&p->platinum_regs->reg[24].r, 0); /* turn display on */
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ /* And let the world know the truth. */
+ if (!console_fb_info || console_fb_info == &p->info) {
+ display_info.height = p->var.yres;
+ display_info.width = p->var.xres;
+ display_info.depth = ( (cmode == CMODE_32) ? 32 :
+ ((cmode == CMODE_16) ? 16 : 8));
+ display_info.pitch = p->fix.line_length;
+ display_info.mode = vmode;
+ strncpy(display_info.name, "platinum",
+ sizeof(display_info.name));
+ display_info.fb_address = p->frame_buffer_phys
+ + init->fb_offset
+ + 0x10;
+ display_info.cmap_adr_address = p->cmap_regs_phys;
+ display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+ display_info.disp_reg_address = p->platinum_regs_phys;
+ console_fb_info = &p->info;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void platinum_init(void))
+{
+#ifndef CONFIG_FB_OF
+ struct device_node *dp;
+
+ dp = find_devices("platinum");
+ if (dp != 0)
+ platinum_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void platinum_of_init(struct device_node *dp))
+{
+ struct fb_info_platinum *p;
+ unsigned long addr, size;
+ int i, bank0, bank1, bank2, bank3;
+//FUNCID;
+ if(dp->n_addrs != 2)
+ panic("expecting 2 address for platinum (got %d)", dp->n_addrs);
+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ if (p == 0)
+ return;
+
+ /* Map in frame buffer and registers */
+ for (i = 0; i < dp->n_addrs; ++i) {
+ addr = dp->addrs[i].address;
+ size = dp->addrs[i].size;
+ if (size >= 0x400000) {
+ /* frame buffer - map only 4MB */
+ p->frame_buffer_phys = addr;
+ p->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
+ p->base_frame_buffer = p->frame_buffer;
+ } else {
+ /* registers */
+ p->platinum_regs_phys = addr;
+ p->platinum_regs = ioremap(addr, size);
+ }
+ }
+ p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
+ p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+ /* Grok total video ram */
+ out_be32(&p->platinum_regs->reg[16].r, (unsigned)p->frame_buffer_phys);
+ out_be32(&p->platinum_regs->reg[20].r, 0x1011); /* select max vram */
+ out_be32(&p->platinum_regs->reg[24].r, 0); /* switch in vram */
+ eieio();
+ p->frame_buffer[0x100000] = 0x34;
+ asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x100000]) : "memory");
+ p->frame_buffer[0x200000] = 0x56;
+ asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory");
+ p->frame_buffer[0x300000] = 0x78;
+ asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x300000]) : "memory");
+ bank0 = 1; /* builtin 1MB vram, always there */
+ bank1 = p->frame_buffer[0x100000] == 0x34;
+ bank2 = p->frame_buffer[0x200000] == 0x56;
+ bank3 = p->frame_buffer[0x300000] == 0x78;
+ p->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+ printk("Total VRAM = %dMB\n", p->total_vram / 1024 / 1024);
+
+// p->frame_buffer = p->base_frame_buffer
+// + platinum_reg_init[p->par.vmode-1]->fb_offset;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+ console_set_cmap_ptr = platinum_set_cmap;
+ console_setmode_ptr = platinum_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+ init_platinum(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int read_platinum_sense(struct fb_info_platinum *p)
+{
+ int sense;
+
+ out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */
+ __delay(2000);
+ sense = (~in_be32(&p->platinum_regs->reg[23].r) & 7) << 8;
+
+ /* drive each sense line low in turn and collect the other 2 */
+ out_be32(&p->platinum_regs->reg[23].r, 3); /* drive A low */
+ __delay(2000);
+ sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 3) << 4;
+ out_be32(&p->platinum_regs->reg[23].r, 5); /* drive B low */
+ __delay(2000);
+ sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 4) << 1;
+ sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 1) << 2;
+ out_be32(&p->platinum_regs->reg[23].r, 6); /* drive C low */
+ __delay(2000);
+ sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 6) >> 1;
+
+ out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */
+
+ return sense;
+}
+
+#if 0
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+ int xres = var->xres;
+ int yres = var->yres;
+ int bpp = var->bits_per_pixel;
+
+ struct platinum_regvals *init;
+ struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+
+// FUNCID;
+ /*
+ * Get the video params out of 'var'. If a value doesn't fit, round it up,
+ * if it's too big, return -EINVAL.
+ *
+ * Suggestion: Round up in the following order: bits_per_pixel, xres,
+ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ * bitfields, horizontal timing, vertical timing.
+ */
+ /* swiped by jonh from atyfb.c */
+ if (xres <= 512 && yres <= 384)
+ par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */
+ else if (xres <= 640 && yres <= 480)
+ par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */
+ else if (xres <= 640 && yres <= 870)
+ par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
+ else if (xres <= 768 && yres <= 576)
+ par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */
+ else if (xres <= 800 && yres <= 600)
+ par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */
+ else if (xres <= 832 && yres <= 624)
+ par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */
+ else if (xres <= 1024 && yres <= 768)
+ par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
+ else if (xres <= 1152 && yres <= 870)
+ par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
+ else if (xres <= 1280 && yres <= 960)
+ par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
+ else if (xres <= 1280 && yres <= 1024)
+ par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
+ else {
+ printk(KERN_ERR "Bad resolution in platinum_var_to_par()!\n");
+ return -EINVAL;
+ }
+ xres = vmode_attrs[par->vmode - 1].hres;
+ yres = vmode_attrs[par->vmode - 1].vres;
+
+/*
+ if (var->xres_virtual <= xres)
+ par->vxres = xres;
+ else
+ par->vxres = (var->xres_virtual+7) & ~7;
+ if (var->yres_virtual <= yres)
+ par->vyres = yres;
+ else
+ par->vyres = var->yres_virtual;
+
+ par->xoffset = (var->xoffset+7) & ~7;
+ par->yoffset = var->yoffset;
+ if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+ return -EINVAL;
+*/
+
+ /* I'm too chicken to think about virtual */
+ /* resolutions just yet. Bok bok. */
+
+ /* And I'm too chicken to even figure out what they are. Awk awk. [danj] */
+ if (var->xres_virtual > xres || var->yres_virtual > yres
+ || var->xoffset != 0 || var->yoffset != 0) {
+ printk(KERN_ERR "Bad virtual resolution in platinum_var_to_par()!\n");
+ return -EINVAL;
+ }
+
+ par->xres = xres;
+ par->yres = yres;
+ par->vxres = xres;
+ par->vyres = yres;
+ par->xoffset = 0;
+ par->yoffset = 0;
+
+ if (bpp <= 8)
+ par->cmode = CMODE_8;
+ else if (bpp <= 16)
+ par->cmode = CMODE_16;
+ else if (bpp <= 32)
+ par->cmode = CMODE_32;
+ else {
+ printk(KERN_ERR "Bad color mode in platinum_var_to_par()!\n");
+ return -EINVAL;
+ }
+
+ if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) {
+ printk(KERN_ERR "Bad vram size requested in platinum_var_to_par()!\n");
+ return -EINVAL;
+ }
+ /* Check if we know about the wanted video mode */
+ init = platinum_reg_init[par->vmode-1];
+ if (init == NULL) {
+ /* I'm not sure if platinum has any specific requirements -- */
+ /* if we have a regvals struct, we're good to go? */
+ printk(KERN_ERR "platinum_reg_init failed platinum_var_to_par()!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+ struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+ struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+
+// FUNCID;
+ if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+ return -EINVAL;
+ par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+ par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+ par->xoffset = par->yoffset = 0;
+
+ if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+ return -EINVAL;
+
+ /* Check if we know about the wanted video mode */
+ if(!platinum_reg_init[par->vmode-1]) {
+ /* I'm not sure if platinum has any specific requirements -- */
+ /* if we have a regvals struct, we're good to go? */
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+#if 0
+static void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+ memset(var, 0, sizeof(*var));
+ var->xres = vmode_attrs[par->vmode - 1].hres;
+ var->yres = vmode_attrs[par->vmode - 1].vres;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres; /* For now. */
+ var->xoffset = par->xoffset;
+ var->yoffset = par->yoffset;
+ var->grayscale = 0;
+
+ if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+ printk(KERN_ERR "Bad color mode in platinum_par_to_var()!\n");
+ par->cmode = CMODE_8;
+ }
+ switch(par->cmode) {
+ case CMODE_8:
+ var->bits_per_pixel = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CMODE_16: /* RGB 555 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CMODE_32: /* RGB 888 */
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->height = -1;
+ var->width = -1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ /* these are total guesses, copied right out of atyfb.c */
+ var->left_margin = var->right_margin = 64;
+ var->upper_margin = var->lower_margin = 32;
+ var->hsync_len = 8;
+ var->vsync_len = 8;
+ var->sync = 0;
+
+#if 1
+/* jonh's pixclocks...*/
+ /* no long long support in the kernel :-( */
+ /* this splittig trick will work if xres > 232 */
+ var->pixclock = 1000000000/
+ (var->left_margin+var->xres+var->right_margin+var->hsync_len);
+ var->pixclock *= 1000;
+ var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+ (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+ /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+ /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+ /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+ var->pixclock = 255990 * platinum_reg_init[par->vmode-1]->clock_params[0];
+ var->pixclock /= platinum_reg_init[par->vmode-1]->clock_params[1];
+ var->pixclock >>= platinum_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+// FUNCID;
+ mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+// FUNCID;
+ memset(fix, 0, sizeof(*fix));
+ strcpy(fix->id, "platinum");
+ fix->mmio_start = (char *)p->platinum_regs_phys;
+ fix->mmio_len = 0x1000;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+
+ fix->type_aux = 0;
+ fix->ywrapstep = 0;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void platinum_par_to_fix(struct fb_par_platinum *par,
+ struct fb_fix_screeninfo *fix,
+ struct fb_info_platinum *p)
+{
+// FUNCID;
+ fix->smem_start = (void *)(p->frame_buffer_phys);
+ fix->smem_len = platinum_vram_reqd(par->vmode, par->cmode);
+ /* Hmm, jonh used total_vram here. */
+ fix->visual = (par->cmode == CMODE_8) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+// fix->line_length = par->vxres << par->cmode;
+ fix->line_length = platinum_reg_init[par->vmode-1]->pitch[par->cmode];
+
+}
+
+static void platinum_init_display(struct display *disp)
+{
+ memset(disp, 0, sizeof(*disp));
+ disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+ disp->can_soft_blank = 1;
+ disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+ disp->type_aux = fix->type_aux;
+ disp->cmap.red = NULL; /* ??? danj */
+ disp->cmap.green = NULL;
+ disp->cmap.blue = NULL;
+ disp->cmap.transp = NULL;
+ /* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void platinum_par_to_display(struct fb_par_platinum *par,
+ struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+// FUNCID;
+ disp->var = p->var;
+ disp->screen_base = (char *) p->frame_buffer
+ + platinum_reg_init[par->vmode-1]->fb_offset
+ + ((par->yres % 16) / 2) * fix->line_length + 0x10;
+ disp->visual = fix->visual;
+ disp->line_length = fix->line_length;
+
+ if(disp->scrollmode != SCROLL_YREDRAW) {
+ printk(KERN_ERR "Scroll mode not YREDRAW in platinum_par_to_display!!\n");
+ disp->scrollmode = SCROLL_YREDRAW;
+ }
+
+ switch(par->cmode) {
+#ifdef FBCON_HAS_CFB8
+ case CMODE_8:
+ disp->dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case CMODE_16:
+ disp->dispsw = &fbcon_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case CMODE_32:
+ disp->dispsw = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ disp->dispsw = NULL;
+ break;
+ }
+}
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p)
+{
+// FUNCID;
+ strcpy(info->modename, p->fix.id);
+ info->node = -1; /* ??? danj */
+ info->fbops = &platinumfb_ops;
+ info->disp = &p->disp;
+ info->fontname[0] = 0;
+ info->changevar = NULL;
+ info->switch_con = &platinum_switch;
+ info->updatevar = &platinum_updatevar;
+ info->blank = &platinum_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void platinum_par_to_all(struct fb_info_platinum *p, int init)
+{
+// FUNCID;
+ if(init) {
+ platinum_init_fix(&p->fix, p);
+ }
+ platinum_par_to_fix(&p->par, &p->fix, p);
+
+ platinum_par_to_var(&p->par, &p->var);
+
+ if(init) {
+ platinum_init_display(&p->disp);
+ }
+ platinum_par_to_display(&p->par, &p->disp, &p->fix, p);
+
+ if(init) {
+ platinum_init_info(&p->info, p);
+ }
+}
+
+#if 0
+__initfunc(void platinum_setup(char *options, int *ints))
+{
+ /* Parse user speficied options (`video=platinumfb:') */
+ FUNCID;
+}
+
+#endif
+
--- /dev/null
+/*
+ * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the
+ * Platinum on-board video in PowerMac 7200s (and some clones based
+ * on the same motherboard.)
+ *
+ * Created 09 Feb 1998 by Jon Howell <jonh@cs.dartmouth.edu>
+ *
+ * Copyright (C) 1998 Jon Howell
+ *
+ * based on drivers/macintosh/platinum.c: Console support
+ * for PowerMac "platinum" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ * based on skeletonfb.c:
+ * Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+ unsigned char addr;
+ char pad1[15];
+ unsigned char d1;
+ char pad2[15];
+ unsigned char d2;
+ char pad3[15];
+ unsigned char lut;
+ char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+struct preg { /* padded register */
+ unsigned r; /* notice this is 32 bits. */
+ char pad[12];
+};
+
+struct platinum_regs {
+ struct preg reg[128];
+};
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there. Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ * F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ * F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct platinum_regvals {
+ int fb_offset;
+ int pitch[3];
+ unsigned regs[26];
+ unsigned char offset[3];
+ unsigned char mode[3];
+ unsigned char dacula_ctrl[3];
+ unsigned char clock_params[2][2];
+};
+
+#define DIV2 0x20
+#define DIV4 0x40
+#define DIV8 0x60
+#define DIV16 0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct platinum_regvals platinum_reg_init_20 = {
+ 0x5c00,
+ { 1312, 2592, 2592 },
+ { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+ 0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+ 0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+ 0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+ { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+ {{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct platinum_regvals platinum_reg_init_19 = {
+ 0x5c00,
+ { 1312, 2592, 2592 },
+ { 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+ 0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+ 0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+ 0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+ { 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+ {{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct platinum_regvals platinum_reg_init_18 = {
+ 0x11b0,
+ { 1184, 2336, 4640 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+ 0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+ 0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+ 0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct platinum_regvals platinum_reg_init_17 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+ 0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+ 0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct platinum_regvals platinum_reg_init_16 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+ 0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+ 0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct platinum_regvals platinum_reg_init_15 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+ 0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+ 0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct platinum_regvals platinum_reg_init_14 = {
+ 0x10b0,
+ { 1056, 2080, 4128 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+ 0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+ 0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct platinum_regvals platinum_reg_init_13 = {
+ 0x70,
+ { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+ { 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+ 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+ 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+ 0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct platinum_regvals platinum_reg_init_12 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+ 0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+ 0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct platinum_regvals platinum_reg_init_11 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+ 0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+ 0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct platinum_regvals platinum_reg_init_10 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+ 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+ 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct platinum_regvals platinum_reg_init_9 = {
+ 0x1010,
+ { 832, 1632, 3232 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+ 0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+ 0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct platinum_regvals platinum_reg_init_8 = {
+ 0x1010,
+ { 800, 1568, 3104 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+ 0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+ 0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct platinum_regvals platinum_reg_init_7 = {
+ 0xb10,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+ 0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+ 0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct platinum_regvals platinum_reg_init_6 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+ 0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+ 0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+ 0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct platinum_regvals platinum_reg_init_5 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+ 0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+ 0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct platinum_regvals platinum_reg_init_4 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+ 0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+ 0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct platinum_regvals platinum_reg_init_3 = {
+ 0x1010,
+ { 672, 1312, 2592 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+ 0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+ 0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct platinum_regvals platinum_reg_init_2 = {
+ 0x1010,
+ { 544, 1056, 2080 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+ 0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+ 0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct platinum_regvals platinum_reg_init_1 = {
+ 0x1010,
+ { 544, 1056, 2080 },
+ { 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+ 0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+ 0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+ 0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+ {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+#define VMODE_MAX 20
+
+static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = {
+ &platinum_reg_init_1,
+ &platinum_reg_init_2,
+ &platinum_reg_init_3,
+ &platinum_reg_init_4,
+ &platinum_reg_init_5,
+ &platinum_reg_init_6,
+ &platinum_reg_init_7,
+ &platinum_reg_init_8,
+ &platinum_reg_init_9,
+ &platinum_reg_init_10,
+ &platinum_reg_init_11,
+ &platinum_reg_init_12,
+ &platinum_reg_init_13,
+ &platinum_reg_init_14,
+ &platinum_reg_init_15,
+ &platinum_reg_init_16,
+ &platinum_reg_init_17,
+ &platinum_reg_init_18,
+ &platinum_reg_init_19,
+ &platinum_reg_init_20
+};
+
+struct vmode_attr {
+ int hres;
+ int vres;
+ int vfreq;
+ int interlaced;
+};
+
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+ {512, 384, 60, 1},
+ {512, 384, 60},
+ {640, 480, 50, 1},
+ {640, 480, 60, 1},
+ {640, 480, 60},
+ {640, 480, 67},
+ {640, 870, 75},
+ {768, 576, 50, 1},
+ {800, 600, 56},
+ {800, 600, 60},
+ {800, 600, 72},
+ {800, 600, 75},
+ {832, 624, 75},
+ {1024, 768, 60},
+ {1024, 768, 72},
+ {1024, 768, 75},
+ {1024, 768, 75},
+ {1152, 870, 75},
+ {1280, 960, 75},
+ {1280, 1024, 75}
+};
+
+/* this stuff should probably be shared by the various vmode-based */
+/* drivers in a vmode.h header. */
+
+#define VMODE_NVRAM 0 /* use value stored in nvram */
+#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60 2 /* 512x384, 60Hz */
+#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67 6 /* 640x480, 67Hz */
+#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56 9 /* 800x600, 56Hz */
+#define VMODE_800_600_60 10 /* 800x600, 60Hz */
+#define VMODE_800_600_72 11 /* 800x600, 72Hz */
+#define VMODE_800_600_75 12 /* 800x600, 75Hz */
+#define VMODE_832_624_75 13 /* 832x624, 75Hz */
+#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */
+#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */
+#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */
+#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */
+#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */
+#define VMODE_MAX 20
+#define VMODE_CHOOSE 99 /* choose based on monitor sense */
+
+#define CMODE_NVRAM -1 /* use value stored in nvram */
+#define CMODE_8 0 /* 8 bits/pixel */
+#define CMODE_16 1 /* 16 (actually 15) bits/pixel */
+#define CMODE_32 2 /* 32 (actually 24) bits/pixel */
--- /dev/null
+#
+# Unicode mapping table for font in Sun PROM
+#
+#
+0x20-0x7e idem
+0xa0-0xff idem
+#
+0x7c U+2502
+0x2d U+2500
+0x2b U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c
+0xa4 U+fffd
-/* $Id: promcon.c,v 1.6 1998/07/19 12:49:26 mj Exp $
+/* $Id: promcon.c,v 1.10 1998/07/24 15:31:53 jj Exp $
* Console driver utilizing PROM sun terminal emulation
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/console.h>
#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kd.h>
#include <asm/oplib.h>
+#include <asm/uaccess.h>
static short pw = 80 - 1, ph = 34 - 1;
static short px, py;
+static unsigned long promcon_uni_pagedir[2];
-#define PROMCON_COLOR 1
+extern u8 promfont_unicount[];
+extern u16 promfont_unitable[];
+
+#define PROMCON_COLOR 0
#if PROMCON_COLOR
#define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1)
return display_desc;
}
+__initfunc(static void
+promcon_init_unimap(struct vc_data *conp))
+{
+ mm_segment_t old_fs = get_fs();
+ struct unipair *p, *p1;
+ u16 *q;
+ int i, j, k;
+
+ p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
+ if (!p) return;
+
+ q = promfont_unitable;
+ p1 = p;
+ k = 0;
+ for (i = 0; i < 256; i++)
+ for (j = promfont_unicount[i]; j; j--) {
+ p1->unicode = *q++;
+ p1->fontpos = i;
+ p1++;
+ k++;
+ }
+ set_fs(KERNEL_DS);
+ con_clear_unimap(conp->vc_num, NULL);
+ con_set_unimap(conp->vc_num, k, p);
+ con_protect_unimap(conp->vc_num, 1);
+ set_fs(old_fs);
+ kfree(p);
+}
+
static void
promcon_init(struct vc_data *conp, int init)
{
+ unsigned long p;
+
conp->vc_can_do_color = PROMCON_COLOR;
- conp->vc_cols = pw + 1;
- conp->vc_rows = ph + 1;
+ if (init) {
+ conp->vc_cols = pw + 1;
+ conp->vc_rows = ph + 1;
+ }
+ p = *conp->vc_uni_pagedir_loc;
+ if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
+ !--conp->vc_uni_pagedir_loc[1])
+ con_free_unimap(conp->vc_num);
+ conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
+ promcon_uni_pagedir[1]++;
+ if (!promcon_uni_pagedir[0] && p) {
+ promcon_init_unimap(conp);
+ }
+ if (!init) {
+ if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
+ vc_resize_con(ph + 1, pw + 1, conp->vc_num);
+ else if (conp->vc_num == fg_console)
+ update_screen(fg_console);
+ }
+}
+
+static void
+promcon_deinit(struct vc_data *conp)
+{
+ /* When closing the last console, reset video origin */
+ if (!--promcon_uni_pagedir[1])
+ con_free_unimap(conp->vc_num);
+ conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
+ con_set_default_unimap(conp->vc_num);
}
static int
return 0;
}
+#if !(PROMCON_COLOR)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+ return (_reverse) ? 0xf : 0x7;
+}
+#endif
+
/*
* The console 'switch' structure for the VGA based console
*/
struct consw prom_con = {
con_startup: promcon_startup,
con_init: promcon_init,
- con_deinit: DUMMY,
+ con_deinit: promcon_deinit,
con_clear: promcon_clear,
con_putc: promcon_putc,
con_putcs: promcon_putcs,
con_scrolldelta: DUMMY,
con_set_origin: NULL,
con_save_screen: NULL,
+#if PROMCON_COLOR
con_build_attr: NULL,
+#else
+ con_build_attr: promcon_build_attr,
+#endif
con_invert_region: NULL,
};
+
+__initfunc(void prom_con_init(void))
+{
+ if (conswitchp == &dummy_con)
+ take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
+ else if (conswitchp == &prom_con)
+ promcon_init_unimap(vc_cons[fg_console].d);
+}
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
rects [13] = fb->var.yres_virtual - fb->y_margin;
rects [14] = fb->var.xres_virtual - fb->x_margin;
rects [15] = fb->var.yres_virtual;
- (*fb->fill)(fb, s, 4, rects);
+ (*fb->fill)(fb, p, s, 4, rects);
} else {
unsigned char *fb_base = p->screen_base, *q;
int skip_bytes = fb->y_margin * fb->var.xres_virtual;
memset (q, ~0, size);
} else {
fb_base -= (skip_bytes + fb->x_margin);
- memset (fb_base, attr_bg_col(s), skip_bytes - fb->x_margin);
- memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bg_col(s), skip_bytes - fb->x_margin);
+ memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+ memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
incr = fb->var.xres_virtual;
size = fb->x_margin * 2;
for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
h <= he; q += incr, h++)
- memset (q, attr_bg_col(s), size);
+ memset (q, attr_bgcol(p,s), size);
}
}
if (fb->switch_from_graph)
type->fb_height = h = prom_getintdefault(node, "height", 900);
type->fb_width = w = prom_getintdefault(node, "width", 1152);
+sizechange:
type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
linebytes = prom_getintdefault(node, "linebytes", w * depth / 8);
type->fb_size = PAGE_ALIGN((linebytes) * h);
fb->cursor.hwsize.fbx = 32;
fb->cursor.hwsize.fby = 32;
- if (depth > 1)
+ if (depth > 1 && !fb->color_map)
fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
switch(fbtype) {
kfree(fb);
return;
}
+
+ if (p == SBUSFBINIT_SIZECHANGE)
+ goto sizechange;
disp->dispsw = &fb->dispsw;
if (fb->setcursor)
struct cg6_tec *tec;
volatile u32 *fhc;
};
+struct fb_info_bwtwo {
+ struct bw2_regs *regs;
+};
+struct fb_info_cgthree {
+ struct cg3_regs *regs;
+};
+struct fb_info_tcx {
+ struct bt_regs *bt;
+ struct tcx_thc *thc;
+ struct tcx_tec *tec;
+ u32 *cplane;
+};
struct cg_cursor {
short enable; /* cursor is enabled */
union {
struct fb_info_creator ffb;
struct fb_info_cgsix cg6;
+ struct fb_info_bwtwo bw2;
+ struct fb_info_cgthree cg3;
+ struct fb_info_tcx tcx;
} s;
unsigned char *color_map;
struct cg_cursor cursor;
void (*unblank)(struct fb_info_sbusfb *);
void (*margins)(struct fb_info_sbusfb *, struct display *, int, int);
void (*reset)(struct fb_info_sbusfb *);
- void (*fill)(struct fb_info_sbusfb *, int, int, unsigned short *);
+ void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *);
void (*switch_from_graph)(struct fb_info_sbusfb *);
void (*restore_palette)(struct fb_info_sbusfb *);
};
extern char *bwtwofb_init(struct fb_info_sbusfb *);
extern char *cgfourteenfb_init(struct fb_info_sbusfb *);
-#define attr_fg_col(s) \
- (((s) >> 8) & 0x0f)
-#define attr_bg_col(s) \
- (((s) >> 12) & 0x0f)
-#define attr_bg_col_ec(conp) \
- (((conp)->vc_video_erase_char >> 12) & 0x0f)
-
#define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
#define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
#define CM(i, j) [3*(i)+(j)]
+
+#define SBUSFBINIT_SIZECHANGE ((char *)-1)
* for more details.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
--- /dev/null
+/* $Id: tcxfb.c,v 1.1 1998/07/21 14:50:44 jj Exp $
+ * tcxfb.c: TCX 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT 16
+#define TCX_THC_MISC_REV_MASK 15
+#define TCX_THC_MISC_VSYNC_DIS (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS (1 << 24)
+#define TCX_THC_MISC_RESET (1 << 12)
+#define TCX_THC_MISC_VIDEO (1 << 10)
+#define TCX_THC_MISC_SYNC (1 << 9)
+#define TCX_THC_MISC_VSYNC (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB (1 << 7)
+#define TCX_THC_MISC_CURS_RES (1 << 6)
+#define TCX_THC_MISC_INT_ENAB (1 << 5)
+#define TCX_THC_MISC_INT (1 << 4)
+#define TCX_THC_MISC_INIT 0x9f
+#define TCX_THC_REV_REV_SHIFT 20
+#define TCX_THC_REV_REV_MASK 15
+#define TCX_THC_REV_MINREV_SHIFT 28
+#define TCX_THC_REV_MINREV_MASK 15
+
+/* The contents are unknown */
+struct tcx_tec {
+ volatile u32 tec_matrix;
+ volatile u32 tec_clip;
+ volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+ volatile u32 thc_rev;
+ u32 thc_pad0[511];
+ volatile u32 thc_hs; /* hsync timing */
+ volatile u32 thc_hsdvs;
+ volatile u32 thc_hd;
+ volatile u32 thc_vs; /* vsync timing */
+ volatile u32 thc_vd;
+ volatile u32 thc_refresh;
+ volatile u32 thc_misc;
+ u32 thc_pad1[56];
+ volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ volatile u32 thc_cursmask[32]; /* cursor mask bits */
+ volatile u32 thc_cursbits[32]; /* what to show where mask enabled */
+};
+
+static struct sbus_mmap_map tcx_mmap_map[] = {
+ { TCX_RAM8BIT, 0, SBUS_MMAP_FBSIZE(1) },
+ { TCX_RAM24BIT, 0, SBUS_MMAP_FBSIZE(4) },
+ { TCX_UNK3, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_UNK4, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_CONTROLPLANE, 0, SBUS_MMAP_FBSIZE(4) },
+ { TCX_UNK6, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_UNK7, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_TEC, 0, PAGE_SIZE },
+ { TCX_BTREGS, 0, PAGE_SIZE },
+ { TCX_THC, 0, PAGE_SIZE },
+ { TCX_DHC, 0, PAGE_SIZE },
+ { TCX_ALT, 0, PAGE_SIZE },
+ { TCX_UNK2, 0, 0x20000 },
+ { 0, 0, 0 }
+};
+
+static void tcx_set_control_plane (struct fb_info_sbusfb *fb)
+{
+ u32 *p, *pend;
+
+ p = fb->s.tcx.cplane;
+ if (!p) return;
+ for (pend = p + fb->type.fb_size; p < pend; p++)
+ *p &= 0xffffff;
+}
+
+static void tcx_switch_from_graph (struct fb_info_sbusfb *fb)
+{
+ /* Reset control plane to 8bit mode if necessary */
+ if (fb->open && fb->mmaped)
+ tcx_set_control_plane (fb);
+}
+
+static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+ struct bt_regs *bt = fb->s.tcx.bt;
+ int i;
+
+ bt->addr = index << 24;
+ for (i = index; count--; i++){
+ bt->color_map = fb->color_map CM(i,0) << 24;
+ bt->color_map = fb->color_map CM(i,1) << 24;
+ bt->color_map = fb->color_map CM(i,2) << 24;
+ }
+}
+
+static void tcx_restore_palette (struct fb_info_sbusfb *fb)
+{
+ struct bt_regs *bt = fb->s.tcx.bt;
+
+ bt->addr = 0;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+ bt->color_map = 0xffffffff;
+}
+
+static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
+{
+ struct bt_regs *bt = fb->s.tcx.bt;
+
+ /* Note the 2 << 24 is different from cg6's 1 << 24 */
+ bt->addr = 2 << 24;
+ bt->cursor = red[0] << 24;
+ bt->cursor = green[0] << 24;
+ bt->cursor = blue[0] << 24;
+ bt->addr = 3 << 24;
+ bt->cursor = red[1] << 24;
+ bt->cursor = green[1] << 24;
+ bt->cursor = blue[1] << 24;
+ bt->addr = 0;
+}
+
+/* Set cursor shape */
+static void tcx_setcurshape (struct fb_info_sbusfb *fb)
+{
+ struct tcx_thc *thc = fb->s.tcx.thc;
+ int i;
+
+ for (i = 0; i < 32; i++){
+ thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+ thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+ }
+}
+
+/* Load cursor information */
+static void tcx_setcursor (struct fb_info_sbusfb *fb)
+{
+ unsigned int v;
+ struct cg_cursor *c = &fb->cursor;
+
+ if (c->enable)
+ v = ((c->cpos.fbx - c->chot.fbx) << 16)
+ |((c->cpos.fby - c->chot.fby) & 0xffff);
+ else
+ /* Magic constant to turn off the cursor */
+ v = ((65536-32) << 16) | (65536-32);
+ fb->s.tcx.thc->thc_cursxy = v;
+}
+
+static void tcx_blank (struct fb_info_sbusfb *fb)
+{
+ fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+ /* This should put us in power-save */
+ fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VSYNC_DIS;
+ fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_HSYNC_DIS;
+}
+
+static void tcx_unblank (struct fb_info_sbusfb *fb)
+{
+ fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VSYNC_DIS;
+ fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_HSYNC_DIS;
+ fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
+}
+
+static void tcx_reset (struct fb_info_sbusfb *fb)
+{
+ if (fb->open && fb->mmaped)
+ tcx_set_control_plane(fb);
+
+ /* Turn off stuff in the Transform Engine. */
+ fb->s.tcx.tec->tec_matrix = 0;
+ fb->s.tcx.tec->tec_clip = 0;
+ fb->s.tcx.tec->tec_vdc = 0;
+
+ /* Enable cursor in Brooktree DAC. */
+ fb->s.tcx.bt->addr = 0x06 << 24;
+ fb->s.tcx.bt->control |= 0x03 << 24;
+}
+
+static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+ p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb))
+{
+ struct fb_fix_screeninfo *fix = &fb->fix;
+ struct display *disp = &fb->disp;
+ struct fbtype *type = &fb->type;
+ unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+ int lowdepth;
+
+#ifndef FBCON_HAS_CFB8
+ return NULL;
+#endif
+
+ lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit");
+
+ if (lowdepth) {
+ strcpy(fb->info.modename, "TCX8");
+ strcpy(fix->id, "TCX8");
+ } else {
+ strcpy(fb->info.modename, "TCX24");
+ strcpy(fix->id, "TCX24");
+ }
+ fix->line_length = fb->var.xres_virtual;
+
+ disp->scrollmode = SCROLL_YREDRAW;
+ if (!disp->screen_base)
+ disp->screen_base = (char *)sparc_alloc_io(phys, 0,
+ type->fb_size, "tcx_ram", fb->iospace, 0);
+ disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+ fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0,
+ sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0);
+ fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0,
+ sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0);
+ fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0,
+ sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0);
+ if (!lowdepth) {
+ fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0,
+ type->fb_size*4, "tcx_cplane", fb->iospace, 0);
+ type->fb_depth = 24;
+ fb->switch_from_graph = tcx_switch_from_graph;
+ } else {
+ /* As there can be one tcx in a machine only, we can write directly into
+ tcx_mmap_map */
+ tcx_mmap_map[1].size = SBUS_MMAP_EMPTY;
+ tcx_mmap_map[4].size = SBUS_MMAP_EMPTY;
+ tcx_mmap_map[5].size = SBUS_MMAP_EMPTY;
+ tcx_mmap_map[6].size = SBUS_MMAP_EMPTY;
+ }
+ fb->dispsw = fbcon_cfb8;
+
+ fb->margins = tcx_margins;
+ fb->loadcmap = tcx_loadcmap;
+ if (prom_getbool (fb->prom_node, "hw-cursor")) {
+ fb->setcursor = tcx_setcursor;
+ fb->setcursormap = tcx_setcursormap;
+ fb->setcurshape = tcx_setcurshape;
+ }
+ fb->restore_palette = tcx_restore_palette;
+ fb->blank = tcx_blank;
+ fb->unblank = tcx_unblank;
+ fb->reset = tcx_reset;
+
+ fb->physbase = 0;
+ fb->mmap_map = tcx_mmap_map;
+
+ /* Initialize Brooktree DAC */
+ fb->s.tcx.bt->addr = 0x04 << 24; /* color planes */
+ fb->s.tcx.bt->control = 0xff << 24;
+ fb->s.tcx.bt->addr = 0x05 << 24;
+ fb->s.tcx.bt->control = 0x00 << 24;
+ fb->s.tcx.bt->addr = 0x06 << 24; /* overlay plane */
+ fb->s.tcx.bt->control = 0x73 << 24;
+ fb->s.tcx.bt->addr = 0x07 << 24;
+ fb->s.tcx.bt->control = 0x00 << 24;
+
+ sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys,
+ (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK,
+ (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK,
+ lowdepth ? "8-bit only" : "24-bit depth");
+
+ tcx_reset(fb);
+
+ return idstring;
+}
* KNOWN PROBLEMS/TO DO ==================================================== */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
* more details.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
* more details.
*/
-#include <linux/config.h>
+
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
+static unsigned long vgacon_uni_pagedir[2];
/* Description of the hardware situation */
return display_desc;
}
-static int vga_use_count;
-
static void vgacon_init(struct vc_data *c, int init)
{
+ unsigned long p;
+
/* We cannot be loaded as a module, therefore init is always 1 */
c->vc_can_do_color = vga_can_do_color;
c->vc_cols = vga_video_num_columns;
c->vc_rows = vga_video_num_lines;
c->vc_complement_mask = 0x7700;
- vga_use_count++;
+ p = *c->vc_uni_pagedir_loc;
+ if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
+ !--c->vc_uni_pagedir_loc[1])
+ con_free_unimap(c->vc_num);
+ c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
+ vgacon_uni_pagedir[1]++;
+ if (!vgacon_uni_pagedir[0] && p)
+ con_set_default_unimap(c->vc_num);
}
static inline void vga_set_mem_top(struct vc_data *c)
static void vgacon_deinit(struct vc_data *c)
{
/* When closing the last console, reset video origin */
- if (!--vga_use_count) {
+ if (!--vgacon_uni_pagedir[1]) {
c->vc_visible_origin = vga_vram_base;
vga_set_mem_top(c);
+ con_free_unimap(c->vc_num);
}
+ c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
+ con_set_default_unimap(c->vc_num);
}
static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
{
- int col = vga_can_do_color;
-
- while (count--) {
- u16 a = *p;
- if (col)
- a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
- else
+ if (vga_can_do_color) {
+ while (count--) {
+ u16 a = scr_readw(p);
+ a = (((a) & 0x88ff) | (((a) & 0x7000) >> 4)
+ | (((a) & 0x0700) << 4));
+ scr_writew(a, p++);
+ }
+ } else {
+ while (count--) {
+ u16 a = scr_readw(p);
a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
- *p++ = a;
+ scr_writew(a, p++);
+ }
}
}
op->width = 8;
op->height = vga_video_font_height;
op->charcount = vga_512_chars ? 512 : 256;
+ if (!op->data) return 0;
rc = vgacon_do_font_op(op->data, 0, 0);
} else
rc = -ENOSYS;
#undef VIRGEFBDEBUG
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
for (i = 0; i < uspi->s_apb; i++)
if (SWAB32(*ubh_get_addr32(ind_ubh,i)))
break;
- if (i >= uspi->s_apb)
+ if (i >= uspi->s_apb) {
if (ubh_max_bcount(ind_ubh) != 1) {
retry = 1;
}
ubh_bforget(ind_ubh);
ind_ubh = NULL;
}
+ }
if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
ubh_ll_rw_block (WRITE, 1, &ind_ubh);
ubh_wait_on_buffer (ind_ubh);
*/
#define CUR_DEFAULT CUR_UNDERLINE
+#include <linux/config.h>
+
#define NPAR 16
struct vc_data {
unsigned char vc_ulcolor; /* Color for underline mode */
unsigned char vc_halfcolor; /* Color for half intensity mode */
unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */
- unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars or font or 0 if not supported */
+ unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
unsigned int vc_x, vc_y; /* Cursor position */
unsigned int vc_top, vc_bottom; /* Scrolling region */
unsigned int vc_state; /* Escape sequence parser state */
unsigned int vc_bell_duration; /* Console bell duration */
unsigned int vc_cursor_type;
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
+ unsigned long vc_uni_pagedir;
+ unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
/* additional information is in vt_kern.h */
};
#define IBMPC_MAP 2
#define USER_MAP 3
-extern int hashtable_contents_valid;
-extern unsigned char inverse_translate(int glyph);
+struct vc_data;
+
+extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
extern unsigned short *set_translate(int m);
-extern int conv_uni_to_pc(long ucs);
+extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
struct display_switch *dispsw; /* low level operations */
u_short scrollmode; /* Scroll Method */
short yscroll; /* Hardware scrolling */
+ unsigned char fgshift, bgshift;
+ unsigned short charmask; /* 0xff or 0x1ff */
};
/* From here on everything is device dependent */
};
+ /*
+ * `Generic' versions of the frame buffer device operations
+ */
+
+extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+ /*
+ * Helper functions
+ */
+
+extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info_gen *info);
+extern void fbgen_set_disp(int con, struct fb_info_gen *info);
+extern void fbgen_install_cmap(int con, struct fb_info_gen *info);
+extern int fbgen_update_var(int con, struct fb_info *info);
+extern int fbgen_switch(int con, struct fb_info *info);
+extern void fbgen_blank(int blank, struct fb_info *info);
+
struct fb_videomode {
const char *name;
#define IPV6_MULTICAST_LOOP 19
#define IPV6_ADD_MEMBERSHIP 20
#define IPV6_DROP_MEMBERSHIP 21
+#define IPV6_ROUTER_ALERT 22
#endif
#define KD_FONT_FLAG_GLOBAL 1 /* Change on _all_ consoles */
#define KD_FONT_FLAG_DONT_RECALC 2 /* Don't recalculate hw charcell size [compat] */
+#ifdef __KERNEL__
+#define KD_FONT_FLAG_NEW 0x80000000 /* Indicate new KDFONTOP interface, which should be more strict */
+#endif
/* note: 0x4B00-0x4B4E all have had a value at some time;
don't reuse for the time being */
PROC_NET_AX25_ROUTE,
PROC_NET_AX25,
PROC_NET_AX25_CALLS,
+ PROC_NET_BMAC,
PROC_NET_NR_NODES,
PROC_NET_NR_NEIGH,
PROC_NET_NR,
extern void getconsxy(int currcons, char *p);
extern void putconsxy(int currcons, char *p);
+extern u16 vcs_scr_readw(int currcons, u16 *org);
+extern void vcs_scr_writew(int currcons, u16 val, u16 *org);
+
#endif
+++ /dev/null
-/*
- * include/linux/simp.h -- simple allocator for cached objects
- *
- * This is meant as a faster and simpler (not full-featured) replacement
- * for SLAB, thus the name "simp" :-)
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#ifndef SIMP_H
-#define SIMP_H
-
-/* used for constructors / destructors */
-typedef void (*structor)(void *);
-
-/* create an object cache */
-/* positive clearable_offset means the next two pointers at that offset
- * can be internally used for freelist pointers when the object is
- * deallocated / not in use;
- * if there is no space inside the element that can be reused for
- * this purpose, supply -1. Using positive offsets is essential for
- * saving space with very small-sized objects.
- *
- * Note for big-sized objects in the range of whole pages, use
- * the fast Linux page allocator instead, directly.
- */
-extern struct simp * simp_create(char * name, long size,
- structor first_ctor,
- structor again_ctor,
- structor dtor);
-
-/* alloc / dealloc routines */
-extern void * simp_alloc(struct simp * simp);
-extern void simp_free(void * objp);
-
-/* garbage collection */
-extern long simp_garbage(void);
-
-#endif
extern int skb_tailroom(struct sk_buff *skb);
extern void skb_reserve(struct sk_buff *skb, unsigned int len);
extern void skb_trim(struct sk_buff *skb, unsigned int len);
+extern void skb_over_panic(struct sk_buff *skb, int len, void *here);
+extern void skb_under_panic(struct sk_buff *skb, int len, void *here);
/* Internal */
extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
return result;
}
-
-extern const char skb_put_errstr[];
-extern const char skb_push_errstr[];
-
/*
* Add data to an sk_buff
*/
skb->len+=len;
if(skb->tail>skb->end)
{
- __label__ here;
- panic(skb_put_errstr,&&here,len);
-here: ;
+ __label__ here;
+ skb_over_panic(skb, len, &&here);
+here: ;
}
return tmp;
}
if(skb->data<skb->head)
{
__label__ here;
- panic(skb_push_errstr, &&here,len);
-here: ;
+ skb_under_panic(skb, len, &&here);
+here: ;
}
return skb->data;
}
#define PF_ROUTE AF_ROUTE
#define PF_PACKET AF_PACKET
#define PF_ASH AF_ASH
+#define PF_ECONET AF_ECONET
#define PF_ATMSVC AF_ATMSVC
#define PF_SNA AF_SNA
* with information needed by the vt package
*/
+#include <linux/config.h>
#include <linux/vt.h>
/*
* fixed. The linux/Documentation directory includes a code snippet
* to save and restore the text font.
*/
+#ifdef CONFIG_VGA_CONSOLE
#define BROKEN_GRAPHICS_PROGRAMS 1
+#endif
extern struct vt_struct {
int vc_num; /* The console number */
int con_get_trans_old(unsigned char * table);
int con_set_trans_new(unsigned short * table);
int con_get_trans_new(unsigned short * table);
-void con_clear_unimap(struct unimapinit *ui);
-int con_set_unimap(ushort ct, struct unipair *list);
-int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
-void con_set_default_unimap(void);
+int con_clear_unimap(int currcons, struct unimapinit *ui);
+int con_set_unimap(int currcons, ushort ct, struct unipair *list);
+int con_get_unimap(int currcons, ushort ct, ushort *uct, struct unipair *list);
+int con_set_default_unimap(int currcons);
+void con_free_unimap(int currcons);
+void con_protect_unimap(int currcons, int rdonly);
/* vt.c */
extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern void rt6_ifdown(struct device *dev);
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $
+ * $Id: ipv6.h,v 1.12 1998/07/15 05:05:02 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
__u8 *nhptr;
};
+struct ipv6_tlvtype
+{
+ u8 type;
+ u8 len;
+};
+
+struct ip6_ra_chain
+{
+ struct ip6_ra_chain *next;
+ struct sock *sk;
+ int sel;
+ void (*destructor)(struct sock *);
+};
+
+extern struct ip6_ra_chain *ip6_ra_chain;
+
+extern int ip6_ra_control(struct sock *sk, int sel,
+ void (*destructor)(struct sock *));
+
+
+extern int ip6_call_ra_chain(struct sk_buff *skb, int sel);
+
+extern int ip6_dstopt_unknown(struct sk_buff *skb,
+ struct ipv6_tlvtype *hdr);
+
extern int ipv6_routing_header(struct sk_buff **skb,
struct device *dev,
__u8 *nhptr,
#endif
#ifdef CONFIG_NETLINK
struct netlink_opt af_netlink;
+#endif
+#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
+ struct econet_opt *af_econet;
#endif
} protinfo;
extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
extern void x25_destroy_socket(struct sock *);
extern int x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
+extern void x25_kill_by_neigh(struct x25_neigh *);
#include <net/x25call.h>
extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
extern int x25_create_facilities(unsigned char *, struct x25_facilities *);
extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
+extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
/* x25_in.c */
extern int x25_process_rx_frame(struct sock *, struct sk_buff *);
*/
void clear_page_tables(struct task_struct * tsk)
{
+ pgd_t * page_dir = tsk->mm->pgd;
int i;
- pgd_t * page_dir;
- page_dir = tsk->mm->pgd;
- if (!page_dir || page_dir == swapper_pg_dir) {
- printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
- return;
- }
+ if (!page_dir || page_dir == swapper_pg_dir)
+ goto out_bad;
for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
free_one_pgd(page_dir + i);
+
+ /* keep the page table cache within bounds */
+ check_pgt_cache();
+ return;
+
+out_bad:
+ printk(KERN_ERR
+ "clear_page_tables: %s trying to clear kernel pgd\n",
+ tsk->comm);
+ return;
}
/*
*/
void free_page_tables(struct mm_struct * mm)
{
+ pgd_t * page_dir = mm->pgd;
int i;
- pgd_t * page_dir;
- page_dir = mm->pgd;
- if (page_dir) {
- if (page_dir == swapper_pg_dir) {
- printk("free_page_tables: Trying to free kernel pgd\n");
- return;
- }
- for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
- free_one_pgd(page_dir + i);
- pgd_free(page_dir);
- }
+ if (!page_dir)
+ goto out;
+ if (page_dir == swapper_pg_dir)
+ goto out_bad;
+ for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
+ free_one_pgd(page_dir + i);
+ pgd_free(page_dir);
+
+ /* keep the page table cache within bounds */
+ check_pgt_cache();
+out:
+ return;
+
+out_bad:
+ printk(KERN_ERR
+ "free_page_tables: Trying to free kernel pgd\n");
+ return;
}
int new_page_tables(struct task_struct * tsk)
if ((prot & PROT_WRITE) && !(file->f_mode & 2))
return -EACCES;
+ /* Make sure we don't allow writing to an append-only file.. */
+ if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2))
+ return -EACCES;
+
/* make sure there are no mandatory locks on the file. */
if (locks_verify_locked(file->f_dentry->d_inode))
return -EAGAIN;
+
/* fall through */
case MAP_PRIVATE:
if (!(file->f_mode & 1))
+++ /dev/null
-#define NULL 0
-/*
- * mm/simp.c -- simple allocator for cached objects
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#include <linux/simp.h>
-#include <linux/tasks.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
-#include <asm/spinlock.h>
-
-/* The next two defines can be independently enabled for debugging */
-/*#define DEBUG*/
-/*#define DEAD_BEEF*/
-
-#ifdef DEAD_BEEF
-#define DEBUG_BEEF 1
-#else
-#define DEBUG_BEEF 0
-#endif
-
-#ifdef __SMP__
-#define NR_PROCESSORS NR_CPUS
-#define GLOBAL_SIZE CHUNK_SIZE
-#else
-#define NR_PROCESSORS 1
-#define GLOBAL_SIZE PAGE_SIZE
-#endif
-
-#define POSTBUFFER_SIZE 63
-#define ORDER 2
-#define CHUNK_SIZE (PAGE_SIZE*(1<<ORDER))
-#define CHUNK_BASE(ptr) (struct header*)(((unsigned long)(ptr)) & ~(CHUNK_SIZE-1))
-#define CHUNK_END(hdr) (void**)((char*)(hdr) + CHUNK_SIZE)
-
-#define COLOR_INCREMENT (8*sizeof(void*)) /* should be 1 cache line */
-#define ALIGN_CACHE(adr) ((((((unsigned long)adr) - 1) / COLOR_INCREMENT) + 1) * COLOR_INCREMENT)
-#define HEADER_SIZE ALIGN_CACHE(sizeof(struct header))
-#define ELEM_SIZE ALIGN_CACHE(sizeof(struct elem))
-#define FILL_TYPE(name,wrongsize) char name[ALIGN_CACHE(wrongsize)-(wrongsize)]
-
-#define MAX_SIMPS ((GLOBAL_SIZE / sizeof(struct simp)) - 1)
-
-struct header { /* this is at the beginning of each memory region */
- /* 1st cache line */
- void ** index;
- void ** fresh;
- struct simp * father;
- void ** emptypos;
- struct header * next;
- structor again_ctor;
- structor first_ctor;
- void * fill[1];
-#ifdef DEBUG
- /* 2nd cache line */
- char magic[32];
-#endif
-};
-
-struct per_processor {
- void ** buffer_pos;
- void * postbuffer[POSTBUFFER_SIZE];
-};
-
-struct simp {
- /* 1st cache lines */
- struct per_processor private[NR_PROCESSORS];
- /* next cache line */
- struct header * usable_list;
- spinlock_t lock;
- /* This value is negative on Alpha SMP. */
- /* char fill[sizeof(void*) - sizeof(spinlock_t)]; */
- long real_size;
- long max_elems;
- structor again_ctor;
- structor first_ctor;
- structor dtor;
- long fill2;
- /* next cache line */
- long create_offset;
- long color;
- long max_color;
- long size;
- long fill3[4];
- /* next cache line */
- char name[32];
-};
-
-struct global_data {
- /* 1st cache line */
- long changed_flag;
- long nr_simps;
- spinlock_t lock;
- char fill[(6+8)*sizeof(void*)+sizeof(void*)-sizeof(spinlock_t)];
- /* rest */
- struct simp simps[MAX_SIMPS];
-};
-
-static struct global_data * global = NULL;
-
-#ifdef DEBUG
-static char global_magic[32] = "SIMP header SdC581oi9rY20051962\n";
-#endif
-
-struct simp * simp_create(char * name, long size,
- structor first_ctor,
- structor again_ctor,
- structor dtor)
-{
- struct simp * simp;
- long fraction;
- long real_size;
- int cpu;
-
- if(!global) {
-#ifdef __SMP__
- global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER);
- memset(global, 0, CHUNK_SIZE);
-#else
- global = (struct global_data*)get_free_page(GFP_KERNEL);
-#endif
- spin_lock_init(&global->lock);
- }
-
- spin_lock(&global->lock);
- simp = &global->simps[global->nr_simps++];
- spin_unlock(&global->lock);
-
- if(global->nr_simps >= MAX_SIMPS) {
- printk("SIMP: too many simps allocated\n");
- return NULL;
- }
- memset(simp, 0, sizeof(struct simp));
- spin_lock_init(&simp->lock);
- strncpy(simp->name, name, 15);
- simp->size = size;
- simp->real_size = real_size = ALIGN_CACHE(size);
- /* allow aggregation of very small objects in 2-power fractions of
- * cachelines */
- fraction = COLOR_INCREMENT / 2;
- while(size <= fraction && fraction >= sizeof(void*)) {
- simp->real_size = fraction;
- fraction >>= 1;
- }
- simp->first_ctor = first_ctor;
- simp->again_ctor = again_ctor;
- simp->dtor = dtor;
-
- real_size += sizeof(void*);
- simp->max_elems = (CHUNK_SIZE - HEADER_SIZE) / real_size;
- simp->max_color = (CHUNK_SIZE - HEADER_SIZE) % real_size;
- for(cpu = 0; cpu < NR_PROCESSORS; cpu++) {
- struct per_processor * private = &simp->private[cpu];
- private->buffer_pos = private->postbuffer;
- }
- return simp;
-}
-
-/* Do *not* inline this, it clobbers too many registers... */
-static void alloc_header(struct simp * simp)
-{
- struct header * hdr;
- char * ptr;
- void ** index;
- long count;
-
- spin_unlock(&simp->lock);
- for(;;) {
- hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER);
- if(hdr)
- break;
- if(!simp_garbage())
- return;
- }
-#ifdef DEBUG
- if(CHUNK_BASE(hdr) != hdr)
- panic("simp: bad kernel page alignment");
-#endif
-
- memset(hdr, 0, HEADER_SIZE);
-#ifdef DEBUG
- memcpy(hdr->magic, global_magic, sizeof(global_magic));
-#endif
- hdr->father = simp;
- hdr->again_ctor = simp->again_ctor;
- hdr->first_ctor = simp->first_ctor;
-
- /* note: races on simp->color don't produce any error :-) */
- ptr = ((char*)hdr) + HEADER_SIZE + simp->color;
- index = CHUNK_END(hdr);
- for(count = 0; count < simp->max_elems; count++) {
- *--index = ptr;
- ptr += simp->real_size;
- /* note: constructors are not called here in bunch but
- * instead at each single simp_alloc(), in order
- * to maximize chances that the cache will be
- * polluted after a simp_alloc() anyway,
- * and not here. */
- }
- hdr->index = hdr->fresh = hdr->emptypos = index;
-
- spin_lock(&simp->lock);
- simp->color += COLOR_INCREMENT;
- if(simp->color >= simp->max_color)
- simp->color = 0;
- hdr->next = simp->usable_list;
- simp->usable_list = hdr;
-}
-
-/* current x86 memcpy() is horribly moving around registers for nothing,
- * is doing unnecessary work if the size is dividable by a power-of-two,
- * and it clobbers way too many registers.
- * This results in nearly any other register being transfered to stack.
- * Fixing this would be a major win for the whole kernel!
- */
-static void ** bunch_alloc(struct simp * simp, void ** buffer)
-{
- struct header * hdr;
- void ** index;
- void ** to;
- void ** end;
- structor todo;
- long length;
-
- spin_lock(&simp->lock);
- hdr = simp->usable_list;
- if(!hdr) {
- alloc_header(simp);
- hdr = simp->usable_list;
- if(!hdr) {
- spin_unlock(&simp->lock);
- *buffer = NULL;
- return buffer+1;
- }
- }
-
- index = hdr->index;
- end = hdr->fresh;
- todo = hdr->again_ctor;
- if(index == end) {
- end = CHUNK_END(hdr);
- todo = hdr->first_ctor;
- }
- to = index + POSTBUFFER_SIZE/2;
- if(to >= end) {
- to = end;
- if(to == CHUNK_END(hdr)) {
- simp->usable_list = hdr->next;
- hdr->next = NULL;
- }
- }
- if(to > hdr->fresh)
- hdr->fresh = to;
- hdr->index = to;
- length = ((unsigned long)to) - (unsigned long)index;
- to = buffer + (length/sizeof(void**));
-
- memcpy(buffer, index, length);
-
- spin_unlock(&simp->lock);
-
- if(todo) {
- do {
- todo(*buffer++);
- } while(buffer < to);
- }
- return to;
-}
-
-void * simp_alloc(struct simp * simp)
-{
-#ifdef __SMP__
- const long cpu = smp_processor_id();
- struct per_processor * priv = &simp->private[cpu];
-#else
-#define priv (&simp->private[0]) /*fool gcc to use no extra register*/
-#endif
- void ** buffer_pos = priv->buffer_pos;
- void * res;
-
- if(buffer_pos == priv->postbuffer) {
- buffer_pos = bunch_alloc(simp, buffer_pos);
- }
- buffer_pos--;
- res = *buffer_pos;
- priv->buffer_pos = buffer_pos;
- return res;
-}
-
-#ifdef DEBUG
-long check_header(struct header * hdr, void * ptr)
-{
- void ** test;
-
- if(!hdr) {
- printk("SIMP: simp_free() with NULL pointer\n");
- return 1;
- }
- if(strncmp(hdr->magic, global_magic, 32)) {
- printk("SIMP: simpe_free() with bad ptr %p, or header corruption\n", ptr);
- return 1;
- }
- /* This is brute force, but I don't want to pay for any
- * overhead if debugging is not enabled, in particular
- * no space overhead for keeping hashtables etc. */
- test = hdr->index;
- while(test < CHUNK_END(hdr)) {
- if(*test++ == ptr) {
- printk("SIMP: trying to simp_free(%p) again\n", ptr);
- return 1;
- }
- }
- return 0;
-}
-#endif
-
-static void ** bunch_free(struct simp * simp, void ** buffer)
-{
- void ** stop;
-
- stop = buffer - POSTBUFFER_SIZE/3;
-
- spin_lock(&simp->lock);
- while(buffer > stop) {
- void * elem = buffer[-1];
- struct header * hdr = CHUNK_BASE(elem);
- void ** index = hdr->index;
- index--;
- hdr->index = index;
- *index = elem;
- if(!hdr->next) {
- hdr->next = simp->usable_list;
- simp->usable_list = hdr;
- }
-
- buffer -= 2;
- elem = *buffer;
- hdr = CHUNK_BASE(elem);
- index = hdr->index;
- index--;
- hdr->index = index;
- *index = elem;
- if(!hdr->next) {
- hdr->next = simp->usable_list;
- simp->usable_list = hdr;
- }
- }
- spin_unlock(&simp->lock);
- global->changed_flag = 1;
- return buffer;
-}
-
-void simp_free(void * objp)
-{
- struct header * hdr;
- void ** buffer_pos;
- struct per_processor * private;
-#ifdef __SMP__
- const long cpu = smp_processor_id();
-#else
- const long cpu = 0;
-#endif
-
- hdr = CHUNK_BASE(objp);
-#ifdef DEBUG
- if(check_header(hdr, objp))
- return;
-#endif
-
- private = &hdr->father->private[cpu];
- buffer_pos = private->buffer_pos;
- if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) {
- buffer_pos = bunch_free(hdr->father, buffer_pos);
- }
-
- *buffer_pos++ = objp;
- private->buffer_pos = buffer_pos;
-
-#ifdef DEAD_BEEF
- {
- unsigned int * ptr = (unsigned int*)objp;
- int count = (hdr->father->real_size - ELEM_SIZE) / sizeof(unsigned int);
- while(count--)
- *ptr++ = 0xdeadbeef;
- }
-#endif
-}
-
-long simp_garbage(void)
-{
- int i;
- int res;
-
- if(!global->changed_flag)
- return 0; /* shortcut */
- /* Note: costs do not matter here. Any heavy thrashing of
- * simp chunks that could be caused by pools stealing each
- * other's memory has to be considered a BUG :-)
- * Simply avoid memory shortages by conservative allocating
- * policies.
- */
- global->changed_flag = 0;
- res = 0;
- for(i = 0; i < global->nr_simps; i++) {
- struct simp * simp = &global->simps[i];
- struct header ** base = &simp->usable_list;
- struct header * del;
-
- spin_lock(&simp->lock);
- del = *base;
- while(del) {
- if(del->index == del->emptypos) {
- if(simp->dtor) {
- void ** ptr = del->index;
- while(ptr < CHUNK_END(del)) {
- simp->dtor(*ptr++);
- }
- }
- *base = del->next;
-#ifdef DEBUG
- memset(del, 0, CHUNK_SIZE);
-#endif
- free_pages((unsigned long)del, ORDER);
- res++;
- } else
- base = &del->next;
- del = *base;
- }
- spin_unlock(&simp->lock);
- }
- return res;
-}
-
MOD_SUB_DIRS := ipv4
ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
- netrom rose lapb x25 wanrouter netlink sched packet sunrpc #decnet
+ netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
+ econet #decnet
SUB_DIRS := core ethernet sched
MOD_LIST_NAME := NET_MISC_MODULES
endif
endif
+ifeq ($(CONFIG_ECONET),y)
+SUB_DIRS += econet
+else
+ ifeq ($(CONFIG_ECONET),m)
+ MOD_SUB_DIRS += econet
+ endif
+endif
+
# We must attach netsyms.o to socket.o, as otherwise there is nothing
# to pull the object file from the archive.
* Jonathan(G4KLX) Support for packet forwarding.
* AX.25 036 Jonathan(G4KLX) Major restructuring.
* Joerg(DL1BKE) Fixed DAMA Slave.
- * Jonathan(G4KLX) Fix widlcard listen parameter setting.
+ * Jonathan(G4KLX) Fix wildcard listen parameter setting.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel
* independent of AX25_MAX_DIGIS used by applications.
static kmem_cache_t *skbuff_head_cache;
/*
- * Strings we don't want inline's duplicating
+ * Keep out-of-line to prevent kernel bloat.
+ * __builtin_return_address is not used because it is not always
+ * reliable.
*/
-
-const char skb_push_errstr[]="skpush:under: %p:%d";
-const char skb_put_errstr[] ="skput:over: %p:%d";
+
+void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+{
+ panic("skput:over: %p:%d put:%d dev:%s",
+ here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
+
+void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+{
+ panic("skput:over: %p:%d put:%d dev:%s",
+ here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
void show_net_buffers(void)
{
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
are treated in BSD as hints */
if (val > sysctl_wmem_max)
- return 0;
+ val = sysctl_wmem_max;
sk->sndbuf = max(val*2,2048);
are treated in BSD as hints */
if (val > sysctl_rmem_max)
- return 0;
+ val = sysctl_rmem_max;
/* FIXME: is this lower bound the right one? */
sk->rcvbuf = max(val*2,256);
kmem_cache_free(sk_cachep, sk);
}
-void sk_init(void)
+__initfunc(void sk_init(void))
{
sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
SLAB_HWCACHE_ALIGN, 0, 0);
+
}
/*
econet_release,
econet_bind,
sock_no_connect,
- NULL,
- NULL,
+ sock_no_socketpair,
+ sock_no_accept,
econet_getname,
datagram_poll,
econet_ioctl,
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $
+ * Version: $Id: arp.c,v 1.67 1998/06/19 13:22:31 davem Exp $
*
* Copyright (C) 1994 by Florian La Roche
*
* 2 of the License, or (at your option) any later version.
*
* Fixes:
- * Alan Cox : Removed the ethernet assumptions in
+ * Alan Cox : Removed the Ethernet assumptions in
* Florian's code
* Alan Cox : Fixed some small errors in the ARP
* logic
neigh->ops = &arp_direct_ops;
neigh->output = neigh->ops->queue_xmit;
} else {
- /* Good devices (checked by reading texts, but only ethernet is
+ /* Good devices (checked by reading texts, but only Ethernet is
tested)
ARPHRD_ETHER: (ethernet, apfddi)
ARPHRD_ARCNET:
etc. etc. etc.
- ARPHRD_IPDDP will also work, if author repaires it.
+ ARPHRD_IPDDP will also work, if author repairs it.
I did not it, because this driver does not work even
in old paradigm.
*/
#ifdef CONFIG_AX25_MODULE
/*
- * ax25 -> ascii conversion
+ * ax25 -> ASCII conversion
*/
char *ax2asc(ax25_address *a)
{
*
* IPv4 FIB: lookup engine and maintenance routines.
*
- * Version: $Id: fib_hash.c,v 1.3 1998/03/08 05:56:16 davem Exp $
+ * Version: $Id: fib_hash.c,v 1.4 1998/07/15 05:05:08 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
#endif
) {
if (matched)
- return 1;
+ break;
continue;
}
matched = 1;
*
* Alan Cox, <alan@cymru.net>
*
- * Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
+ * Version: $Id: icmp.c,v 1.44 1998/06/16 04:38:27 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
+ * Version: $Id: ip_fragment.c,v 1.38 1998/06/16 04:38:29 davem Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
+ * Version: $Id: ip_output.c,v 1.59 1998/07/15 05:05:15 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* will inherit fixed options.
*/
if (offset == 0)
- ip_options_fragment(skb2);
+ ip_options_fragment(skb);
/*
* Added AC : If we are fragmenting a fragment that's not the
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $
+ * Version: $Id: ip_sockglue.c,v 1.36 1998/07/15 05:05:06 davem Exp $
*
* Authors: see ip.c
*
static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
{
- if (IPCB(skb)->opt.optlen == 0)
- return;
-
put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl);
}
static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
{
- if (IPCB(skb)->opt.optlen == 0)
- return;
-
put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
}
/*
- * $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
+ * $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
*
* Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
* information to configure own IP address and routes.
if (rarp->ar_op != htons(ARPOP_RREPLY))
goto drop;
- /* If it's not ethernet, delete it. */
+ /* If it's not Ethernet, delete it. */
if (rarp->ar_pro != htons(ETH_P_IP))
goto drop;
* Copyright (C) 1994 by Ross Martin
* Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
*
- * $Id: rarp.c,v 1.24 1998/03/08 05:56:30 davem Exp $
+ * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $
*
* This module implements the Reverse Address Resolution Protocol
* (RARP, RFC 903), which is used to convert low level addresses such
- * as ethernet addresses into high level addresses such as IP addresses.
+ * as Ethernet addresses into high level addresses such as IP addresses.
* The most common use of RARP is as a means for a diskless workstation
* to discover its IP address during a network boot.
*
*** unless you have all the rest to boot the box from it.
**
*
- * Currently, only ethernet address -> IP address is likely to work.
+ * Currently, only Ethernet address -> IP address is likely to work.
* (Is RARP ever used for anything else?)
*
* This code is free software; you can redistribute it and/or
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
+ * Version: $Id: route.c,v 1.54 1998/07/15 05:05:22 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
}
/* Multicast recognition logic is moved from route cache to here.
- The problem was that too many ethernet cards have broken/missing
+ The problem was that too many Ethernet cards have broken/missing
hardware multicast filters :-( As result the host on multicasting
network acquires a lot of useless route cache entries, sort of
SDR messages from all the world. Now we try to get rid of them.
nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;
r->rtm_family = AF_INET;
r->rtm_dst_len = 32;
- r->rtm_src_len = 32;
+ r->rtm_src_len = 0;
r->rtm_tos = rt->key.tos;
r->rtm_table = RT_TABLE_MAIN;
r->rtm_type = rt->rt_type;
o = skb->tail;
#endif
RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
- RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src);
+ if (rt->key.src) {
+ r->rtm_src_len = 32;
+ RTA_PUT(skb, RTA_SRC, 4, &rt->key.src);
+ }
if (rt->u.dst.dev)
RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+ if (rt->key.iif)
+ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
+ else if (rt->rt_src != rt->key.src)
+ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
if (rt->rt_dst != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
#ifdef CONFIG_RTNL_OLD_IFINFO
if (mx->rta_len == RTA_LENGTH(0))
skb_trim(skb, (u8*)mx - skb->data);
#endif
- RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
ci.rta_used = atomic_read(&rt->u.dst.refcnt);
ci.rta_clntref = atomic_read(&rt->u.dst.use);
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
+ * Version: $Id: tcp.c,v 1.116 1998/07/26 03:06:54 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.121 1998/07/15 04:39:12 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
}
}
-/* Calculate rto without backoff. This is the second half of Van Jacobsons
- * routine refered to above.
+/* Calculate rto without backoff. This is the second half of Van Jacobson's
+ * routine referred to above.
*/
static __inline__ void tcp_set_rto(struct tcp_opt *tp)
}
/* WARNING: this must not be called if tp->saw_timestamp was false. */
-extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
+extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp,
+ __u32 start_seq, __u32 end_seq)
{
/* From draft-ietf-tcplw-high-performance: the correct
* test is last_ack_sent <= end_seq.
* (RFC1323 stated last_ack_sent < end_seq.)
+ *
+ * HOWEVER: The current check contradicts the draft statements.
+ * It has been done for good reasons.
+ * The implemented check improves security and eliminates
+ * unnecessary RTT overestimation.
+ * 1998/06/27 Andrey V. Savochkin <saw@msu.ru>
*/
- if (!before(end_seq, tp->last_ack_sent)) {
+ if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) &&
+ !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) {
/* PAWS bug workaround wrt. ACK frames, the PAWS discard
* extra check below makes sure this can only happen
* for pure ACK frames. -DaveM
goto discard;
}
}
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+ tcp_replace_ts_recent(sk, tp,
+ TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
}
}
goto discard;
}
}
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+ tcp_replace_ts_recent(sk, tp,
+ TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
}
}
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.148 1998/07/23 12:28:25 freitag Exp $
*
* IPv4 specific functions
*
return dopt;
}
-int sysctl_max_syn_backlog = 1024;
+/*
+ * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
+ * One SYN_RECV socket costs about 80bytes on a 32bit machine.
+ * It would be better to replace it with a global counter for all sockets
+ * but then some measure against one socket starving all other sockets
+ * would be needed.
+ */
+int sysctl_max_syn_backlog = 128;
struct or_calltable or_ipv4 = {
tcp_v4_send_synack,
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.92 1998/06/19 13:22:44 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
}
}
-/* Function to create two new tcp segments. Shrinks the given segment
+/* Function to create two new TCP segments. Shrinks the given segment
* to the specified size and appends a new segment with the rest of the
- * packet to the list. This won't be called frenquently, I hope...
- * Remember, these are still header-less SKB's at this point.
+ * packet to the list. This won't be called frequently, I hope.
+ * Remember, these are still headerless SKBs at this point.
*/
static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
{
*
* a) following SWS avoidance [and Nagle algorithm]
* b) not exceeding our congestion window.
- * c) not retransmiting [Nagle]
+ * c) not retransmitting [Nagle]
*/
while((skb = tp->send_head) && tcp_snd_test(sk, skb)) {
if (skb->len > mss_now) {
* 2. We limit memory per socket
*
* RFC 1122:
- * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
* RECV.NEXT + RCV.WIN fixed until:
* RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
*
* i.e. don't raise the right edge of the window until you can raise
* it at least MSS bytes.
*
- * Unfortunately, the recomended algorithm breaks header prediction,
+ * Unfortunately, the recommended algorithm breaks header prediction,
* since header prediction assumes th->window stays fixed.
*
* Strictly speaking, keeping th->window fixed violates the receiver
/* This retransmits one SKB. Policy decisions and retransmit queue
* state updates are done by the caller. Returns non-zero if an
- * error occured which prevented the send.
+ * error occurred which prevented the send.
*/
int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
tp->retrans_out++;
/* Make a copy, if the first transmission SKB clone we made
- * is still in somebodies hands, else make a clone.
+ * is still in somebody's hands, else make a clone.
*/
TCP_SKB_CB(skb)->when = jiffies;
if(skb_cloned(skb))
mss = min(mss, sk->user_mss);
if (mss < 1) {
- printk(KERN_DEBUG "intial sk->mss below 1\n");
+ printk(KERN_DEBUG "initial sk->mss below 1\n");
mss = 1; /* Sanity limit */
}
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $
+ * $Id: addrconf.c,v 1.43 1998/07/15 05:05:32 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
struct inet6_dev * idev;
if (dev->type != ARPHRD_ETHER) {
- /* Alas, we support only ethernet autoconfiguration. */
+ /* Alas, we support only Ethernet autoconfiguration. */
return;
}
{ inet6_rtm_newroute, NULL, },
{ inet6_rtm_delroute, NULL, },
- { NULL, inet6_dump_fib, },
+ { inet6_rtm_getroute, inet6_dump_fib, },
{ NULL, NULL, },
};
#endif
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $
+ * $Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
/* New header structures */
-struct ipv6_tlvtype {
- u8 type;
- u8 len;
-};
-
struct tlvtype_proc {
u8 type;
int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
{255, NULL}
};
-static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
+int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
{
struct in6_addr *daddr;
int pos;
* unkown destination option type
*/
- pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw;
+ pos = (__u8 *) hdr - (__u8 *) skb->nh.raw;
/* I think this is correct please check - IPM */
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.12 1998/04/11 22:11:06 davem Exp $
+ * $Id: ip6_output.c,v 1.13 1998/07/15 05:05:38 davem Exp $
*
* Based on linux/net/ipv4/ip_output.c
*
#include <net/protocol.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#include <net/rawv6.h>
static u32 ipv6_fragmentation_id = 1;
return err;
}
+int ip6_call_ra_chain(struct sk_buff *skb, int sel)
+{
+ struct ip6_ra_chain *ra;
+ struct sock *last = NULL;
+
+ for (ra = ip6_ra_chain; ra; ra = ra->next) {
+ struct sock *sk = ra->sk;
+ if (sk && ra->sel == sel) {
+ if (last) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ skb2->sk = last;
+ rawv6_rcv(skb2, skb2->dev, &skb2->nh.ipv6h->saddr,
+ &skb2->nh.ipv6h->daddr, NULL, skb2->len);
+ }
+ }
+ last = sk;
+ }
+ }
+
+ if (last) {
+ skb->sk = last;
+ rawv6_rcv(skb, skb->dev, &skb->nh.ipv6h->saddr,
+ &skb->nh.ipv6h->daddr, NULL, skb->len);
+ return 1;
+ }
+ return 0;
+}
+
int ip6_forward(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
struct ipv6hdr *hdr = skb->nh.ipv6h;
int size;
- if (ipv6_devconf.forwarding == 0) {
- kfree_skb(skb);
- return -EINVAL;
- }
+ if (ipv6_devconf.forwarding == 0)
+ goto drop;
/*
* check hop-by-hop options present
*/
-#if 0
- if (hdr->nexthdr == NEXTHDR_HOP)
- {
+ /*
+ * Note, that NEXTHDR_HOP header must be checked
+ * always at the most beginning of ipv6_rcv.
+ * The result should be saved somewhere, but
+ * we do not it for now. Alas. Let's do it here. --ANK
+ *
+ * Second note: we DO NOT make any processing on
+ * RA packets, pushing them to user level AS IS
+ * without ane WARRANTY that application will able
+ * to interpret them. The reson is that we
+ * cannot make anything clever here.
+ *
+ * We are not end-node, so that if packet contains
+ * AH/ESP, we cannot make anything.
+ * Defragmentation also would be mistake, RA packets
+ * cannot be fragmented, because there is no warranty
+ * that different fragments will go along one path. --ANK
+ */
+ if (hdr->nexthdr == NEXTHDR_HOP) {
+ int ra_value = -1;
+ u8 *ptr = (u8*)(skb->nh.ipv6h+1);
+ int len = (ptr[1]+1)<<3;
+
+ if (len + sizeof(struct ipv6hdr) > skb->len)
+ goto drop;
+
+ ptr += 2;
+ len -= 2;
+ while (len > 0) {
+ u8 *opt;
+ int optlen;
+
+ if (ptr[0] == 0) {
+ len--;
+ ptr++;
+ continue;
+ }
+ opt = ptr;
+ optlen = ptr[1]+1;
+
+ len -= optlen;
+ ptr += optlen;
+ if (len < 0)
+ goto drop;
+
+ if (opt[0] == 20) {
+ /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
+ if (optlen < 4)
+ goto drop;
+ ra_value = opt[2] + (opt[3]<<8);
+ } else if (!ip6_dstopt_unknown(skb, (struct ipv6_tlvtype*)opt))
+ goto drop;
+ }
+ if (ra_value>=0 && ip6_call_ra_chain(skb, ra_value))
+ return 0;
}
-#endif
+
/*
* check and decrement ttl
*/
dst->output(skb);
return 0;
+
+drop:
+ kfree_skb(skb);
+ return -EINVAL;
}
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43:13 davem Exp $
+ * $Id: ipv6_sockglue.c,v 1.22 1998/07/15 05:05:39 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
0
};
+struct ip6_ra_chain *ip6_ra_chain;
+
+int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
+{
+ struct ip6_ra_chain *ra, *new_ra, **rap;
+
+ /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
+ if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
+ return -EINVAL;
+
+ new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+
+ for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+ if (ra->sk == sk) {
+ if (sel>=0) {
+ if (new_ra)
+ kfree(new_ra);
+ return -EADDRINUSE;
+ }
+ *rap = ra->next;
+ if (ra->destructor)
+ ra->destructor(sk);
+ kfree(ra);
+ return 0;
+ }
+ }
+ if (new_ra == NULL)
+ return -ENOBUFS;
+ new_ra->sk = sk;
+ new_ra->sel = sel;
+ new_ra->destructor = destructor;
+ start_bh_atomic();
+ new_ra->next = ra;
+ *rap = new_ra;
+ end_bh_atomic();
+ return 0;
+}
+
+
int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
int optlen)
{
int val, err;
int retv = -ENOPROTOOPT;
+ if(level==SOL_IP && sk->type != SOCK_RAW)
+ return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
if(level!=SOL_IPV6)
goto out;
retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
else
retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
+ break;
}
+ case IPV6_ROUTER_ALERT:
+ retv = ip6_ra_control(sk, val, NULL);
+ break;
};
out:
int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
int *optlen)
{
- return 0;
+ if(level==SOL_IP && sk->type != SOCK_RAW)
+ return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+ if(level!=SOL_IPV6)
+ return -ENOPROTOOPT;
+ return -EINVAL;
}
#if defined(MODULE) && defined(CONFIG_SYSCTL)
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.19 1998/03/20 09:12:20 davem Exp $
+ * $Id: raw.c,v 1.20 1998/07/15 05:05:41 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
{
sk->state = TCP_CLOSE;
ipv6_sock_mc_close(sk);
+ if (sk->num == IPPROTO_RAW)
+ ip6_ra_control(sk, -1, NULL);
sk->dead = 1;
destroy_sock(sk);
}
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $
+ * $Id: route.c,v 1.32 1998/07/25 23:28:52 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
return err;
}
-
struct rt6_rtnl_dump_arg
{
struct sk_buff *skb;
};
static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+ struct in6_addr *dst,
+ struct in6_addr *src,
+ int iif,
int type, pid_t pid, u32 seq)
{
struct rtmsg *rtm;
#ifdef CONFIG_RTNL_OLD_IFINFO
o = skb->tail;
#endif
- if (rtm->rtm_dst_len)
+ if (dst) {
+ RTA_PUT(skb, RTA_DST, 16, dst);
+ rtm->rtm_dst_len = 128;
+ } else if (rtm->rtm_dst_len)
RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
- if (rtm->rtm_src_len)
+ if (src) {
+ RTA_PUT(skb, RTA_SRC, 16, src);
+ rtm->rtm_src_len = 128;
+ } else if (rtm->rtm_src_len)
RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+ if (iif)
+ RTA_PUT(skb, RTA_IIF, 4, &iif);
+ else if (dst) {
+ struct inet6_ifaddr *ifp = ipv6_get_saddr(&rt->u.dst, dst);
+ if (ifp)
+ RTA_PUT(skb, RTA_PREFSRC, 16, &ifp->addr);
+ }
#ifdef CONFIG_RTNL_OLD_IFINFO
if (rt->u.dst.pmtu)
RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
arg->count++;
continue;
}
- if (rt6_fill_node(arg->skb, rt, RTM_NEWROUTE,
+ if (rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq) <= 0) {
arg->stop = 1;
break;
return skb->len;
}
+int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ int iif = 0;
+ int err;
+ struct sk_buff *skb;
+ struct flowi fl;
+ struct rt6_info *rt;
+
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (skb == NULL)
+ return -ENOBUFS;
+
+ /* Reserve room for dummy headers, this skb can pass
+ through good chunk of routing engine.
+ */
+ skb->mac.raw = skb->data;
+ skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
+
+ fl.proto = 0;
+ fl.nl_u.ip6_u.daddr = NULL;
+ fl.nl_u.ip6_u.saddr = NULL;
+ fl.uli_u.icmpt.type = 0;
+ fl.uli_u.icmpt.code = 0;
+ if (rta[RTA_SRC-1])
+ fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
+ if (rta[RTA_DST-1])
+ fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
+
+ if (rta[RTA_IIF-1])
+ memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+
+ if (iif) {
+ struct device *dev;
+ dev = dev_get_by_index(iif);
+ if (!dev)
+ return -ENODEV;
+ }
+
+ fl.oif = 0;
+ if (rta[RTA_OIF-1])
+ memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+
+ rt = (struct rt6_info*)ip6_route_output(NULL, &fl);
+
+ skb->dst = &rt->u.dst;
+
+ NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+ err = rt6_fill_node(skb, rt,
+ fl.nl_u.ip6_u.daddr,
+ fl.nl_u.ip6_u.saddr,
+ iif,
+ RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
+ if (err < 0)
+ return -EMSGSIZE;
+
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
void inet6_rt_notify(int event, struct rt6_info *rt)
{
struct sk_buff *skb;
netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
return;
}
- if (rt6_fill_node(skb, rt, event, 0, 0) < 0) {
+ if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) {
kfree_skb(skb);
netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
return;
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
+ * $Id: udp.c,v 1.31 1998/07/15 05:05:45 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
struct in6_addr *daddr;
struct dst_entry *dst;
- struct ipv6_pinfo *np;
struct inet6_ifaddr *ifa;
struct flowi fl;
int addr_type;
+ int err;
+
+ if (usin->sin6_family == AF_INET) {
+ err = udp_connect(sk, uaddr, addr_len);
+ goto ipv4_connected;
+ }
if (addr_len < sizeof(*usin))
return(-EINVAL);
return(-EAFNOSUPPORT);
addr_type = ipv6_addr_type(&usin->sin6_addr);
- np = &sk->net_pinfo.af_inet6;
if (addr_type == IPV6_ADDR_ANY) {
/*
if (addr_type == IPV6_ADDR_MAPPED) {
struct sockaddr_in sin;
- int err;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = daddr->s6_addr32[3];
+ sin.sin_port = usin->sin6_port;
err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
-
+
+ipv4_connected:
if (err < 0)
return err;
- ipv6_addr_copy(&np->daddr, daddr);
-
+ ipv6_addr_set(&np->daddr, 0, 0,
+ __constant_htonl(0x0000ffff),
+ sk->daddr);
+
if(ipv6_addr_any(&np->saddr)) {
ipv6_addr_set(&np->saddr, 0, 0,
__constant_htonl(0x0000ffff),
__constant_htonl(0x0000ffff),
sk->rcv_saddr);
}
-
+ return 0;
}
ipv6_addr_copy(&np->daddr, daddr);
if (skb->protocol == __constant_htons(ETH_P_IP)) {
ipv6_addr_set(&sin6->sin6_addr, 0, 0,
__constant_htonl(0xffff), skb->nh.iph->saddr);
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
} else {
memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
sizeof(struct in6_addr));
return(-EINVAL);
if (sin6) {
+ if (sin6->sin6_family == AF_INET)
+ return udp_sendmsg(sk, msg, ulen);
+
if (addr_len < sizeof(*sin6))
return(-EINVAL);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = daddr->s6_addr32[3];
+ sin.sin_port = udh.uh.dest;
+ msg->msg_name = (struct sockaddr *)(&sin);
- return udp_sendmsg(sk, msg, len);
+ return udp_sendmsg(sk, msg, ulen);
}
udh.daddr = NULL;
netlink_release,
netlink_bind,
netlink_connect,
- NULL,
- NULL,
+ sock_no_socketpair,
+ sock_no_accept,
netlink_getname,
datagram_poll,
sock_no_ioctl,
sock_no_listen,
sock_no_shutdown,
- NULL,
- NULL,
+ sock_no_setsockopt,
+ sock_no_getsockopt,
sock_no_fcntl,
netlink_sendmsg,
netlink_recvmsg
defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \
defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \
defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \
- defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \
- defined(CONFIG_LNE390)
+ defined(CONFIG_ES3210)
#include "../drivers/net/8390.h"
#endif
EXPORT_SYMBOL(dev_lockct);
/* Skbuff symbols. */
-EXPORT_SYMBOL(skb_push_errstr);
-EXPORT_SYMBOL(skb_put_errstr);
+EXPORT_SYMBOL(skb_over_panic);
+EXPORT_SYMBOL(skb_under_panic);
/* Socket layer registration */
EXPORT_SYMBOL(sock_register);
EXPORT_SYMBOL(ip_mc_dec_group);
EXPORT_SYMBOL(__ip_finish_output);
EXPORT_SYMBOL(inet_dgram_ops);
+EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(__release_sock);
/* needed for ip_gre -cw */
defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \
defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \
defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \
- defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \
- defined(CONFIG_LNE390)
+ defined(CONFIG_ES3210)
/* If 8390 NIC support is built in, we will need these. */
EXPORT_SYMBOL(ei_open);
EXPORT_SYMBOL(ei_close);
packet_release,
packet_bind_spkt,
sock_no_connect,
- NULL,
- NULL,
+ sock_no_socketpair,
+ sock_no_accept,
packet_getname_spkt,
datagram_poll,
packet_ioctl,
struct sock *s;
for (s = x25_list; s != NULL; s = s->next)
- if (s->protinfo.x25->neighbour->dev == dev)
+ if (s->protinfo.x25->neighbour &&
+ s->protinfo.x25->neighbour->dev == dev)
x25_disconnect(s, ENETUNREACH, 0, 0);
}
if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
return -ENETUNREACH;
+ x25_limit_facilities(&sk->protinfo.x25->facilities,
+ sk->protinfo.x25->neighbour);
+
if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
return -ENETUNREACH;
return 0;
}
+ /*
+ * current neighbour/link might impose additional limits
+ * on certain facilties
+ */
+
+ x25_limit_facilities(&facilities,neigh);
+
/*
* Try to create a new socket.
*/
return -EINVAL;
if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
return -EINVAL;
- if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended)
- {
- if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
- return -EINVAL;
- if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
- return -EINVAL;
- } else {
- if (facilities.winsize_in < 1 || facilities.winsize_in > 7)
- return -EINVAL;
- if (facilities.winsize_out < 1 || facilities.winsize_out > 7)
- return -EINVAL;
- }
+ if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
+ return -EINVAL;
if (facilities.throughput < 0x03 || facilities.throughput > 0x2C)
return -EINVAL;
if (facilities.reverse != 0 && facilities.reverse != 1)
0
};
+void x25_kill_by_neigh(struct x25_neigh *neigh)
+{
+ struct sock *s;
+
+ for( s=x25_list; s != NULL; s=s->next){
+ if( s->protinfo.x25->neighbour == neigh )
+ x25_disconnect(s, ENETUNREACH, 0, 0);
+ }
+}
+
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry proc_net_x25 = {
PROC_NET_X25, 3, "x25",
int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
{
struct x25_neigh *neigh;
+ int queued;
skb->sk = NULL;
switch (skb->data[0]) {
case 0x00:
skb_pull(skb, 1);
- return x25_receive_data(skb, neigh);
+ queued = x25_receive_data(skb, neigh);
+ if( ! queued )
+ /* We need to free the skb ourselves because
+ * net_bh() won't care about our return code.
+ */
+ kfree_skb(skb);
+ return 0;
case 0x01:
x25_link_established(neigh);
{
unsigned char *dptr;
+ skb->nh.raw = skb->data;
+
switch (neigh->dev->type) {
case ARPHRD_X25:
dptr = skb_push(skb, 1);
}
#endif
+
+
+
return len;
}
+/*
+ * Limit values of certain facilities according to the capability of the
+ * currently attached x25 link.
+ */
+void x25_limit_facilities(struct x25_facilities *facilities,
+ struct x25_neigh *neighbour)
+{
+
+ if( ! neighbour->extended ){
+ if( facilities->winsize_in > 7 ){
+ printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
+ facilities->winsize_in = 7;
+ }
+ if( facilities->winsize_out > 7 ){
+ facilities->winsize_out = 7;
+ printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
+ }
+ }
+}
+
#endif
+
+
if (more) {
sk->protinfo.x25->fraglen += skb->len;
skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+ skb_set_owner_r(skb, sk);
return 0;
}
if (!more && sk->protinfo.x25->fraglen > 0) { /* End of fragment */
- sk->protinfo.x25->fraglen += skb->len;
- skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+ int len = sk->protinfo.x25->fraglen + skb->len;
- if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL)
+ if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+ kfree_skb(skb);
return 1;
+ }
+
+ skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
- skb_set_owner_r(skbn, sk);
skbn->h.raw = skbn->data;
skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue);
sk->protinfo.x25->fraglen = 0;
}
- return sock_queue_rcv_skb(sk, skbn);
+ skb_set_owner_r(skbn, sk);
+ skb_queue_tail(&sk->receive_queue, skbn);
+ if (!sk->dead)
+ sk->data_ready(sk,skbn->len);
+
+ return 0;
}
/*
/*
* Called when the link layer has terminated, or an establishment
- * request has failed. XXX should tell sockets.
+ * request has failed.
*/
+
void x25_link_terminated(struct x25_neigh *neigh)
{
neigh->state = X25_LINK_STATE_0;
+ /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
+ x25_kill_by_neigh(neigh);
}
/*