summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
commit4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch)
treecddb50a81d7d1a628cc400519162080c6d87868e /drivers
parent36ea5120664550fae6d31f1c6f695e4f8975cb06 (diff)
o Merge with Linux 2.1.91.
o First round of bugfixes for the SC/MC CPUs. o FPU context switch fixes. o Lazy context switches. o Faster syscalls. o Removed dead code. o Shitloads of other things I forgot ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/amiflop.c1503
-rw-r--r--drivers/block/loop.c56
-rw-r--r--drivers/block/nbd.c27
-rw-r--r--drivers/char/amigamouse.c2
-rw-r--r--drivers/char/amikeyb.c343
-rw-r--r--drivers/char/dn_keyb.c614
-rw-r--r--drivers/char/hfmodem/gentbl.c2
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/macmouse.c311
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/pc_keyb.c10
-rw-r--r--drivers/char/stallion.c11
-rw-r--r--drivers/char/tty_io.c5
-rw-r--r--drivers/misc/parport_pc.c24
-rw-r--r--drivers/misc/parport_share.c4
-rw-r--r--drivers/net/3c523.c4
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/Makefile16
-rw-r--r--drivers/net/hamradio/soundmodem/gentbl.c4
-rw-r--r--drivers/net/sdla_fr.c2430
-rw-r--r--drivers/net/sdla_ppp.c2269
-rw-r--r--drivers/net/sdla_x25.c870
-rw-r--r--drivers/net/sdladrv.c31
-rw-r--r--drivers/net/sgiseeq.c19
-rw-r--r--drivers/net/sk_g16.c12
-rw-r--r--drivers/nubus/Makefile15
-rw-r--r--drivers/nubus/nubus.c629
-rw-r--r--drivers/pci/pci.c9
-rw-r--r--drivers/scsi/53c7xx.c189
-rw-r--r--drivers/scsi/53c7xx.h2
-rw-r--r--drivers/scsi/53c7xx.scr6
-rw-r--r--drivers/scsi/NCR53C9x.c3733
-rw-r--r--drivers/scsi/NCR53C9x.h529
-rw-r--r--drivers/scsi/a2091.c8
-rw-r--r--drivers/scsi/amiga7xx.c52
-rw-r--r--drivers/scsi/amiga7xx.h2
-rw-r--r--drivers/scsi/atari_dma_emul.c466
-rw-r--r--drivers/scsi/atari_scsi.c30
-rw-r--r--drivers/scsi/gvp11.c154
-rw-r--r--drivers/scsi/mvme16x.c60
-rw-r--r--drivers/scsi/mvme16x.h53
-rw-r--r--drivers/scsi/scsi.h15
-rw-r--r--drivers/scsi/sgiwd93.c7
-rw-r--r--drivers/scsi/wd33c93.c2
-rw-r--r--drivers/sgi/char/cons_newport.c7
-rw-r--r--drivers/sgi/char/graphics.c7
-rw-r--r--drivers/sgi/char/sgiserial.c5
-rw-r--r--drivers/sgi/char/streamable.c6
-rw-r--r--drivers/sgi/char/usema.c8
-rw-r--r--drivers/sound/pas2_card.c2
-rw-r--r--drivers/video/Config.in89
-rw-r--r--drivers/video/Makefile160
-rw-r--r--drivers/video/S3triofb.c885
-rw-r--r--drivers/video/amifb.c821
-rw-r--r--drivers/video/atafb.c517
-rw-r--r--drivers/video/ati-gt.h203
-rw-r--r--drivers/video/ati-gx.h122
-rw-r--r--drivers/video/ati-vt.h147
-rw-r--r--drivers/video/aty.h923
-rw-r--r--drivers/video/atyfb.c1685
-rw-r--r--drivers/video/cyberfb.c629
-rw-r--r--drivers/video/dnfb.c (renamed from drivers/video/dn_fb.c)161
-rw-r--r--drivers/video/fbcmap.c105
-rw-r--r--drivers/video/fbcon-afb.c399
-rw-r--r--drivers/video/fbcon-afb.h15
-rw-r--r--drivers/video/fbcon-cfb16.c194
-rw-r--r--drivers/video/fbcon-cfb16.h16
-rw-r--r--drivers/video/fbcon-cfb2.c205
-rw-r--r--drivers/video/fbcon-cfb2.h15
-rw-r--r--drivers/video/fbcon-cfb24.c221
-rw-r--r--drivers/video/fbcon-cfb24.h16
-rw-r--r--drivers/video/fbcon-cfb32.c205
-rw-r--r--drivers/video/fbcon-cfb32.h16
-rw-r--r--drivers/video/fbcon-cfb4.c208
-rw-r--r--drivers/video/fbcon-cfb4.h15
-rw-r--r--drivers/video/fbcon-cfb8.c141
-rw-r--r--drivers/video/fbcon-cfb8.h15
-rw-r--r--drivers/video/fbcon-cyber.c229
-rw-r--r--drivers/video/fbcon-ilbm.c137
-rw-r--r--drivers/video/fbcon-ilbm.h15
-rw-r--r--drivers/video/fbcon-iplan2p2.c241
-rw-r--r--drivers/video/fbcon-iplan2p2.h15
-rw-r--r--drivers/video/fbcon-iplan2p4.c262
-rw-r--r--drivers/video/fbcon-iplan2p4.h15
-rw-r--r--drivers/video/fbcon-iplan2p8.c315
-rw-r--r--drivers/video/fbcon-iplan2p8.h15
-rw-r--r--drivers/video/fbcon-mac.c513
-rw-r--r--drivers/video/fbcon-mac.h15
-rw-r--r--drivers/video/fbcon-mfb.c107
-rw-r--r--drivers/video/fbcon-mfb.h15
-rw-r--r--drivers/video/fbcon-retz3.c260
-rw-r--r--drivers/video/fbcon.c571
-rw-r--r--drivers/video/fbcon.h19
-rw-r--r--drivers/video/fbgen.c386
-rw-r--r--drivers/video/font_6x11.c3345
-rw-r--r--drivers/video/fonts.c31
-rw-r--r--drivers/video/macfb.c459
-rw-r--r--drivers/video/offb.c612
-rw-r--r--drivers/video/retz3fb.c567
-rw-r--r--drivers/video/skeletonfb.c388
-rw-r--r--drivers/video/tgafb.c201
-rw-r--r--drivers/video/txtcon.c117
-rw-r--r--drivers/video/vfb.c234
-rw-r--r--drivers/video/vgacon.c116
-rw-r--r--drivers/video/virgefb.c1190
105 files changed, 25893 insertions, 7198 deletions
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 60bcb042d..4cdcc28a3 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -45,11 +45,16 @@
* major/minor handling that came with kdev_t. It seems to work for
* the time being, but I can't guarantee that it will stay like
* that when we start using 16 (24?) bit minors.
+ *
+ * restructured jan 1997 by Joerg Dorchain
+ * - Fixed Bug accessing multiple disks
+ * - some code cleanup
+ * - added trackbuffer for each drive to speed things up
+ * - fixed some race conditions (who finds the next may send it to me ;-)
*/
-#ifdef MODULE
#include <linux/module.h>
-#endif
+
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
@@ -61,7 +66,7 @@
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/string.h>
-#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <asm/setup.h>
@@ -82,20 +87,9 @@
#define IOCTL_RAW_TRACK 0x5254524B /* 'RTRK' */
#endif
-/* prototypes */
-
-static int amiga_read(int,unsigned char *, unsigned long, int);
-static void amiga_write(int, unsigned long, unsigned char *, int);
-static int dos_read(int, unsigned char *, unsigned long, int);
-static void dos_write(int, unsigned long, unsigned char *,int);
-static ushort dos_crc(void *, int, int, int);
-static void fd_probe(int);
-
-
/*
* Defines
*/
-#define MAX_SECTORS 22
/*
* Error codes
@@ -107,6 +101,11 @@ static void fd_probe(int);
#define FD_NOTACTIVE 3 /* unit is not active */
#define FD_NOTREADY 4 /* unit is not ready (motor not on/no disk) */
+#define MFM_NOSYNC 1
+#define MFM_HEADER 2
+#define MFM_DATA 3
+#define MFM_TRACK 4
+
/*
* Floppy ID values
*/
@@ -115,8 +114,9 @@ static void fd_probe(int);
#define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */
#define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */
-static int fd_def_df0 = 0; /* default for df0 if it doesn't identify */
+static long int fd_def_df0 = 0; /* default for df0 if it doesn't identify */
+MODULE_PARM(fd_def_df0,"l");
/*
* Macros
@@ -147,26 +147,34 @@ static int floppy_sizes[256]={880,880,880,880,720,720,720,720,};
static int floppy_blocksizes[256]={0,};
/* hardsector size assumed to be 512 */
+static int amiga_read(int), dos_read(int);
+static void amiga_write(int), dos_write(int);
static struct fd_data_type data_types[] = {
{ "Amiga", 11 , amiga_read, amiga_write},
{ "MS-Dos", 9, dos_read, dos_write}
};
/* current info on each unit */
-static struct amiga_floppy_struct unit[FD_MAX_UNITS];
+static struct amiga_floppy_struct unit[FD_MAX_UNITS] = {{ 0,}};
-static struct timer_list flush_track_timer;
+static struct timer_list flush_track_timer[FD_MAX_UNITS];
static struct timer_list post_write_timer;
static struct timer_list motor_on_timer;
static struct timer_list motor_off_timer[FD_MAX_UNITS];
static int on_attempts;
-/* track buffer */
-static int lastdrive = -1;
-static int savedtrack = -1;
+/* Synchronization of FDC access */
+/* request loop (trackbuffer) */
+static volatile int fdc_busy = -1;
+static volatile int fdc_nested = 0;
+static struct wait_queue *fdc_wait = NULL;
+
+static struct wait_queue *motor_wait = NULL;
+
+static volatile int selected = -1; /* currently selected drive */
+
static int writepending = 0;
static int writefromint = 0;
-static unsigned char trackdata[MAX_SECTORS * 512];
static char *raw_buf;
#define RAW_BUF_SIZE 30000 /* size of raw disk data */
@@ -177,21 +185,8 @@ static char *raw_buf;
* request.
*/
static volatile char block_flag = 0;
-static volatile int selected = 0;
static struct wait_queue *wait_fd_block = NULL;
-/* Synchronization of FDC access */
-/* request loop (trackbuffer) */
-static volatile int fdc_busy = -1;
-static volatile int fdc_nested = 0;
-static struct wait_queue *fdc_wait = NULL;
-/* hardware */
-static volatile int hw_busy = -1;
-static volatile int hw_nested = 0;
-static struct wait_queue *hw_wait = NULL;
-
-static struct wait_queue *motor_wait = NULL;
-
/* MS-Dos MFM Coding tables (should go quick and easy) */
static unsigned char mfmencode[16]={
0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
@@ -211,13 +206,6 @@ static struct wait_queue *ms_wait = NULL;
*/
#define MAX_ERRORS 12
-/*
- * The driver is trying to determine the correct media format
- * while probing is set. rw_interrupt() clears it after a
- * successful access.
- */
-static int probing = 0;
-
/* Prevent "aliased" accesses. */
static int fd_ref[4] = { 0,0,0,0 };
static int fd_device[4] = { 0,0,0,0 };
@@ -231,61 +219,15 @@ static int fd_device[4] = { 0,0,0,0 };
/* Current error count. */
#define CURRENT_ERRORS (CURRENT->errors)
-static void get_fdc(int drive)
-{
-unsigned long flags;
-
- drive &= 3;
- save_flags(flags);
- cli();
- if (fdc_busy != drive)
- while (!(fdc_busy < 0))
- sleep_on(&fdc_wait);
- fdc_busy = drive;
- fdc_nested++;
- restore_flags(flags);
-}
-
-static inline void rel_fdc(void)
-{
-#ifdef DEBUG
- if (fdc_nested == 0)
- printk("fd: unmatched rel_fdc\n");
-#endif
- fdc_nested--;
- if (fdc_nested == 0) {
- fdc_busy = -1;
- wake_up(&fdc_wait);
- }
-}
-static void get_hw(int drive)
-{
-unsigned long flags;
- drive &= 3;
- save_flags(flags);
- cli();
- if (hw_busy != drive)
- while (!(hw_busy < 0))
- sleep_on(&hw_wait);
- hw_busy = drive;
- hw_nested++;
- restore_flags(flags);
-}
+/*
+ * Here come the actual hardware access and helper functions.
+ * They are not reentrant and single threaded because all drives
+ * share the same hardware and the same trackbuffer.
+ */
-static inline void rel_hw(void)
-{
-#ifdef DEBUG
- if (hw_nested == 0)
- printk("fd: unmatched hw_rel\n");
-#endif
- hw_nested--;
- if (hw_nested == 0) {
- hw_busy = -1;
- wake_up(&hw_wait);
- }
-}
+/* Milliseconds timer */
static void ms_isr(int irq, void *dummy, struct pt_regs *fp)
{
@@ -314,53 +256,102 @@ static void ms_delay(int ms)
}
}
-/*
- * Functions
- */
-/*======================================================================
- Turn off the motor of the given drive. Unit must already be active.
- Returns standard floppy error code.
-======================================================================*/
-static void fd_motor_off(unsigned long drive)
+/* Hardware semaphore */
+
+/* returns true when we would get the semaphore */
+static inline int try_fdc(int drive)
+{
+ drive &= 3;
+ return ((fdc_busy < 0) || (fdc_busy == drive));
+}
+
+static void get_fdc(int drive)
+{
+unsigned long flags;
+
+ drive &= 3;
+#ifdef DEBUG
+ printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested);
+#endif
+ save_flags(flags);
+ cli();
+ while (!try_fdc(drive))
+ sleep_on(&fdc_wait);
+ fdc_busy = drive;
+ fdc_nested++;
+ restore_flags(flags);
+}
+
+static inline void rel_fdc(void)
+{
+#ifdef DEBUG
+ if (fdc_nested == 0)
+ printk("fd: unmatched rel_fdc\n");
+ printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);
+#endif
+ fdc_nested--;
+ if (fdc_nested == 0) {
+ fdc_busy = -1;
+ wake_up(&fdc_wait);
+ }
+}
+
+static void fd_select (int drive)
{
- unsigned long flags;
unsigned char prb = ~0;
drive&=3;
- get_hw(drive);
- save_flags(flags);
- cli();
+#ifdef DEBUG
+ printk("selecting %d\n",drive);
+#endif
+ if (drive == selected)
+ return;
+ get_fdc(drive);
+ selected = drive;
if (unit[drive].track % 2 != 0)
prb &= ~DSKSIDE;
+ if (unit[drive].motor == 1)
+ prb &= ~DSKMOTOR;
ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
ciab.prb = prb;
prb &= ~SELMASK(drive);
ciab.prb = prb;
- udelay (1);
+ rel_fdc();
+}
+
+static void fd_deselect (int drive)
+{
+ unsigned char prb;
+ unsigned long flags;
+
+ drive&=3;
+#ifdef DEBUG
+ printk("deselecting %d\n",drive);
+#endif
+ if (drive != selected) {
+ printk(KERN_WARNING "Deselecting drive %d while %d was selected!\n",drive,selected);
+ return;
+ }
+
+ get_fdc(drive);
+ save_flags (flags);
+ sti();
+
+ selected = -1;
+
+ prb = ciab.prb;
prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
ciab.prb = prb;
- selected = -1;
- unit[drive].motor = 0;
- rel_hw();
-#ifdef MODULE
-/*
-this is the last interrupt for any drive access, happens after
-release. So we have to wait until now to decrease the use count.
-*/
- if (fd_ref[drive] == 0)
- MOD_DEC_USE_COUNT;
-#endif
- restore_flags(flags);
+ restore_flags (flags);
+ rel_fdc();
+
}
static void motor_on_callback(unsigned long nr)
{
- nr &= 3;
-
if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
- unit[nr].motor = 1;
wake_up (&motor_wait);
} else {
motor_on_timer.expires = jiffies + HZ/10;
@@ -368,39 +359,25 @@ static void motor_on_callback(unsigned long nr)
}
}
-static int motor_on(int nr)
+static int fd_motor_on(int nr)
{
- unsigned long flags;
- unsigned char prb = ~0;
-
nr &= 3;
- get_hw(nr);
- save_flags (flags);
- cli();
+
del_timer(motor_off_timer + nr);
if (!unit[nr].motor) {
+ unit[nr].motor = 1;
+ fd_select(nr);
+
del_timer(&motor_on_timer);
motor_on_timer.data = nr;
motor_on_timer.expires = jiffies + HZ/2;
add_timer(&motor_on_timer);
- on_attempts = 10;
-
- prb &= ~DSKMOTOR;
- if (unit[nr].track % 2 != 0)
- prb &= ~DSKSIDE;
- ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
- ciab.prb = prb;
- prb &= ~SELMASK(nr);
- ciab.prb = prb;
- selected = nr;
-
- while (!unit[nr].motor)
- sleep_on (&motor_wait);
+ on_attempts = 10;
+ sleep_on (&motor_wait);
+ fd_deselect(nr);
}
- rel_hw();
- restore_flags(flags);
if (on_attempts == 0) {
on_attempts = -1;
@@ -416,72 +393,58 @@ static int motor_on(int nr)
return 1;
}
-static void floppy_off (unsigned int nr)
-{
- nr&=3;
- del_timer(motor_off_timer+nr);
- motor_off_timer[nr].expires = jiffies + 3*HZ;
- add_timer(motor_off_timer+nr);
-}
-
-static void fd_select (int drive)
+static void fd_motor_off(unsigned long drive)
{
- unsigned char prb = ~0;
+long calledfromint;
+#ifdef MODULE
+long decusecount;
+ decusecount = drive & 0x40000000;
+#endif
+ calledfromint = drive & 0x80000000;
drive&=3;
- if (drive == selected)
+ if (calledfromint && !try_fdc(drive)) {
+ /* We would be blocked in an interrupt, so try again later */
+ motor_off_timer[drive].expires = jiffies + 1;
+ add_timer(motor_off_timer + drive);
return;
- get_hw(drive);
- selected = drive;
+ }
+ unit[drive].motor = 0;
+ fd_select(drive);
+ udelay (1);
+ fd_deselect(drive);
- if (unit[drive].track % 2 != 0)
- prb &= ~DSKSIDE;
- if (unit[drive].motor == 1)
- prb &= ~DSKMOTOR;
- ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
- ciab.prb = prb;
- prb &= ~SELMASK(drive);
- ciab.prb = prb;
- rel_hw();
+#ifdef MODULE
+/*
+this is the last interrupt for any drive access, happens after
+release (from floppy_off). So we have to wait until now to decrease
+the use count.
+*/
+ if (decusecount)
+ MOD_DEC_USE_COUNT;
+#endif
}
-static void fd_deselect (int drive)
+static void floppy_off (unsigned int nr)
{
- unsigned char prb;
- unsigned long flags;
-
- drive&=3;
- if (drive != selected)
- return;
-
- get_hw(drive);
- save_flags (flags);
- sti();
-
- selected = -1;
-
- prb = ciab.prb;
- prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
- ciab.prb = prb;
-
- restore_flags (flags);
- rel_hw();
-
+int drive;
+
+ drive = nr & 3;
+ del_timer(motor_off_timer + drive);
+ motor_off_timer[drive].expires = jiffies + 3*HZ;
+ /* called this way it is always from interrupt */
+ motor_off_timer[drive].data = nr | 0x80000000;
+ add_timer(motor_off_timer + nr);
}
-/*======================================================================
- Seek the drive to track 0.
- The drive must be active and the motor must be running.
- Returns standard floppy error code.
-======================================================================*/
static int fd_calibrate(int drive)
{
unsigned char prb;
int n;
drive &= 3;
- get_hw(drive);
- if (!motor_on (drive))
+ get_fdc(drive);
+ if (!fd_motor_on (drive))
return 0;
fd_select (drive);
prb = ciab.prb;
@@ -511,46 +474,45 @@ static int fd_calibrate(int drive)
if ((ciaa.pra & DSKTRACK0) == 0)
break;
if (--n == 0) {
- printk (KERN_ERR "calibrate failed, turning motor off\n");
+ printk (KERN_ERR "fd%d: calibrate failed, turning motor off\n", drive);
fd_motor_off (drive);
unit[drive].track = -1;
- rel_hw();
+ rel_fdc();
return 0;
}
}
unit[drive].track = 0;
ms_delay(unit[drive].type->settle_time);
- rel_hw();
+ rel_fdc();
+ fd_deselect(drive);
return 1;
}
-/*======================================================================
- Seek the drive to the requested cylinder.
- The drive must have been calibrated at some point before this.
- The drive must also be active and the motor must be running.
-======================================================================*/
static int fd_seek(int drive, int track)
{
unsigned char prb;
int cnt;
+#ifdef DEBUG
+ printk("seeking drive %d to track %d\n",drive,track);
+#endif
drive &= 3;
- get_hw(drive);
+ get_fdc(drive);
if (unit[drive].track == track) {
- rel_hw();
+ rel_fdc();
return 1;
}
- if (!motor_on(drive)) {
- rel_hw();
+ if (!fd_motor_on(drive)) {
+ rel_fdc();
return 0;
}
- fd_select (drive);
if (unit[drive].track < 0 && !fd_calibrate(drive)) {
- rel_hw();
+ rel_fdc();
return 0;
}
+ fd_select (drive);
cnt = unit[drive].track/2 - track/2;
prb = ciab.prb;
prb |= DSKSIDE | DSKDIREC;
@@ -565,7 +527,8 @@ static int fd_seek(int drive, int track)
ms_delay (unit[drive].type->side_time);
unit[drive].track = track;
if (cnt == 0) {
- rel_hw();
+ rel_fdc();
+ fd_deselect(drive);
return 1;
}
do {
@@ -578,119 +541,189 @@ static int fd_seek(int drive, int track)
} while (--cnt != 0);
ms_delay (unit[drive].type->settle_time);
- rel_hw();
+ rel_fdc();
+ fd_deselect(drive);
return 1;
}
-static void encode(unsigned long data, unsigned long *dest)
+static unsigned long fd_get_drive_id(int drive)
{
- unsigned long data2;
+ int i;
+ ulong id = 0;
- data &= 0x55555555;
- data2 = data ^ 0x55555555;
- data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
+ drive&=3;
+ get_fdc(drive);
+ /* set up for ID */
+ MOTOR_ON;
+ udelay(2);
+ SELECT(SELMASK(drive));
+ udelay(2);
+ DESELECT(SELMASK(drive));
+ udelay(2);
+ MOTOR_OFF;
+ udelay(2);
+ SELECT(SELMASK(drive));
+ udelay(2);
+ DESELECT(SELMASK(drive));
+ udelay(2);
- if (*(dest - 1) & 0x00000001)
- data &= 0x7FFFFFFF;
+ /* loop and read disk ID */
+ for (i=0; i<32; i++) {
+ SELECT(SELMASK(drive));
+ udelay(2);
- *dest = data;
+ /* read and store value of DSKRDY */
+ id <<= 1;
+ id |= (ciaa.pra & DSKRDY) ? 0 : 1; /* cia regs are low-active! */
+
+ DESELECT(SELMASK(drive));
+ }
+
+ rel_fdc();
+
+ /*
+ * RB: At least A500/A2000's df0: don't identify themselves.
+ * As every (real) Amiga has at least a 3.5" DD drive as df0:
+ * we default to that if df0: doesn't identify as a certain
+ * type.
+ */
+ if(drive == 0 && id == FD_NODRIVE)
+ {
+ id = fd_def_df0;
+ printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0);
+ }
+ /* return the ID value */
+ return (id);
}
-static void encode_block(unsigned long *dest, unsigned long *src, int len)
+static void fd_block_done(int irq, void *dummy, struct pt_regs *fp)
{
- int cnt, to_cnt = 0;
- unsigned long data;
+ if (block_flag)
+ custom.dsklen = 0x4000;
- /* odd bits */
- for (cnt = 0; cnt < len / 4; cnt++) {
- data = src[cnt] >> 1;
- encode(data, dest + to_cnt++);
+ if (block_flag == 2) { /* writing */
+ writepending = 2;
+ post_write_timer.expires = jiffies + 1; /* at least 2 ms */
+ post_write_timer.data = selected;
+ add_timer(&post_write_timer);
}
-
- /* even bits */
- for (cnt = 0; cnt < len / 4; cnt++) {
- data = src[cnt];
- encode(data, dest + to_cnt++);
+ else { /* reading */
+ block_flag = 0;
+ wake_up (&wait_fd_block);
}
}
-unsigned long checksum(unsigned long *addr, int len)
+static void raw_read(int drive)
{
- unsigned long csum = 0;
+ drive&=3;
+ get_fdc(drive);
+ while (block_flag)
+ sleep_on(&wait_fd_block);
+ fd_select(drive);
+ /* setup adkcon bits correctly */
+ custom.adkcon = ADK_MSBSYNC;
+ custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST;
- len /= sizeof(*addr);
- while (len-- > 0)
- csum ^= *addr++;
- csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555);
+ custom.dsksync = MFM_SYNC;
- return csum;
-}
+ custom.dsklen = 0;
+ custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
+ custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
+ custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
-struct header {
- unsigned char magic;
- unsigned char track;
- unsigned char sect;
- unsigned char ord;
- unsigned char labels[16];
- unsigned long hdrchk;
- unsigned long datachk;
-};
+ block_flag = 1;
-static unsigned long *putsec(int disk, unsigned long *raw, int track, int cnt,
- unsigned char *data)
+ while (block_flag)
+ sleep_on (&wait_fd_block);
+
+ custom.dsklen = 0;
+ fd_deselect(drive);
+ rel_fdc();
+}
+
+static int raw_write(int drive)
{
- struct header hdr;
- int i;
+ ushort adk;
- disk&=3;
- *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA;
- raw++;
- *raw++ = 0x44894489;
+ drive&=3;
+ get_fdc(drive); /* corresponds to rel_fdc() in post_write() */
+ if ((ciaa.pra & DSKPROT) == 0) {
+ rel_fdc();
+ return 0;
+ }
+ while (block_flag)
+ sleep_on(&wait_fd_block);
+ fd_select(drive);
+ /* clear adkcon bits */
+ custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
+ /* set appropriate adkcon bits */
+ adk = ADK_SETCLR|ADK_FAST;
+ if ((ulong)unit[drive].track >= unit[drive].type->precomp2)
+ adk |= ADK_PRECOMP1;
+ else if ((ulong)unit[drive].track >= unit[drive].type->precomp1)
+ adk |= ADK_PRECOMP0;
+ custom.adkcon = adk;
- hdr.magic = 0xFF;
- hdr.track = track;
- hdr.sect = cnt;
- hdr.ord = unit[disk].sects-cnt;
- for (i = 0; i < 16; i++)
- hdr.labels[i] = 0;
- hdr.hdrchk = checksum((ulong *)&hdr,
- (char *)&hdr.hdrchk-(char *)&hdr);
- hdr.datachk = checksum((ulong *)data, 512);
+ custom.dsklen = DSKLEN_WRITE;
+ custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
+ custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
+ custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
- encode_block(raw, (ulong *)&hdr.magic, 4);
- raw += 2;
- encode_block(raw, (ulong *)&hdr.labels, 16);
- raw += 8;
- encode_block(raw, (ulong *)&hdr.hdrchk, 4);
- raw += 2;
- encode_block(raw, (ulong *)&hdr.datachk, 4);
- raw += 2;
- encode_block(raw, (ulong *)data, 512);
- raw += 256;
+ block_flag = 2;
+ return 1;
+}
- return raw;
+/*
+ * to be called at least 2ms after the write has finished but before any
+ * other access to the hardware.
+ */
+static void post_write (unsigned long drive)
+{
+#ifdef DEBUG
+ printk("post_write for drive %ld\n",drive);
+#endif
+ drive &= 3;
+ custom.dsklen = 0;
+ block_flag = 0;
+ writepending = 0;
+ writefromint = 0;
+ unit[drive].dirty = 0;
+ wake_up(&wait_fd_block);
+ fd_deselect(drive);
+ rel_fdc(); /* corresponds to get_fdc() in raw_write */
}
-/*==========================================================================
- amiga_write converts track/labels data to raw track data
-==========================================================================*/
-static void amiga_write(int disk, unsigned long raw, unsigned char *data,
- int track)
+/*
+ * The following functions are to convert the block contents into raw data
+ * written to disk and vice versa.
+ * (Add other formats here ;-))
+ */
+
+static unsigned long scan_sync(unsigned long raw, unsigned long end)
{
- unsigned int cnt;
- unsigned long *ptr = (unsigned long *)raw;
+ ushort *ptr = (ushort *)raw, *endp = (ushort *)end;
- disk&=3;
- /* gap space */
- for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++)
- *ptr++ = 0xaaaaaaaa;
+ while (ptr < endp && *ptr++ != 0x4489)
+ ;
+ if (ptr < endp) {
+ while (*ptr == 0x4489 && ptr < endp)
+ ptr++;
+ return (ulong)ptr;
+ }
+ return 0;
+}
- /* sectors */
- for (cnt = 0; cnt < unit[disk].sects; cnt++)
- ptr = putsec (disk, ptr, track, cnt, data + cnt*512);
- *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;
- raw = (unsigned long)ptr + 2;
+static inline unsigned long checksum(unsigned long *addr, int len)
+{
+ unsigned long csum = 0;
+
+ len /= sizeof(*addr);
+ while (len-- > 0)
+ csum ^= *addr++;
+ csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555);
+
+ return csum;
}
static unsigned long decode (unsigned long *data, unsigned long *raw,
@@ -713,45 +746,29 @@ static unsigned long decode (unsigned long *data, unsigned long *raw,
return (ulong)raw;
}
-#define MFM_NOSYNC 1
-#define MFM_HEADER 2
-#define MFM_DATA 3
-#define MFM_TRACK 4
-
-/*==========================================================================
- scan_sync - looks for the next start of sector marked by a sync. d3 is the
- sector number (10..0). When d3 = 10, can't be certain of a
- starting sync.
-==========================================================================*/
-static unsigned long scan_sync(unsigned long raw, unsigned long end)
-{
- ushort *ptr = (ushort *)raw, *endp = (ushort *)end;
-
- while (ptr < endp && *ptr++ != 0x4489)
- ;
- if (ptr < endp) {
- while (*ptr == 0x4489 && ptr < endp)
- ptr++;
- return (ulong)ptr;
- }
- return 0;
-}
+struct header {
+ unsigned char magic;
+ unsigned char track;
+ unsigned char sect;
+ unsigned char ord;
+ unsigned char labels[16];
+ unsigned long hdrchk;
+ unsigned long datachk;
+};
-/*==========================================================================
- amiga_read reads a raw track of data into a track buffer
-==========================================================================*/
-static int amiga_read(int drive, unsigned char *track_data,
- unsigned long raw, int track)
+static int amiga_read(int drive)
{
+ unsigned long raw;
unsigned long end;
int scnt;
unsigned long csum;
struct header hdr;
drive&=3;
+ raw = (long) raw_buf;
end = raw + unit[drive].type->read_size;
- for (scnt = 0;scnt < unit[drive].sects; scnt++) {
+ for (scnt = 0;scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
if (!(raw = scan_sync(raw, end))) {
printk (KERN_INFO "can't find sync for sector %d\n", scnt);
return MFM_NOSYNC;
@@ -778,24 +795,24 @@ static int amiga_read(int drive, unsigned char *track_data,
}
/* verify track */
- if (hdr.track != track) {
- printk(KERN_INFO "MFM_TRACK: %d, %d\n", hdr.track, track);
+ if (hdr.track != unit[drive].track) {
+ printk(KERN_INFO "MFM_TRACK: %d, %d\n", hdr.track, unit[drive].track);
return MFM_TRACK;
}
- raw = decode ((ulong *)(track_data + hdr.sect*512),
+ raw = decode ((ulong *)(unit[drive].trackbuf + hdr.sect*512),
(ulong *)raw, 512);
- csum = checksum((ulong *)(track_data + hdr.sect*512), 512);
+ csum = checksum((ulong *)(unit[drive].trackbuf + hdr.sect*512), 512);
if (hdr.datachk != csum) {
printk(KERN_INFO "MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n",
hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt,
hdr.datachk, csum);
printk (KERN_INFO "data=(%lx,%lx,%lx,%lx)\n",
- ((ulong *)(track_data+hdr.sect*512))[0],
- ((ulong *)(track_data+hdr.sect*512))[1],
- ((ulong *)(track_data+hdr.sect*512))[2],
- ((ulong *)(track_data+hdr.sect*512))[3]);
+ ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[0],
+ ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[1],
+ ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[2],
+ ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[3]);
return MFM_DATA;
}
}
@@ -803,6 +820,89 @@ static int amiga_read(int drive, unsigned char *track_data,
return 0;
}
+static void encode(unsigned long data, unsigned long *dest)
+{
+ unsigned long data2;
+
+ data &= 0x55555555;
+ data2 = data ^ 0x55555555;
+ data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
+
+ if (*(dest - 1) & 0x00000001)
+ data &= 0x7FFFFFFF;
+
+ *dest = data;
+}
+
+static void encode_block(unsigned long *dest, unsigned long *src, int len)
+{
+ int cnt, to_cnt = 0;
+ unsigned long data;
+
+ /* odd bits */
+ for (cnt = 0; cnt < len / 4; cnt++) {
+ data = src[cnt] >> 1;
+ encode(data, dest + to_cnt++);
+ }
+
+ /* even bits */
+ for (cnt = 0; cnt < len / 4; cnt++) {
+ data = src[cnt];
+ encode(data, dest + to_cnt++);
+ }
+}
+
+static unsigned long *putsec(int disk, unsigned long *raw, int cnt)
+{
+ struct header hdr;
+ int i;
+
+ disk&=3;
+ *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA;
+ raw++;
+ *raw++ = 0x44894489;
+
+ hdr.magic = 0xFF;
+ hdr.track = unit[disk].track;
+ hdr.sect = cnt;
+ hdr.ord = unit[disk].dtype->sects * unit[disk].type->sect_mult - cnt;
+ for (i = 0; i < 16; i++)
+ hdr.labels[i] = 0;
+ hdr.hdrchk = checksum((ulong *)&hdr,
+ (char *)&hdr.hdrchk-(char *)&hdr);
+ hdr.datachk = checksum((ulong *)(unit[disk].trackbuf+cnt*512), 512);
+
+ encode_block(raw, (ulong *)&hdr.magic, 4);
+ raw += 2;
+ encode_block(raw, (ulong *)&hdr.labels, 16);
+ raw += 8;
+ encode_block(raw, (ulong *)&hdr.hdrchk, 4);
+ raw += 2;
+ encode_block(raw, (ulong *)&hdr.datachk, 4);
+ raw += 2;
+ encode_block(raw, (ulong *)(unit[disk].trackbuf+cnt*512), 512);
+ raw += 256;
+
+ return raw;
+}
+
+static void amiga_write(int disk)
+{
+ unsigned int cnt;
+ unsigned long *ptr = (unsigned long *)raw_buf;
+
+ disk&=3;
+ /* gap space */
+ for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++)
+ *ptr++ = 0xaaaaaaaa;
+
+ /* sectors */
+ for (cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
+ ptr = putsec (disk, ptr, cnt);
+ *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;
+}
+
+
struct dos_header {
unsigned char track, /* 0-80 */
side, /* 0-1 */
@@ -811,22 +911,12 @@ unsigned char track, /* 0-80 */
unsigned short crc; /* on 68000 we got an alignment problem,
but this compiler solves it by adding silently
adding a pad byte so data won't fit
- and this cost about 3h to discover.... */
+ and this took about 3h to discover.... */
unsigned char gap1[22]; /* for longword-alignedness (0x4e) */
};
/* crc routines are borrowed from the messydos-handler */
-static inline ushort dos_hdr_crc (struct dos_header *hdr)
-{
-return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
-}
-
-static inline ushort dos_data_crc(unsigned char *data)
-{
-return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
-}
-
/* excerpt from the messydos-device
; The CRC is computed not only over the actual data, but including
; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
@@ -937,6 +1027,16 @@ for (i=data_d3; i>=0; i--) {
return (crch<<8)|crcl;
}
+static inline ushort dos_hdr_crc (struct dos_header *hdr)
+{
+return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
+}
+
+static inline ushort dos_data_crc(unsigned char *data)
+{
+return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
+}
+
static inline unsigned char dos_decode_byte(ushort word)
{
register ushort w2;
@@ -965,30 +1065,28 @@ return ((ulong)raw);
#ifdef DEBUG
static void dbg(unsigned long ptr)
{
-printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr,
- ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]);
+ printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr,
+ ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]);
}
#endif
-/*******************************************************************
- this reads a raw track of data into trackbuffer for ms-disks
-*******************************************************************/
-static int dos_read(int drive, unsigned char *track_data,
- unsigned long raw, int track)
+static int dos_read(int drive)
{
unsigned long end;
+ unsigned long raw;
int scnt;
unsigned short crc,data_crc[2];
struct dos_header hdr;
drive&=3;
+ raw = (long) raw_buf;
end = raw + unit[drive].type->read_size;
- for (scnt=0;scnt<unit[drive].sects;scnt++) {
+ for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
do { /* search for the right sync of each sec-hdr */
if (!(raw = scan_sync (raw, end))) {
printk(KERN_INFO "dos_read: no hdr sync on track %d, unit %d for sector %d\n",
- track,drive,scnt);
+ unit[drive].track,drive,scnt);
return MFM_NOSYNC;
}
#ifdef DEBUG
@@ -1008,15 +1106,15 @@ static int dos_read(int drive, unsigned char *track_data,
printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", hdr.crc, crc);
return MFM_HEADER;
}
- if (hdr.track != track/unit[drive].type->heads) {
+ if (hdr.track != unit[drive].track/unit[drive].type->heads) {
printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", hdr.track,
- track/unit[drive].type->heads);
+ unit[drive].track/unit[drive].type->heads);
return MFM_TRACK;
}
- if (hdr.side != track%unit[drive].type->heads) {
+ if (hdr.side != unit[drive].track%unit[drive].type->heads) {
printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", hdr.side,
- track%unit[drive].type->heads);
+ unit[drive].track%unit[drive].type->heads);
return MFM_TRACK;
}
@@ -1029,7 +1127,7 @@ static int dos_read(int drive, unsigned char *track_data,
#endif
if (!(raw = scan_sync (raw, end))) {
printk(KERN_INFO "dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n",
- track, drive, scnt, hdr.sec);
+ unit[drive].track, drive, scnt, hdr.sec);
return MFM_NOSYNC;
}
#ifdef DEBUG
@@ -1043,19 +1141,19 @@ static int dos_read(int drive, unsigned char *track_data,
}
raw+=2; /* skip data mark (included in checksum) */
- raw = dos_decode((unsigned char *)(track_data + (hdr.sec - 1) * 512), (ushort *) raw, 512);
+ raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512);
raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4);
- crc = dos_data_crc(track_data + (hdr.sec - 1) * 512);
+ crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512);
if (crc != data_crc[0]) {
printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n",
hdr.track, hdr.side, hdr.sec, hdr.len_desc,
scnt,data_crc[0], crc);
printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n",
- ((ulong *)(track_data+(hdr.sec-1)*512))[0],
- ((ulong *)(track_data+(hdr.sec-1)*512))[1],
- ((ulong *)(track_data+(hdr.sec-1)*512))[2],
- ((ulong *)(track_data+(hdr.sec-1)*512))[3]);
+ ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0],
+ ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1],
+ ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2],
+ ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]);
return MFM_DATA;
}
}
@@ -1086,8 +1184,7 @@ for (i = 0; i < len; i++) {
}
}
-static unsigned long *ms_putsec(int drive, unsigned long *raw, int track, int cnt,
- unsigned char *data)
+static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt)
{
static struct dos_header hdr={0,0,0,2,0,
{78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
@@ -1104,8 +1201,8 @@ for(i=0;i<6;i++)
*raw++=0x44895554;
/* fill in the variable parts of the header */
-hdr.track=track/unit[drive].type->heads;
-hdr.side=track%unit[drive].type->heads;
+hdr.track=unit[drive].track/unit[drive].type->heads;
+hdr.side=unit[drive].track%unit[drive].type->heads;
hdr.sec=cnt+1;
hdr.crc=dos_hdr_crc(&hdr);
@@ -1122,11 +1219,11 @@ for(i=0;i<6;i++)
*raw++=0x44895545;
/* data */
-dos_encode_block((ushort *)raw,(unsigned char *)data,512);
+dos_encode_block((ushort *)raw,(unsigned char *)unit[drive].trackbuf+cnt*512,512);
raw+=256;
/*data crc + jd's special gap (long words :-/) */
-crc[0]=dos_data_crc(data);
+crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512);
dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
raw+=2;
@@ -1137,14 +1234,10 @@ for(i=0;i<38;i++)
return raw; /* wrote 652 MFM words */
}
-
-/**************************************************************
- builds encoded track data from trackbuffer data
-**************************************************************/
-static void dos_write(int disk, unsigned long raw, unsigned char *data,
- int track)
+static void dos_write(int disk)
{
int cnt;
+unsigned long raw = (unsigned long) raw_buf;
unsigned long *ptr=(unsigned long *)raw;
disk&=3;
@@ -1168,183 +1261,40 @@ for (cnt=0;cnt<20;cnt++)
*ptr++=0x92549254;
/* sectors */
-for(cnt=0;cnt<unit[disk].sects;cnt++)
- ptr=ms_putsec(disk,ptr,track,cnt,data+cnt*512);
+for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
+ ptr=ms_putsec(disk,ptr,cnt);
*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */
}
-static void request_done(int uptodate)
-{
- timer_active &= ~(1 << FLOPPY_TIMER);
- end_request(uptodate);
-}
-
/*
- * floppy-change is never called from an interrupt, so we can relax a bit
- * here, sleep etc. Note that floppy-on tries to set current_DOR to point
- * to the desired drive, but it will probably not survive the sleep if
- * several floppies are used at the same time: thus the loop.
+ * Here comes the high level stuff (i.e. the filesystem interface)
+ * and helper functions.
+ * Normally this should be the only part that has to be adapted to
+ * different kernel versions.
*/
-static int amiga_floppy_change(kdev_t dev)
-{
- int drive = dev & 3;
- int changed;
- static int first_time = 1;
-
- if (MAJOR(dev) != MAJOR_NR) {
- printk(KERN_CRIT "floppy_change: not a floppy\n");
- return 0;
- }
- if (first_time)
- changed = first_time--;
- else {
- get_hw(drive);
- fd_select (drive);
- changed = !(ciaa.pra & DSKCHANGE);
- fd_deselect (drive);
- rel_hw();
+/* FIXME: this assumes the drive is still spinning -
+ * which is only true if we complete writing a track within three seconds
+ */
+static void flush_track_callback(unsigned long nr)
+{
+ nr&=3;
+ writefromint = 1;
+ if (!try_fdc(nr)) {
+ /* we might block in an interrupt, so try again later */
+ flush_track_timer[nr].expires = jiffies + 1;
+ add_timer(flush_track_timer + nr);
+ return;
}
-
- if (changed) {
- fd_probe(dev);
- unit[drive].track = -1;
- selected = -1;
- savedtrack = -1;
- writepending = 0; /* if this was true before, too bad! */
+ get_fdc(nr);
+ (*unit[nr].dtype->write_fkt)(nr);
+ if (!raw_write(nr)) {
+ printk (KERN_NOTICE "floppy disk write protected\n");
writefromint = 0;
- return 1;
- }
- return 0;
-}
-
-static __inline__ void copy_buffer(void *from, void *to)
-{
- ulong *p1,*p2;
- int cnt;
-
- p1 = (ulong *)from;
- p2 = (ulong *)to;
-
- for (cnt = 0; cnt < 512/4; cnt++)
- *p2++ = *p1++;
-}
-
-static void raw_read(int drive, int track, char *ptrack, int len)
-{
- drive&=3;
- get_hw(drive);
- /* setup adkcon bits correctly */
- custom.adkcon = ADK_MSBSYNC;
- custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST;
-
- custom.dsksync = MFM_SYNC;
-
- custom.dsklen = 0;
-#if 0
- ms_delay (unit[drive].type->side_time);
-#endif
- custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack);
- custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN;
- custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN;
-
- block_flag = 1;
-
- while (block_flag == 1)
- sleep_on (&wait_fd_block);
-
- custom.dsklen = 0;
- rel_hw();
-}
-
-static int raw_write(int drive, int track, char *ptrack, int len)
-{
- ushort adk;
-
- drive&=3;
- if ((ciaa.pra & DSKPROT) == 0)
- return 0;
-
- get_hw(drive); /* corresponds to rel_hw() in post_write() */
- /* clear adkcon bits */
- custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
- /* set appropriate adkcon bits */
- adk = ADK_SETCLR|ADK_FAST;
- if ((ulong)track >= unit[drive].type->precomp2)
- adk |= ADK_PRECOMP1;
- else if ((ulong)track >= unit[drive].type->precomp1)
- adk |= ADK_PRECOMP0;
- custom.adkcon = adk;
-
- custom.dsklen = DSKLEN_WRITE;
-#if 0
- ms_delay (unit[drive].type->side_time);
-#endif
- custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack);
- custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
- custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
-
- block_flag = 2;
- return 1;
-}
-
-static void post_write (unsigned long dummy)
-{
- custom.dsklen = 0;
- writepending = 0;
- writefromint = 0;
- rel_hw(); /* corresponds to get_hw() in raw_write */
-}
-
-static int get_track(int drive, int track)
-{
- int error, errors;
-
- drive&=3;
- get_hw(drive);
- if (!motor_on(drive)) {
- rel_hw();
- return -1;
- }
- fd_select(drive);
- errors = 0;
- while (errors < MAX_ERRORS) {
- if (!fd_seek(drive, track)) {
- rel_hw();
- return -1; /* we can not calibrate - no chance */
- }
- if ((lastdrive == drive) && (savedtrack == track)) {
- rel_hw();
- return 0;
- }
- lastdrive = drive;
- raw_read(drive, track, raw_buf, unit[drive].type->read_size);
- savedtrack = -1;
- error = (*unit[drive].dtype->read_fkt)(drive, trackdata, (unsigned long)raw_buf, track);
- if (error == 0) {
- savedtrack = track;
- rel_hw();
- return 0;
- }
- if (error == MFM_TRACK)
- unit[drive].track = -1;
- errors++;
+ writepending = 0;
}
- rel_hw();
- return -1;
-}
-
-static void flush_track_callback(unsigned long nr)
-{
- nr&=3;
- writefromint = 1;
- (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack);
- if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
- printk (KERN_NOTICE "floppy disk write protected\n");
- writefromint = 0;
- writepending = 0;
- }
+ rel_fdc();
}
static int non_int_flush_track (unsigned long nr)
@@ -1354,12 +1304,18 @@ unsigned long flags;
nr&=3;
writefromint = 0;
del_timer(&post_write_timer);
+ get_fdc(nr);
+ if (!fd_motor_on(nr)) {
+ writepending = 0;
+ rel_fdc();
+ return 0;
+ }
save_flags(flags);
cli();
if (writepending != 2) {
restore_flags(flags);
- (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack);
- if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
+ (*unit[nr].dtype->write_fkt)(nr);
+ if (!raw_write(nr)) {
printk (KERN_NOTICE "floppy disk write protected in write!\n");
writepending = 0;
return 0;
@@ -1367,13 +1323,50 @@ unsigned long flags;
while (block_flag == 2)
sleep_on (&wait_fd_block);
}
- else
+ else {
restore_flags(flags);
- ms_delay(2); /* 2 ms post_write delay */
- post_write(0);
+ ms_delay(2); /* 2 ms post_write delay */
+ post_write(nr);
+ }
+ rel_fdc();
return 1;
}
+static int get_track(int drive, int track)
+{
+ int error, errcnt;
+
+ drive&=3;
+ if (unit[drive].track == track)
+ return 0;
+ get_fdc(drive);
+ if (!fd_motor_on(drive)) {
+ rel_fdc();
+ return -1;
+ }
+
+ if (unit[drive].dirty == 1) {
+ del_timer (flush_track_timer + drive);
+ non_int_flush_track (drive);
+ }
+ errcnt = 0;
+ while (errcnt < MAX_ERRORS) {
+ if (!fd_seek(drive, track))
+ return -1;
+ raw_read(drive);
+ error = (*unit[drive].dtype->read_fkt)(drive);
+ if (error == 0) {
+ rel_fdc();
+ return 0;
+ }
+ /* Read Error Handling: recalibrate and try again */
+ unit[drive].track = -1;
+ errcnt++;
+ }
+ rel_fdc();
+ return -1;
+}
+
static void redo_fd_request(void)
{
unsigned int cnt, block, track, sector;
@@ -1388,10 +1381,7 @@ static void redo_fd_request(void)
repeat:
if (!CURRENT) {
- if (fdc_busy < 0)
- printk(KERN_CRIT "FDC access conflict!");
- rel_fdc();
- CLEAR_INTR;
+ /* Nothing left to do */
return;
}
@@ -1401,74 +1391,64 @@ static void redo_fd_request(void)
if (CURRENT->bh && !buffer_locked(CURRENT->bh))
panic(DEVICE_NAME ": block not locked");
- probing = 0;
device = MINOR(CURRENT_DEVICE);
- if (device > 3) {
+ if (device < 8) {
/* manual selection */
drive = device & 3;
floppy = unit + drive;
} else {
/* Auto-detection */
- /* printk("redo_fd_request: can't handle auto detect\n");*/
- /* printk("redo_fd_request: default to normal\n");*/
+#ifdef DEBUG
+ printk("redo_fd_request: can't handle auto detect\n");
+ printk("redo_fd_request: default to normal\n");
+#endif
drive = device & 3;
floppy = unit + drive;
}
- save_flags (flags);
- cli();
- if (drive != selected && writepending) {
- del_timer (&flush_track_timer);
- restore_flags (flags);
- if (!non_int_flush_track (selected)) {
- end_request(0);
- goto repeat;
- }
- } else
- restore_flags (flags);
-
/* Here someone could investigate to be more efficient */
for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) {
#ifdef DEBUG
- printk("fd: sector %d + %d requested\n",CURRENT->sector,cnt);
+ printk("fd: sector %ld + %d requested for %s\n",CURRENT->sector,cnt,
+ (CURRENT->cmd==READ)?"read":"write");
#endif
block = CURRENT->sector + cnt;
if ((int)block > floppy->blocks) {
- request_done(0);
+ end_request(0);
goto repeat;
}
- track = block / floppy->sects;
- sector = block % floppy->sects;
+ track = block / (floppy->dtype->sects * floppy->type->sect_mult);
+ sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
data = CURRENT->buffer + 512 * cnt;
+#ifdef DEBUG
+ printk("access to track %d, sector %d, with buffer at 0x%08lx\n",
+ track, sector, data);
+#endif
- save_flags (flags);
- cli();
- if (track != savedtrack && writepending) {
- del_timer (&flush_track_timer);
- restore_flags (flags);
- if (!non_int_flush_track (selected)) {
- end_request(0);
- goto repeat;
- }
- } else
- restore_flags (flags);
+ if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
+ printk(KERN_WARNING "do_fd_request: unknown command\n");
+ end_request(0);
+ goto repeat;
+ }
+ if (get_track(drive, track) == -1) {
+ end_request(0);
+ goto repeat;
+ }
switch (CURRENT->cmd) {
case READ:
- if (get_track(drive, track) == -1) {
- end_request(0);
- goto repeat;
- }
- copy_buffer(trackdata + sector * 512, data);
+ memcpy(data, unit[drive].trackbuf + sector * 512, 512);
break;
case WRITE:
- if (get_track(drive, track) == -1) {
+ memcpy(unit[drive].trackbuf + sector * 512, data, 512);
+
+ /* keep the drive spinning while writes are scheduled */
+ if (!fd_motor_on(drive)) {
end_request(0);
goto repeat;
}
- copy_buffer(data, trackdata + sector * 512);
/*
* setup a callback to write the track buffer
* after a short (1 tick) delay.
@@ -1476,33 +1456,25 @@ static void redo_fd_request(void)
save_flags (flags);
cli();
- if (writepending)
- /* reset the timer */
- del_timer (&flush_track_timer);
+ unit[drive].dirty = 1;
+ /* reset the timer */
+ del_timer (flush_track_timer + drive);
- writepending = 1;
- flush_track_timer.data = drive;
- flush_track_timer.expires = jiffies + 1;
- add_timer (&flush_track_timer);
+ flush_track_timer[drive].expires = jiffies + 1;
+ add_timer (flush_track_timer + drive);
restore_flags (flags);
break;
-
- default:
- printk(KERN_WARNING "do_fd_request: unknown command\n");
- request_done(0);
- goto repeat;
}
}
CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
CURRENT->sector += CURRENT->current_nr_sectors;
- request_done(1);
+ end_request(1);
goto repeat;
}
static void do_fd_request(void)
{
- get_fdc(CURRENT_DEVICE & 3);
redo_fd_request();
}
@@ -1512,53 +1484,48 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
int drive = inode->i_rdev & 3;
static struct floppy_struct getprm;
struct super_block * sb;
- unsigned long flags;
switch(cmd){
case HDIO_GETGEO:
{
struct hd_geometry loc;
loc.heads = unit[drive].type->heads;
- loc.sectors = unit[drive].sects;
+ loc.sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult;
loc.cylinders = unit[drive].type->tracks;
loc.start = 0;
if (copy_to_user((void *)param, (void *)&loc,
- sizeof(struct hd_geometry)))
+ sizeof(struct hd_geometry)))
return -EFAULT;
break;
}
case FDFMTBEG:
- get_hw(drive);
+ get_fdc(drive);
if (fd_ref[drive] > 1) {
- rel_hw();
+ rel_fdc();
return -EBUSY;
}
fsync_dev(inode->i_rdev);
- if (motor_on(drive) == 0) {
- rel_hw();
+ if (fd_motor_on(drive) == 0) {
+ rel_fdc();
return -ENODEV;
}
if (fd_calibrate(drive) == 0) {
- rel_hw();
+ rel_fdc();
return -ENXIO;
}
floppy_off(drive);
- rel_hw();
+ rel_fdc();
break;
case FDFMTTRK:
if (param < unit[drive].type->tracks * unit[drive].type->heads)
{
get_fdc(drive);
- get_hw(drive);
- fd_select(drive);
- if (fd_seek(drive,param)!=0){
- savedtrack=param;
- memset(trackdata, FD_FILL_BYTE,
- unit[drive].sects*512);
+ if (fd_seek(drive,param) != 0){
+ memset(unit[drive].trackbuf, FD_FILL_BYTE,
+ unit[drive].dtype->sects * unit[drive].type->sect_mult * 512);
non_int_flush_track(drive);
}
floppy_off(drive);
- rel_hw();
rel_fdc();
}
else
@@ -1575,33 +1542,27 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
memset((void *)&getprm, 0, sizeof (getprm));
getprm.track=unit[drive].type->tracks;
getprm.head=unit[drive].type->heads;
- getprm.sect=unit[drive].sects;
+ getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult;
getprm.size=unit[drive].blocks;
if (copy_to_user((void *)param,
- (void *)&getprm,
- sizeof(struct floppy_struct)))
+ (void *)&getprm,
+ sizeof(struct floppy_struct)))
return -EFAULT;
break;
case BLKGETSIZE:
return put_user(unit[drive].blocks,(long *)param);
+ break;
case FDSETPRM:
case FDDEFPRM:
return -EINVAL;
- case FDFLUSH:
- save_flags(flags);
- cli();
- if ((drive == selected) && (writepending)) {
- del_timer (&flush_track_timer);
- restore_flags(flags);
- non_int_flush_track(selected);
- }
- else
- restore_flags(flags);
+ case FDFLUSH: /* unconditionally, even if not needed */
+ del_timer (flush_track_timer + drive);
+ non_int_flush_track(drive);
break;
#ifdef RAW_IOCTL
case IOCTL_RAW_TRACK:
if (copy_to_user((void *)param, raw_buf,
- unit[drive].type->read_size))
+ unit[drive].type->read_size))
return -EFAULT;
else
return unit[drive].type->read_size;
@@ -1613,76 +1574,16 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-/*======================================================================
- Return unit ID number of given disk
-======================================================================*/
-static unsigned long get_drive_id(int drive)
-{
- static int called = 0;
- int i;
- ulong id = 0;
-
- drive&=3;
- get_hw(drive);
- /* set up for ID */
- MOTOR_ON;
- udelay(2);
- SELECT(SELMASK(drive));
- udelay(2);
- DESELECT(SELMASK(drive));
- udelay(2);
- MOTOR_OFF;
- udelay(2);
- SELECT(SELMASK(drive));
- udelay(2);
- DESELECT(SELMASK(drive));
- udelay(2);
-
- /* loop and read disk ID */
- for (i=0; i<32; i++) {
- SELECT(SELMASK(drive));
- udelay(2);
-
- /* read and store value of DSKRDY */
- id <<= 1;
- id |= (ciaa.pra & DSKRDY) ? 0 : 1; /* cia regs are low-active! */
-
- DESELECT(SELMASK(drive));
- }
-
- selected = -1;
- rel_hw();
-
- /*
- * RB: At least A500/A2000's df0: don't identify themselves.
- * As every (real) Amiga has at least a 3.5" DD drive as df0:
- * we default to that if df0: doesn't identify as a certain
- * type.
- */
- if(drive == 0 && id == FD_NODRIVE)
- {
- id = fd_def_df0;
- printk("%sfd: drive 0 didn't identify, setting default %08lx\n",
- (called == 0)? KERN_NOTICE:"", (ulong)fd_def_df0);
- if (called == 0)
- called++;
- }
- /* return the ID value */
- return (id);
-}
-
static void fd_probe(int dev)
{
unsigned long code;
int type;
int drive;
- int system;
drive = dev & 3;
- code = get_drive_id(drive);
+ code = fd_get_drive_id(drive);
/* get drive type */
- unit[drive].type = NULL;
for (type = 0; type < num_dr_types; type++)
if (drive_types[type].code == code)
break;
@@ -1694,39 +1595,13 @@ static void fd_probe(int dev)
return;
}
- unit[drive].type = &drive_types[type];
+ unit[drive].type = drive_types + type;
unit[drive].track = -1;
unit[drive].disk = -1;
unit[drive].motor = 0;
unit[drive].busy = 0;
unit[drive].status = -1;
-
-
- system=(dev & 4)>>2;
- unit[drive].dtype=&data_types[system];
- unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult;
- unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
- unit[drive].sects;
-
- floppy_sizes[MINOR(dev)] = unit[drive].blocks >> 1;
-
-}
-
-__initfunc(static void probe_drives(void))
-{
- int drive,found;
-
- printk(KERN_INFO "FD: probing units\n" KERN_INFO "found ");
- found=0;
- for(drive=0;drive<FD_MAX_UNITS;drive++) {
- fd_probe(drive);
- if (unit[drive].type->code != FD_NODRIVE) {
- printk("fd%d ",drive);
- found=1;
- }
- }
- printk("%s\n",(found==0)?" no drives":"");
}
/*
@@ -1741,7 +1616,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
int system;
unsigned long flags;
- drive = inode->i_rdev & 3;
+ drive = MINOR(inode->i_rdev) & 3;
old_dev = fd_device[drive];
if (fd_ref[drive])
@@ -1751,17 +1626,20 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (unit[drive].type->code == FD_NODRIVE)
return -ENODEV;
- if (filp && (filp->f_flags & (O_WRONLY|O_RDWR))) {
+ if (filp && filp->f_mode & 3) {
+ check_disk_change(inode->i_rdev);
+ if (filp->f_mode & 2 ) {
int wrprot;
- get_hw(drive);
+ get_fdc(drive);
fd_select (drive);
wrprot = !(ciaa.pra & DSKPROT);
fd_deselect (drive);
- rel_hw();
+ rel_fdc();
if (wrprot)
return -EROFS;
+ }
}
save_flags(flags);
@@ -1777,55 +1655,87 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (old_dev && old_dev != inode->i_rdev)
invalidate_buffers(old_dev);
- if (filp && filp->f_mode)
- check_disk_change(inode->i_rdev);
-
system=(inode->i_rdev & 4)>>2;
unit[drive].dtype=&data_types[system];
- unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult;
unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
- unit[drive].sects;
+ data_types[system].sects*unit[drive].type->sect_mult;
+ floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1;
-printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,unit[drive].type->name,
- data_types[system].name);
+ printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
+ unit[drive].type->name, data_types[system].name);
return 0;
}
static int floppy_release(struct inode * inode, struct file * filp)
{
- unsigned long flags;
+#ifdef DEBUG
struct super_block * sb;
+#endif
+ int drive = MINOR(inode->i_rdev) & 3;
fsync_dev(inode->i_rdev);
+
+#ifdef DEBUG
+ /* This is now handled in floppy_change, but still useful for debugging */
sb = get_super(inode->i_rdev);
if (sb)
invalidate_inodes(sb);
invalidate_buffers(inode->i_rdev);
- save_flags (flags);
- cli();
- if ((inode->i_rdev & 3) == selected && writepending) {
- del_timer (&flush_track_timer);
- restore_flags (flags);
- non_int_flush_track (selected);
- } else
- restore_flags (flags);
+#endif
+
+ if (unit[drive].dirty == 1) {
+ del_timer (flush_track_timer + drive);
+ non_int_flush_track (drive);
+ }
- if (!fd_ref[inode->i_rdev & 3]--) {
+ if (!fd_ref[drive]--) {
printk(KERN_CRIT "floppy_release with fd_ref == 0");
- fd_ref[inode->i_rdev & 3] = 0;
+ fd_ref[drive] = 0;
}
#ifdef MODULE
/* the mod_use counter is handled this way */
- floppy_off (inode->i_rdev & 3);
+ floppy_off (drive | 0x40000000);
#endif
return 0;
}
-__initfunc(void amiga_floppy_setup (char *str, int *ints))
+/*
+ * floppy-change is never called from an interrupt, so we can relax a bit
+ * here, sleep etc. Note that floppy-on tries to set current_DOR to point
+ * to the desired drive, but it will probably not survive the sleep if
+ * several floppies are used at the same time: thus the loop.
+ */
+static int amiga_floppy_change(kdev_t dev)
{
- printk ("amiflop: Setting default df0 to %x\n", ints[1]);
- fd_def_df0 = ints[1];
+ int drive = MINOR(dev) & 3;
+ int changed;
+ static int first_time = 1;
+
+ if (MAJOR(dev) != MAJOR_NR) {
+ printk(KERN_CRIT "floppy_change: not a floppy\n");
+ return 0;
+ }
+
+ if (first_time)
+ changed = first_time--;
+ else {
+ get_fdc(drive);
+ fd_select (drive);
+ changed = !(ciaa.pra & DSKCHANGE);
+ fd_deselect (drive);
+ rel_fdc();
+ }
+
+ if (changed) {
+ fd_probe(drive);
+ unit[drive].track = -1;
+ unit[drive].dirty = 0;
+ writepending = 0; /* if this was true before, too bad! */
+ writefromint = 0;
+ return 1;
+ }
+ return 0;
}
static struct file_operations floppy_fops = {
@@ -1844,24 +1754,40 @@ static struct file_operations floppy_fops = {
NULL, /* revalidate */
};
-static void fd_block_done(int irq, void *dummy, struct pt_regs *fp)
+__initfunc(void amiga_floppy_setup (char *str, int *ints))
{
- if (block_flag)
- custom.dsklen = 0x4000;
-
- block_flag = 0;
- wake_up (&wait_fd_block);
+ printk (KERN_INFO "amiflop: Setting default df0 to %x\n", ints[1]);
+ fd_def_df0 = ints[1];
+}
- if (writefromint) {
- /*
- * if it was a write from an interrupt,
- * we will call post_write from here
- */
- writepending = 2;
- post_write_timer.expires = 1; /* at least 2 ms */
- add_timer(&post_write_timer);
- }
+__initfunc(static int fd_probe_drives(void))
+{
+ int drive,drives,nomem;
+ printk(KERN_INFO "FD: probing units\n" KERN_INFO "found ");
+ drives=0;
+ nomem=0;
+ for(drive=0;drive<FD_MAX_UNITS;drive++) {
+ fd_probe(drive);
+ if (unit[drive].type->code != FD_NODRIVE) {
+ drives++;
+ if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
+ printk("no mem for ");
+ unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
+ drives--;
+ nomem = 1;
+ }
+ printk("fd%d ",drive);
+ }
+ }
+ if ((drives > 0) || (nomem == 0)) {
+ if (drives == 0)
+ printk("no drives");
+ printk("\n");
+ return drives;
+ }
+ printk("\n");
+ return -ENOMEM;
}
__initfunc(int amiga_floppy_init(void))
@@ -1870,11 +1796,36 @@ __initfunc(int amiga_floppy_init(void))
if (!AMIGAHW_PRESENT(AMI_FLOPPY))
return -ENXIO;
-
if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
- printk("Unable to get major %d for floppy\n",MAJOR_NR);
+ printk("fd: Unable to get major %d for floppy\n",MAJOR_NR);
return -EBUSY;
}
+ if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) {
+ printk("fd: cannot get chip mem buffer\n");
+ unregister_blkdev(MAJOR_NR,"fd");
+ return -ENOMEM;
+ }
+
+ if (request_irq(IRQ_FLOPPY, fd_block_done, 0, "floppy_dma", NULL) != 0) {
+ printk("fd: cannot get irq for dma\n");
+ amiga_chip_free(raw_buf);
+ unregister_blkdev(MAJOR_NR,"fd");
+ return -EBUSY;
+ }
+ if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL) != 0) {
+ printk("fd: cannot get irq for timer\n");
+ free_irq(IRQ_FLOPPY, NULL);
+ amiga_chip_free(raw_buf);
+ unregister_blkdev(MAJOR_NR,"fd");
+ return -EBUSY;
+ }
+ if (fd_probe_drives() < 1) { /* No usable drives */
+ free_irq(IRQ_AMIGA_CIAA_TB, NULL);
+ free_irq(IRQ_FLOPPY, NULL);
+ amiga_chip_free(raw_buf);
+ unregister_blkdev(MAJOR_NR,"fd");
+ return -ENXIO;
+ }
/* initialize variables */
motor_on_timer.next = NULL;
@@ -1886,18 +1837,17 @@ __initfunc(int amiga_floppy_init(void))
motor_off_timer[i].next = NULL;
motor_off_timer[i].prev = NULL;
motor_off_timer[i].expires = 0;
- motor_off_timer[i].data = i;
+ motor_off_timer[i].data = i|0x80000000;
motor_off_timer[i].function = fd_motor_off;
+ flush_track_timer[i].next = NULL;
+ flush_track_timer[i].prev = NULL;
+ flush_track_timer[i].expires = 0;
+ flush_track_timer[i].data = i;
+ flush_track_timer[i].function = flush_track_callback;
unit[i].track = -1;
}
- flush_track_timer.next = NULL;
- flush_track_timer.prev = NULL;
- flush_track_timer.expires = 0;
- flush_track_timer.data = 0;
- flush_track_timer.function = flush_track_callback;
-
post_write_timer.next = NULL;
post_write_timer.prev = NULL;
post_write_timer.expires = 0;
@@ -1909,9 +1859,6 @@ __initfunc(int amiga_floppy_init(void))
blk_size[MAJOR_NR] = floppy_sizes;
- timer_table[FLOPPY_TIMER].fn = NULL;
- timer_active &= ~(1 << FLOPPY_TIMER);
-
#if 0 /* Doesn't seem to be correct */
if (fd_def_df0==0) {
if ((amiga.model == AMI_3000) || (amiga.model == AMI_3000T) ||
@@ -1925,14 +1872,10 @@ __initfunc(int amiga_floppy_init(void))
fd_def_df0 = FD_DD_3;
#endif
- probe_drives();
-
- raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE);
-
for (i = 0; i < 128; i++)
- mfmdecode[i]=255;
+ mfmdecode[i]=255;
for (i = 0; i < 16; i++)
- mfmdecode[mfmencode[i]]=i;
+ mfmdecode[mfmencode[i]]=i;
/* make sure that disk DMA is enabled */
custom.dmacon = DMAF_SETCLR | DMAF_DISK;
@@ -1940,9 +1883,7 @@ __initfunc(int amiga_floppy_init(void))
/* init ms timer */
ciaa.crb = 8; /* one-shot, stop */
- request_irq(IRQ_FLOPPY, fd_block_done, 0, "floppy_dma", NULL);
- request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL);
-
+ (void)do_floppy; /* avoid warning about unused variable */
return 0;
}
@@ -1958,11 +1899,15 @@ int init_module(void)
void cleanup_module(void)
{
+int i;
+
+for( i = 0; i < FD_MAX_UNITS; i++)
+ if (unit[i].type->code != FD_NODRIVE)
+ kfree(unit[i].trackbuf);
free_irq(IRQ_AMIGA_CIAA_TB, NULL);
free_irq(IRQ_FLOPPY, NULL);
custom.dmacon = DMAF_DISK; /* disable DMA */
amiga_chip_free(raw_buf);
-timer_active &= ~(1 << FLOPPY_TIMER);
blk_size[MAJOR_NR] = NULL;
blksize_size[MAJOR_NR] = NULL;
blk_dev[MAJOR_NR].request_fn = NULL;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 9bb78d63e..900ed785a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -19,7 +19,9 @@
#include <linux/module.h>
#include <linux/config.h>
+#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -277,7 +279,7 @@ repeat:
end_request(1);
goto repeat;
error_out:
- current_request->next=CURRENT;
+ current_request->next=CURRENT;
CURRENT=current_request;
end_request(0);
goto repeat;
@@ -287,27 +289,36 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
{
struct file *file;
struct inode *inode;
+ int error;
+
+ MOD_INC_USE_COUNT;
+ error = -EBADF;
+ file = fget(arg);
+ if (!file)
+ goto out;
- if (arg >= NR_OPEN || !(file = current->files->fd[arg]))
- return -EBADF;
+ error = -EBUSY;
if (lo->lo_inode)
- return -EBUSY;
+ goto out_putf;
+
+ error = -EINVAL;
inode = file->f_dentry->d_inode;
if (!inode) {
printk("loop_set_fd: NULL inode?!?\n");
- return -EINVAL;
+ goto out_putf;
}
+
if (S_ISBLK(inode->i_mode)) {
- int error = blkdev_open(inode, file);
- if (error)
- return error;
+ error = blkdev_open(inode, file);
lo->lo_device = inode->i_rdev;
lo->lo_flags = 0;
} else if (S_ISREG(inode->i_mode)) {
lo->lo_device = inode->i_dev;
lo->lo_flags = LO_FLAGS_DO_BMAP;
- } else
- return -EINVAL;
+ error = 0;
+ }
+ if (error)
+ goto out_putf;
if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
lo->lo_flags |= LO_FLAGS_READ_ONLY;
@@ -317,25 +328,34 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
set_device_ro(dev, 0);
}
+ /* N.B. Should keep the file or dentry ... */
+ inode->i_count++;
lo->lo_inode = inode;
- lo->lo_inode->i_count++;
lo->transfer = NULL;
figure_loop_size(lo);
- MOD_INC_USE_COUNT;
- return 0;
+
+out_putf:
+ fput(file);
+out:
+ if (error)
+ MOD_DEC_USE_COUNT;
+ return error;
}
static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
{
- if (!lo->lo_inode)
+ struct inode *inode = lo->lo_inode;
+
+ if (!inode)
return -ENXIO;
if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */
return -EBUSY;
- if (S_ISBLK(lo->lo_inode->i_mode))
- blkdev_release (lo->lo_inode);
- iput(lo->lo_inode);
- lo->lo_device = 0;
+
+ if (S_ISBLK(inode->i_mode))
+ blkdev_release (inode);
lo->lo_inode = NULL;
+ iput(inode);
+ lo->lo_device = 0;
lo->lo_encrypt_type = 0;
lo->lo_offset = 0;
lo->lo_encrypt_key_size = 0;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 9917963a9..b9ebdc848 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -313,7 +313,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct nbd_device *lo;
- int dev;
+ int dev, error;
if (!suser())
return -EPERM;
@@ -322,6 +322,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
dev = MINOR(inode->i_rdev);
if (dev >= MAX_NBD)
return -ENODEV;
+
lo = &nbd_dev[dev];
switch (cmd) {
case NBD_CLEAR_SOCK:
@@ -329,19 +330,26 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
return -EBUSY;
}
- if (!lo->file)
+ file = lo->file;
+ if (!file)
return -EINVAL;
- lo->file->f_count--;
lo->file = NULL;
lo->sock = NULL;
+ fput(file);
return 0;
case NBD_SET_SOCK:
- file = current->files->fd[arg];
- inode = file->f_dentry->d_inode;
- file->f_count++;
- lo->sock = &inode->u.socket_i;
- lo->file = file;
- return 0;
+ if (lo->file)
+ return -EBUSY;
+ error = -EINVAL;
+ file = fget(arg);
+ if (file) {
+ inode = file->f_dentry->d_inode;
+ /* N.B. Should verify that it's a socket */
+ lo->file = file;
+ lo->sock = &inode->u.socket_i;
+ error = 0;
+ }
+ return error;
case NBD_SET_BLKSIZE:
if ((arg & 511) || (arg > PAGE_SIZE))
return -EINVAL;
@@ -383,6 +391,7 @@ static int nbd_release(struct inode *inode, struct file *file)
if (lo->refcnt <= 0)
printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt);
lo->refcnt--;
+ /* N.B. Doesn't lo->file need an fput?? */
MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index 96a7e019d..a3cbd737e 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -267,7 +267,7 @@ static ssize_t read_mouse(struct file * file, char * buffer,
mouse.ready = 0;
AMI_MSE_INT_ON();
- if ((put_user(buttons | 0x80, buffer++)) ||
+ if (put_user(buttons | 0x80, buffer++) ||
put_user((char)dx, buffer++) ||
put_user((char)dy, buffer++))
return -EINVAL;
diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
new file mode 100644
index 000000000..9647caf90
--- /dev/null
+++ b/drivers/char/amikeyb.c
@@ -0,0 +1,343 @@
+/*
+ * linux/arch/m68k/amiga/amikeyb.c
+ *
+ * Amiga Keyboard driver for Linux/m68k
+ *
+ * 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.
+ */
+
+/*
+ * Amiga support by Hamish Macdonald
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/keyboard.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kd.h>
+#include <linux/random.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#define AMIKEY_CAPS (0x62)
+#define BREAK_MASK (0x80)
+#define RESET_WARNING (0xf0) /* before rotation */
+
+static u_short amiplain_map[NR_KEYS] __initdata = {
+ 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
+ 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
+ 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
+ 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
+ 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+ 0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amishift_map[NR_KEYS] __initdata = {
+ 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
+ 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
+ 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+ 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
+ 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
+ 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
+ 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
+ 0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amialtgr_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
+ 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
+ 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
+ 0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amictrl_map[NR_KEYS] __initdata = {
+ 0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
+ 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+ 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
+ 0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
+ 0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
+ 0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+ 0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amishift_ctrl_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
+ 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amialt_map[NR_KEYS] __initdata = {
+ 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
+ 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
+ 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+ 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
+ 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
+ 0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
+ 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
+ 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
+ 0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
+ 0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short amictrl_alt_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
+ 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
+ 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+#define DEFAULT_KEYB_REP_DELAY (HZ/4)
+#define DEFAULT_KEYB_REP_RATE (HZ/25)
+
+/* These could be settable by some ioctl() in future... */
+static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
+static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
+
+static unsigned char rep_scancode;
+static void amikeyb_rep(unsigned long ignore);
+static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
+
+static void amikeyb_rep(unsigned long ignore)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+
+ kbd_pt_regs = NULL;
+
+ amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
+ amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
+ add_timer(&amikeyb_rep_timer);
+ handle_scancode(rep_scancode);
+
+ restore_flags(flags);
+}
+
+static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ unsigned char scancode, break_flag, keycode;
+ static int reset_warning = 0;
+
+ /* save frame for register dump */
+ kbd_pt_regs = fp;
+
+ /* get and invert scancode (keyboard is active low) */
+ scancode = ~ciaa.sdr;
+
+ /* switch SP pin to output for handshake */
+ ciaa.cra |= 0x40;
+
+#if 0 /* No longer used */
+ /*
+ * On receipt of the second RESET_WARNING, we must not pull KDAT high
+ * again to delay the hard reset as long as possible.
+ *
+ * Note that not all keyboards send reset warnings...
+ */
+ if (reset_warning)
+ if (scancode == RESET_WARNING) {
+ printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
+ "The system will be reset within 10 seconds!!\n");
+ /* Panic doesn't sync from within an interrupt, so we do nothing */
+ return;
+ } else
+ /* Probably a mistake, cancel the alert */
+ reset_warning = 0;
+#endif
+
+ /* wait until 85 us have expired */
+ udelay(85);
+ /* switch CIA serial port to input mode */
+ ciaa.cra &= ~0x40;
+
+ mark_bh(KEYBOARD_BH);
+
+ /* rotate scan code to get up/down bit in proper position */
+ scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
+
+ /*
+ * Check make/break first
+ */
+ break_flag = scancode & BREAK_MASK;
+ keycode = scancode & (unsigned char)~BREAK_MASK;
+
+ if (keycode == AMIKEY_CAPS) {
+ /* if the key is CAPS, fake a press/release. */
+ handle_scancode(AMIKEY_CAPS);
+ handle_scancode(BREAK_MASK | AMIKEY_CAPS);
+ } else if (keycode < 0x78) {
+ /* handle repeat */
+ if (break_flag) {
+ del_timer(&amikeyb_rep_timer);
+ rep_scancode = 0;
+ } else {
+ del_timer(&amikeyb_rep_timer);
+ rep_scancode = keycode;
+ amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
+ amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
+ add_timer(&amikeyb_rep_timer);
+ }
+ handle_scancode(scancode);
+ } else
+ switch (keycode) {
+ case 0x78:
+ reset_warning = 1;
+ break;
+ case 0x79:
+ printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
+ break;
+ case 0x7a:
+ printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
+ break;
+#if 0 /* obsolete according to the HRM */
+ case 0x7b:
+ printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
+ break;
+#endif
+ case 0x7c:
+ printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
+ break;
+ case 0x7d:
+ printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
+ break;
+ case 0x7e:
+ printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
+ break;
+#if 0 /* obsolete according to the HRM */
+ case 0x7f:
+ printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
+ break;
+#endif
+ default:
+ printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
+ scancode);
+ break;
+ }
+}
+
+__initfunc(int amiga_keyb_init(void))
+{
+ if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
+ return -EIO;
+
+ /* setup key map */
+ memcpy(plain_map, amiplain_map, sizeof(plain_map));
+ memcpy(shift_map, amishift_map, sizeof(shift_map));
+ memcpy(altgr_map, amialtgr_map, sizeof(altgr_map));
+ memcpy(ctrl_map, amictrl_map, sizeof(ctrl_map));
+ memcpy(shift_ctrl_map, amishift_ctrl_map, sizeof(shift_ctrl_map));
+ memcpy(alt_map, amialt_map, sizeof(alt_map));
+ memcpy(ctrl_alt_map, amictrl_alt_map, sizeof(ctrl_alt_map));
+
+ /*
+ * Initialize serial data direction.
+ */
+ ciaa.cra &= ~0x41; /* serial data in, turn off TA */
+
+ /*
+ * arrange for processing of keyboard interrupt
+ */
+ request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
+
+ return 0;
+}
+
+int amiga_kbdrate( struct kbd_repeat *k )
+{
+ if (k->delay > 0) {
+ /* convert from msec to jiffies */
+ key_repeat_delay = (k->delay * HZ + 500) / 1000;
+ if (key_repeat_delay < 1)
+ key_repeat_delay = 1;
+ }
+ if (k->rate > 0) {
+ key_repeat_rate = (k->rate * HZ + 500) / 1000;
+ if (key_repeat_rate < 1)
+ key_repeat_rate = 1;
+ }
+
+ k->delay = key_repeat_delay * 1000 / HZ;
+ k->rate = key_repeat_rate * 1000 / HZ;
+
+ return( 0 );
+}
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
new file mode 100644
index 000000000..3dd385df1
--- /dev/null
+++ b/drivers/char/dn_keyb.c
@@ -0,0 +1,614 @@
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/keyboard.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kd.h>
+#include <linux/random.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/apollohw.h>
+#include <asm/uaccess.h>
+
+
+extern void handle_scancode(unsigned char);
+
+#define DNKEY_CAPS 0x7e
+#define BREAK_FLAG 0x80
+#define DNKEY_REPEAT_DELAY 50
+#define DNKEY_CTRL 0x43
+#define DNKEY_LSHIFT 0x5e
+#define DNKEY_RSHIFT 0x6a
+#define DNKEY_REPT 0x5d
+#define DNKEY_REPEAT 0x7f
+#define DNKEY_LALT 0x75
+#define DNKEY_RALT 0x77
+
+#define APOLLO_KEYB_CMD_ENTRIES 16
+#define APOLLO_KBD_MODE_KEYB 0x01
+#define APOLLO_KBD_MODE_MOUSE 0x02
+#define APOLLO_KBD_MODE_CHANGE 0xff
+
+#define MSE_UPDATE_ON() mouse_update_allowed=1
+#define MSE_UPDATE_OFF() mouse_update_allowed=0
+
+static u_char keyb_cmds[APOLLO_KEYB_CMD_ENTRIES];
+static short keyb_cmd_read=0, keyb_cmd_write=0;
+static int keyb_cmd_transmit=0;
+
+static unsigned int kbd_mode=APOLLO_KBD_MODE_KEYB;
+static short mouse_dx,mouse_dy,mouse_buttons;
+static int mouse_ready=0,mouse_update_allowed=0,mouse_active=0;
+static struct wait_queue *mouse_wait=NULL;
+static struct fasync_struct *mouse_fasyncptr=NULL;
+
+#if 0
+static void debug_keyb_timer_handler(unsigned long ignored);
+static u_char debug_buf1[4096],debug_buf2[4096],*debug_buf=&debug_buf1[0];
+static u_char *shadow_buf=&debug_buf2[0];
+static short debug_buf_count=0;
+static int debug_buf_overrun=0,debug_timer_running=0,debug_buffer_updated=0;
+static struct timer_list debug_keyb_timer = { NULL, NULL, 0, 0,
+ debug_keyb_timer_handler };
+#endif
+
+static u_short dnplain_map[NR_KEYS] __initdata = {
+/* ins del del F1 F2 F3 F4
+ mark line char */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* F5 F6 F7 F8 F9 F0 Again Read */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* Edit Exit Hold Copy Paste Grow ESC */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
+/* 1 2 3 4 5 6 7 8 */
+ 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038,
+/* 9 0 - = ` Back |<--
+ Space */
+ 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf200, 0xf200,
+/* Shell -->| Tab q w e
+ Cmd */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xfb71, 0xfb77, 0xfb65,
+/* r t y u i o p [ */
+ 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf05b,
+/* ] Del 7 8 9 + */
+ 0xf05d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
+/* [<--] Up [-->] Ctrl a s */
+ 0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb61, 0xfb73,
+/* d f g h j k l ; */
+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+/* ' Return \ 4 5 6 */
+ 0xf027, 0xf200, 0xf201, 0xf05c, 0xf200, 0xf304, 0xf305, 0xf306,
+/* - <-- Next --> Rept Shift
+ Window */
+ 0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf700, 0xf200,
+/* z x c v b n m , */
+ 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c,
+/* . / Shift Pop 1 2 */
+ 0xf02e, 0xf02f, 0xf700, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
+/* 3 PgUp Down PgDn Alt Space Alt */
+ 0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
+/* 0 . Enter */
+ 0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf700, 0xf200,
+};
+
+static u_short dnshift_map[NR_KEYS] __initdata = {
+/* ins del del F1 F2 F3 F4
+ mark line char */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* F5 F6 F7 F8 F9 F0 Again Read */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* Save Abort Help Cut Undo Grow ESC */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
+/* ! @ # $ % ^ & * */
+ 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a,
+/* ( ) _ + ~ Back |<--
+ Space */
+ 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf200, 0xf200,
+/* Shell -->| Tab Q W E
+ Cmd */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xfb51, 0xfb57, 0xfb45,
+/* R T Y U I O P { */
+ 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50, 0xf07b,
+/* } Del 7 8 9 + */
+ 0xf07d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
+/* [<--] Up [-->] Ctrl A S */
+ 0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb41, 0xfb53,
+/* D F G H J K L : */
+ 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+/* " Return | 4 5 6 */
+ 0xf022, 0xf200, 0xf201, 0xf07c, 0xf200, 0xf304, 0xf305, 0xf306,
+/* - <-- Next --> Rept Shift
+ Window */
+ 0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf700, 0xf200,
+/* Z X C V B N M < */
+ 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c,
+/* > ? Shift Pop 1 2 */
+ 0xf03e, 0xf03f, 0xf700, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
+/* 3 PgUp Down PgDn Alt Space Alt */
+ 0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
+/* 0 . Enter */
+ 0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf708, 0xf200,
+};
+
+static u_short dnctrl_map[NR_KEYS] __initdata = {
+/* ins del del F1 F2 F3 F4
+ mark line char */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* F5 F6 F7 F8 F9 F0 Again Read */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+/* Save Abort Help Cut Undo Grow ESC */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
+/* ! @ # $ % ^ & * */
+ 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f,
+/* ( ) _ + ~ Back |<--
+ Space */
+ 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf200, 0xf200,
+/* Shell -->| Tab Q W E
+ Cmd */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xf011, 0xf017, 0xf005,
+/* R T Y U I O P { */
+ 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf01b,
+/* } Del 7 8 9 + */
+ 0xf01d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
+/* [<--] Up [-->] Ctrl A S */
+ 0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb01, 0xfb53,
+/* D F G H J K L : */
+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+/* " Return | 4 5 6 */
+ 0xf200, 0xf200, 0xf201, 0xf01c, 0xf200, 0xf304, 0xf305, 0xf306,
+/* - <-- Next --> Rept Shift
+ Window */
+ 0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf704, 0xf200,
+/* Z X C V B N M < */
+ 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf01d, 0xf03c,
+/* > ? Shift Pop 1 2 */
+ 0xf03e, 0xf03f, 0xf705, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
+/* 3 PgUp Down PgDn Alt Space Alt */
+ 0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
+/* 0 . Enter */
+ 0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short dnalt_map[NR_KEYS] __initdata = {
+/* ins del del F1 F2 F3 F4
+ mark line char */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf502, 0xf503,
+/* F5 F6 F7 F8 F9 F0 Again Read */
+ 0xf504, 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf200, 0xf200,
+/* Edit Exit Hold Copy Paste Grow ESC */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
+/* 1 2 3 4 5 6 7 8 */
+ 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838,
+/* 9 0 - = ` Back |<--
+ Space */
+ 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf200, 0xf200,
+/* Shell -->| Tab q w e
+ Cmd */
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf809, 0xf871, 0xf877, 0xf865,
+/* r t y u i o p [ */
+ 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870, 0xf85b,
+/* ] Del 7 8 9 + */
+ 0xf05d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
+/* [<--] Up [-->] Ctrl a s */
+ 0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xf861, 0xf873,
+/* d f g h j k l ; */
+ 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf03b,
+/* ' Return \ 4 5 6 */
+ 0xf027, 0xf200, 0xf201, 0xf05c, 0xf200, 0xf304, 0xf305, 0xf306,
+/* - <-- Next --> Rept Shift
+ Window */
+ 0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf704, 0xf200,
+/* z x c v b n m , */
+ 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d, 0xf82c,
+/* . / Shift Pop 1 2 */
+ 0xf82e, 0xf82f, 0xf705, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
+/* 3 PgUp Down PgDn Alt Space Alt */
+ 0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf820, 0xf701,
+/* 0 . Enter */
+ 0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short dnaltgr_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short dnshift_ctrl_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short dnctrl_alt_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+#if 0
+static void debug_keyb_timer_handler(unsigned long ignored) {
+
+ unsigned long flags;
+ u_char *swap;
+ short length,i;
+
+ if((jiffies-debug_buffer_updated) > 100) {
+ save_flags(flags);
+ cli();
+ length=debug_buf_count;
+ swap=debug_buf;
+ debug_buf=shadow_buf;
+ shadow_buf=swap;
+ debug_buf_count=0;
+ debug_timer_running=0;
+ restore_flags(flags);
+ for(i=1;length;length--,i++)
+ printk("%02x%c",*(swap++), (i % 25) ? ' ' : '\n');
+ printk("\n");
+ }
+ else {
+ debug_keyb_timer.expires=jiffies+10;
+ add_timer(&debug_keyb_timer);
+ }
+}
+#endif
+
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
+{
+ poll_wait(&mouse_wait, wait);
+ if (mouse_ready)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static ssize_t write_mouse(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t read_mouse(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ int dx,dy,r;
+ unsigned char buttons;
+
+ if (count < 3)
+ return -EINVAL;
+ if ((r = verify_area(VERIFY_WRITE, buffer, count)))
+ return r;
+ if (!mouse_ready)
+ return -EAGAIN;
+
+ MSE_UPDATE_OFF();
+ dx=mouse_dx;
+ dy=mouse_dy;
+ if (dx < -127)
+ dx = -127;
+ else
+ if (dx > 127)
+ dx = 127;
+ if (dy < -127)
+ dy = -127;
+ else
+ if (dy > 127)
+ dy = 127;
+ buttons=(mouse_buttons & 1 ? 4 : 0) |
+ (mouse_buttons & 2 ? 1 : 0) |
+ (mouse_buttons & 4 ? 2 : 0);
+
+ mouse_dx-=dx;
+ mouse_dy-=dy;
+ MSE_UPDATE_ON();
+
+ if (put_user(buttons | 0x80, buffer++) ||
+ put_user((char)dx, buffer++) ||
+ put_user((char)dy, buffer++))
+ return -EINVAL;
+
+ if (count > 3)
+ if (clear_user(buffer, count - 3))
+ return -EFAULT;
+ return count;
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(filp, on, &mouse_fasyncptr);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+
+static int release_mouse(struct inode * inode, struct file * file)
+{
+ fasync_mouse(file, 0);
+ if (--mouse_active)
+ return 0;
+ MSE_UPDATE_OFF();
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+ if (mouse_active++)
+ return 0;
+ /*
+ * use VBL to poll mouse deltas
+ */
+
+ mouse_dx = 0;
+ mouse_dy = 0;
+ mouse_buttons = 0;
+ mouse_active = 1;
+ MOD_INC_USE_COUNT;
+ MSE_UPDATE_ON();
+ return 0;
+}
+
+static void dn_keyb_process_key_event(unsigned char scancode) {
+
+ static unsigned char lastscancode;
+ unsigned char prev_scancode=lastscancode;
+ static unsigned int lastkeypress;
+
+ lastscancode=scancode;
+
+ /* printk("scan: %02x, lastscan: %02X, prev_scancode: %02X\n",scancode,lastscancode,prev_scancode); */
+
+ if(prev_scancode==APOLLO_KBD_MODE_CHANGE) {
+ kbd_mode=scancode;
+/* printk("modechange: %d\n",scancode);*/
+ }
+ else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) {
+ /* printk("handle_scancode: %02x\n",DNKEY_CAPS); */
+ handle_scancode(DNKEY_CAPS);
+ /* printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */
+ handle_scancode(BREAK_FLAG | DNKEY_CAPS);
+ }
+ else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) &&
+ !(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
+ prev_scancode==DNKEY_RSHIFT || prev_scancode==DNKEY_REPT ||
+ prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
+ if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
+ /* printk("handle_scancode: %02x\n",prev_scancode); */
+ handle_scancode(prev_scancode);
+ }
+ lastscancode=prev_scancode;
+ }
+ else {
+ /* printk("handle_scancode: %02x\n",scancode); */
+ handle_scancode(scancode);
+ lastkeypress=jiffies;
+ }
+}
+
+static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
+
+ static short mouse_byte_count=0;
+ static u_char mouse_packet[3];
+
+ mouse_packet[mouse_byte_count++]=mouse_data;
+
+ if(mouse_byte_count==3) {
+ if(mouse_packet[0]==APOLLO_KBD_MODE_CHANGE) {
+ kbd_mode=mouse_packet[1];
+ mouse_byte_count=0;
+/* printk("modechange: %d\n",mouse_packet[1]); */
+ if(kbd_mode==APOLLO_KBD_MODE_KEYB)
+ dn_keyb_process_key_event(mouse_packet[2]);
+ }
+ if((mouse_packet[0] & 0x8f) == 0x80) {
+ if(mouse_update_allowed) {
+ mouse_ready=1;
+ mouse_buttons=(mouse_packet[0] >> 4) & 0x7;
+ mouse_dx+=mouse_packet[1] == 0xff ? 0 : (signed char)mouse_packet[1];
+ mouse_dy+=mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2];
+ wake_up_interruptible(&mouse_wait);
+ if (mouse_dx < -2048)
+ mouse_dx = -2048;
+ else
+ if (mouse_dx > 2048)
+ mouse_dx = 2048;
+ if (mouse_dy < -2048)
+ mouse_dy = -2048;
+ else
+ if (mouse_dy > 2048)
+ mouse_dy = 2048;
+ if (mouse_fasyncptr)
+ kill_fasync(mouse_fasyncptr, SIGIO);
+ }
+ mouse_byte_count=0;
+/* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
+ }
+ }
+}
+
+static void dn_keyb_int(int irq, void *dummy, struct pt_regs *fp) {
+
+ unsigned char data;
+ unsigned long flags;
+ int scn2681_ints;
+
+ do {
+ scn2681_ints=sio01.isr_imr & 3;
+ if(scn2681_ints & 2) {
+ data=sio01.rhra_thra;
+#if 0
+ if(debug_buf_count<4096) {
+ debug_buf[debug_buf_count++]=data;
+ debug_buffer_updated=jiffies;
+ if(!debug_timer_running) {
+ add_timer(&debug_keyb_timer);
+ debug_keyb_timer.expires=jiffies+10;
+ debug_timer_running=1;
+ }
+ }
+ else
+ debug_buf_overrun=1;
+#endif
+ if(sio01.sra_csra & 0x10) {
+ printk("whaa overrun !\n");
+ continue;
+ }
+
+ if(kbd_mode==APOLLO_KBD_MODE_KEYB)
+ dn_keyb_process_key_event(data);
+ else
+ dn_keyb_process_mouse_event(data);
+ }
+
+ if(scn2681_ints & 1) {
+ save_flags(flags);
+ cli();
+ if(keyb_cmd_write!=keyb_cmd_read) {
+ sio01.rhra_thra=keyb_cmds[keyb_cmd_read++];
+ if(keyb_cmd_read==APOLLO_KEYB_CMD_ENTRIES)
+ keyb_cmd_read=0;
+ keyb_cmd_transmit=1;
+ }
+ else {
+ keyb_cmd_transmit=0;
+ sio01.BRGtest_cra=9;
+ }
+ restore_flags(flags);
+ }
+ } while(scn2681_ints) ;
+}
+
+void write_keyb_cmd(u_short length, u_char *cmd) {
+
+ unsigned long flags;
+
+ if((keyb_cmd_write==keyb_cmd_read) && keyb_cmd_transmit)
+ return;
+
+ save_flags(flags);
+ cli();
+ for(;length;length--) {
+ keyb_cmds[keyb_cmd_write++]=*(cmd++);
+ if(keyb_cmd_write==keyb_cmd_read)
+ return;
+ if(keyb_cmd_write==APOLLO_KEYB_CMD_ENTRIES)
+ keyb_cmd_write=0;
+ }
+ if(!keyb_cmd_transmit) {
+ sio01.BRGtest_cra=5;
+ }
+ restore_flags(flags);
+
+}
+
+struct file_operations apollo_mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_poll, /* mouse_poll */
+ NULL, /* mouse_ioctl */
+ NULL, /* mouse_mmap */
+ open_mouse,
+ release_mouse,
+ NULL,
+ fasync_mouse,
+};
+
+static struct miscdevice apollo_mouse = {
+ APOLLO_MOUSE_MINOR, "apollomouse", &apollo_mouse_fops
+};
+
+__initfunc(int dn_keyb_init(void)) {
+
+/* printk("dn_keyb_init\n"); */
+
+ memcpy(plain_map, dnplain_map, sizeof(plain_map));
+ memcpy(shift_map, dnshift_map, sizeof(shift_map));
+ memcpy(altgr_map, dnaltgr_map, sizeof(altgr_map));
+ memcpy(ctrl_map, dnctrl_map, sizeof(ctrl_map));
+ memcpy(shift_ctrl_map, dnshift_ctrl_map, sizeof(shift_ctrl_map));
+ memcpy(alt_map, dnalt_map, sizeof(alt_map));
+ memcpy(ctrl_alt_map, dnctrl_alt_map, sizeof(ctrl_alt_map));
+
+ mouse_dx=0;
+ mouse_dy=0;
+ mouse_buttons=0;
+ mouse_wait=NULL;
+
+ misc_register(&apollo_mouse);
+
+ /* program UpDownMode */
+
+ while(!(sio01.sra_csra & 0x4));
+ sio01.rhra_thra=0xff;
+
+ while(!(sio01.sra_csra & 0x4));
+ sio01.rhra_thra=0x1;
+
+ request_irq(1, dn_keyb_int,0,NULL,NULL);
+
+ /* enable receive int on DUART */
+ sio01.isr_imr=3;
+
+ return 0;
+
+}
+
+int dn_dummy_kbdrate(struct kbd_repeat *k) {
+
+ printk("dn_dummy_kbdrate\n");
+
+ return 0;
+
+}
diff --git a/drivers/char/hfmodem/gentbl.c b/drivers/char/hfmodem/gentbl.c
index d60651b1b..c99b963d8 100644
--- a/drivers/char/hfmodem/gentbl.c
+++ b/drivers/char/hfmodem/gentbl.c
@@ -62,7 +62,7 @@ int main(int argc, char *argv[])
printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
argv[0]);
gensintbl();
- exit(0);
+ return(0);
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 0d7ea6da0..2e0dd3736 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -170,7 +170,7 @@ static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
*/
static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
static char *stli_drvname = "istallion";
-static char *stli_drvversion = "5.4.3";
+static char *stli_drvversion = "5.4.5";
static char *stli_serialname = "ttyE";
static char *stli_calloutname = "cue";
diff --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c
new file mode 100644
index 000000000..0cf1fab20
--- /dev/null
+++ b/drivers/char/macmouse.c
@@ -0,0 +1,311 @@
+/*
+ * Macintosh ADB Mouse driver for Linux
+ *
+ * 27 Oct 1997 Michael Schmitz
+ *
+ * Apple mouse protocol according to:
+ *
+ * Device code shamelessly stolen from:
+ */
+/*
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mac_mouse.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+static struct mouse_status mouse;
+static int mac_mouse_x_threshold = 2, mac_mouse_y_threshold = 2;
+static int mac_mouse_buttons = 0;
+
+extern void (*mac_mouse_interrupt_hook) (char *, int);
+extern int mac_emulate_button2;
+extern int mac_emulate_button3;
+
+extern int console_loglevel;
+
+/*
+ * XXX: need to figure out what ADB mouse packets mean ...
+ * This is the stuff stolen from the Atari driver ...
+ */
+static void mac_mouse_interrupt(char *buf, int nb)
+{
+ static int buttons = 7; /* all mouse buttons _up_ !! */
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = ???? ???? (?)
+ data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+ data[3] = bxxx xxxx First button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+
+ NOTE: data[0] is confirmed by the parent function and need not be
+ checked here.
+ */
+
+ /*
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = 0100 0000 Extended protocol register.
+ Bits 6-7 are the device id, which should be 1.
+ Bits 4-5 are resolution which is in "units/inch".
+ The Logitech MouseMan returns these bits clear but it has
+ 200/300cpi resolution.
+ Bits 0-3 are unique vendor id.
+ data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+ Bits 2-3 should be 8 + 4.
+ Bits 4-7 should be 3 for a mouse device.
+ data[3] = bxxx xxxx Left button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+ data[5] = byyy bxxx Third button and fourth button.
+ Y is additiona. high bits of y-axis motion.
+ X is additional high bits of x-axis motion.
+
+ NOTE: data[0] and data[2] are confirmed by the parent function and
+ need not be checked here.
+ */
+
+ /*
+ * 'buttons' here means 'button down' states!
+ * Button 1 (left) : bit 2, busmouse button 3
+ * Button 2 (right) : bit 0, busmouse button 1
+ * Button 3 (middle): bit 1, busmouse button 2
+ */
+
+ /* x/y and buttons swapped */
+
+ if (buf[0] == 0) { /* real packet : use buttons? */
+#ifdef DEBUG_ADBMOUSE
+ if (console_loglevel >= 8)
+ printk("mac_mouse: real data; ");
+#endif
+ /* button 1 (left, bit 2) : always significant ! */
+ buttons = (buttons&3) | (buf[3] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+ /* button 2 (right, bit 0) present ? */
+ if ( !mac_emulate_button2 )
+ buttons = (buttons&6) | (buf[4] & 0x80 ? 1 : 0); /* 2+3 unchanged */
+ /* button 2 (middle) present? */
+ /* data valid only if extended mouse format ! (buf[3] = 0 else)*/
+ if ( !mac_emulate_button3 && buf[1]&0x40 )
+ buttons = (buttons&5) | (buf[5] & 0x80 ? 2 : 0); /* 1+3 unchanged */
+ } else { /* fake packet : use 2+3 */
+#ifdef DEBUG_ADBMOUSE
+ if (console_loglevel >= 8)
+ printk("mac_mouse: fake data; ");
+#endif
+ /* we only see state changes here, but the fake driver takes care
+ * to preserve state... button 1 state must stay unchanged! */
+ buttons = (buttons&4) | ((buf[4] & 0x80 ? 1 : 0) | (buf[5] & 0x80 ? 2 : 0));
+ }
+
+ add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+ mouse.buttons = buttons & 7;
+ mouse.dx += ((buf[4]&0x7f) < 64 ? (buf[4]&0x7f) : (buf[4]&0x7f)-128 );
+ mouse.dy -= ((buf[3]&0x7f) < 64 ? (buf[3]&0x7f) : (buf[3]&0x7f)-128 );
+
+#ifdef DEBUG_ADBMOUSE
+ if (console_loglevel >= 8)
+ printk(" %X %X %X buttons %x dx %d dy %d \n",
+ buf[3], buf[4], buf[5], mouse.buttons, mouse.dx, mouse.dy);
+#endif
+
+ mouse.ready = 1;
+ wake_up_interruptible(&mouse.wait);
+ if (mouse.fasyncptr)
+ kill_fasync(mouse.fasyncptr, SIGIO);
+
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int release_mouse(struct inode *inode, struct file *file)
+{
+ fasync_mouse(file, 0);
+ if (--mouse.active)
+ return 0;
+
+ mac_mouse_interrupt_hook = NULL;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int open_mouse(struct inode *inode, struct file *file)
+{
+ if (mouse.active++)
+ return 0;
+
+ mouse.ready = 0;
+
+ mouse.dx = mouse.dy = 0;
+ mac_mouse_buttons = 0;
+ MOD_INC_USE_COUNT;
+ mac_mouse_interrupt_hook = mac_mouse_interrupt;
+ return 0;
+}
+
+static ssize_t write_mouse(struct file *file, const char *buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
+ loff_t *ppos)
+{
+ int dx, dy, buttons;
+
+ if (count < 3)
+ return -EINVAL;
+ if (!mouse.ready)
+ return -EAGAIN;
+ dx = mouse.dx;
+ dy = mouse.dy;
+ buttons = mouse.buttons;
+ if (dx > 127)
+ dx = 127;
+ else if (dx < -128)
+ dx = -128;
+ if (dy > 127)
+ dy = 127;
+ else if (dy < -128)
+ dy = -128;
+ mouse.dx -= dx;
+ mouse.dy -= dy;
+ if (mouse.dx == 0 && mouse.dy == 0)
+ mouse.ready = 0;
+ if (put_user(buttons | 0x80, buffer++) ||
+ put_user((char) dx, buffer++) ||
+ put_user((char) dy, buffer++))
+ return -EFAULT;
+ if (count > 3)
+ if (clear_user(buffer, count - 3))
+ return -EFAULT;
+ return count;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(&mouse.wait, wait);
+ if (mouse.ready)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+struct file_operations mac_mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_poll,
+ NULL, /* mouse_ioctl */
+ NULL, /* mouse_mmap */
+ open_mouse,
+ release_mouse,
+ NULL,
+ fasync_mouse,
+};
+
+#define ADB_MOUSE_MINOR 10
+
+static struct miscdevice mac_mouse = {
+ ADB_MOUSE_MINOR, "adbmouse", &mac_mouse_fops
+};
+
+__initfunc(int mac_mouse_init(void))
+{
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.wait = NULL;
+
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
+ printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+ misc_register(&mac_mouse);
+ return 0;
+}
+
+
+#define MIN_THRESHOLD 1
+#define MAX_THRESHOLD 20 /* more seems not reasonable... */
+
+__initfunc(void mac_mouse_setup(char *str, int *ints))
+{
+ if (ints[0] < 1) {
+ printk( "mac_mouse_setup: no arguments!\n" );
+ return;
+ }
+ else if (ints[0] > 2) {
+ printk( "mac_mouse_setup: too many arguments\n" );
+ }
+
+ if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+ printk( "mac_mouse_setup: bad threshold value (ignored)\n" );
+ else {
+ mac_mouse_x_threshold = ints[1];
+ mac_mouse_y_threshold = ints[1];
+ if (ints[0] > 1) {
+ if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+ printk("mac_mouse_setup: bad threshold value (ignored)\n" );
+ else
+ mac_mouse_y_threshold = ints[2];
+ }
+ }
+
+}
+
+#ifdef MODULE
+#include <asm/setup.h>
+
+int init_module(void)
+{
+ return mac_mouse_init();
+}
+
+void cleanup_module(void)
+{
+ misc_deregister(&mac_mouse);
+}
+#endif
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index a5c10988e..1ca4412af 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -38,6 +38,9 @@ int pcwatchdog_init(void);
#ifdef CONFIG_VIDEO_DEV
extern int videodev_init(void);
#endif
+#if defined(CONFIG_FB)
+extern void fbmem_init( void );
+#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
@@ -522,6 +525,9 @@ __initfunc(int chr_dev_init(void))
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
rand_initialize();
+#if defined (CONFIG_FB)
+ fbmem_init();
+#endif
tty_init();
#ifdef CONFIG_PRINTER
lp_init();
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index c17ae5e14..5f6ed4b01 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -53,7 +53,7 @@ unsigned char pckbd_sysrq_xlate[128] =
"\r\000/"; /* 0x60 - 0x6f */
#endif
-__initfunc(static int kbd_wait_for_input(void))
+static int kbd_wait_for_input(void)
{
int n;
int status, data;
@@ -86,7 +86,7 @@ __initfunc(static int kbd_wait_for_input(void))
return -1; /* timed-out if fell through to here... */
}
-__initfunc(static void init_write_command(int data))
+static void init_write_command(int data)
{
int status;
@@ -96,7 +96,7 @@ __initfunc(static void init_write_command(int data))
kbd_write_command(data);
}
-__initfunc(static void init_write_output(int data))
+static void init_write_output(int data)
{
int status;
@@ -106,7 +106,7 @@ __initfunc(static void init_write_output(int data))
kbd_write_output(data);
}
-__initfunc(static char *initialize_kbd2(void))
+static char *initialize_kbd2(void)
{
/* Flush any pending input. */
@@ -183,7 +183,7 @@ __initfunc(static char *initialize_kbd2(void))
return NULL;
}
-__initfunc(void initialize_kbd(void))
+void initialize_kbd(void)
{
char *msg;
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 064031dd8..67aeafc47 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -143,7 +143,7 @@ static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
*/
static char *stl_drvtitle = "Stallion Multiport Serial Driver";
static char *stl_drvname = "stallion";
-static char *stl_drvversion = "5.4.3";
+static char *stl_drvversion = "5.4.5";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
@@ -278,6 +278,7 @@ static char *stl_brdnames[] = {
#define EIO_INTRPEND 0x08
#define EIO_INTEDGE 0x00
#define EIO_INTLEVEL 0x08
+#define EIO_0WS 0x10
#define ECH_ID 0xa0
#define ECH_IDBITMASK 0xe0
@@ -2153,6 +2154,10 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 2;
+ status = inb(brdp->iostatus);
+ if ((status & EIO_IDBITMASK) == EIO_MK3)
+ brdp->ioctrl++;
+
/*
* Handle board specific stuff now. The real difference is PCI
* or not PCI.
@@ -2171,7 +2176,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->irq, brdp->brdnr);
return(-EINVAL);
}
- outb((stl_vecmap[brdp->irq] |
+ outb((stl_vecmap[brdp->irq] | EIO_0WS |
((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
brdp->ioctrl);
}
@@ -2194,7 +2199,6 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
- status = inb(brdp->iostatus);
switch (status & EIO_IDBITMASK) {
case EIO_8PORTM:
brdp->clk = CD1400_CLK8M;
@@ -2220,7 +2224,6 @@ static inline int stl_initeio(stlbrd_t *brdp)
default:
return(-ENODEV);
}
- brdp->ioctrl++;
break;
default:
return(-ENODEV);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 5d100bba4..364c5602e 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -66,6 +66,7 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/file.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
@@ -1734,8 +1735,8 @@ void do_SAK( struct tty_struct *tty)
((session > 0) && (p->session == session)))
send_sig(SIGKILL, p, 1);
else if (p->files) {
- for (i=0; i < NR_OPEN; i++) {
- filp = p->files->fd[i];
+ for (i=0; i < p->files->max_fds; i++) {
+ filp = fcheck_task(p, i);
if (filp && (filp->f_op == &tty_fops) &&
(filp->private_data == tty)) {
send_sig(SIGKILL, p, 1);
diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c
index e5ba92c9e..bd542b4fd 100644
--- a/drivers/misc/parport_pc.c
+++ b/drivers/misc/parport_pc.c
@@ -134,12 +134,12 @@ void parport_pc_change_mode(struct parport *p, int m)
void parport_pc_write_fifo(struct parport *p, unsigned char v)
{
- /* FIXME */
+ outb (v, p->base+CONFIGA);
}
unsigned char parport_pc_read_fifo(struct parport *p)
{
- return 0; /* FIXME */
+ return inb (p->base+CONFIGA);
}
void parport_pc_disable_irq(struct parport *p)
@@ -186,22 +186,34 @@ void parport_pc_restore_state(struct parport *p, struct parport_state *s)
size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
{
- return 0; /* FIXME */
+ size_t got = 0;
+ for (; got < length; got++) {
+ *((char*)buf)++ = inb (p->base+EPPREG);
+ if (inb (p->base+STATUS) & 0x01)
+ break;
+ }
+ return got;
}
size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
{
- return 0; /* FIXME */
+ size_t written = 0;
+ for (; written < length; written++) {
+ outb (*((char*)buf)++, p->base+EPPREG);
+ if (inb (p->base+STATUS) & 0x01)
+ break;
+ }
+ return written;
}
int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
{
- return 0; /* FIXME */
+ return -ENOSYS; /* FIXME */
}
int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
{
- return 0; /* FIXME */
+ return -ENOSYS; /* FIXME */
}
int parport_pc_examine_irq(struct parport *p)
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index bc39b351c..bd0ae3c8b 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.10 1998/03/18 06:32:19 ralf Exp $
+/* $Id: parport_share.c,v 1.11 1998/03/26 10:38:32 ralf Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -46,7 +46,9 @@ struct parport *parport_enumerate(void)
{
#ifdef CONFIG_KMOD
if (portlist == NULL) {
+#if defined(CONFIG_PARPORT_PC_MODULE) || defined(CONFIG_PARPORT_AX_MODULE) || defined(CONFIG_PARPORT_ARC_MODULE)
request_module("parport_lowlevel");
+#endif /* CONFIG_PARPORT_LOWLEVEL_MODULE */
#ifdef CONFIG_PNP_PARPORT_MODULE
request_module("parport_probe");
#endif /* CONFIG_PNP_PARPORT_MODULE */
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index e0f47e712..9a818d4d4 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -383,8 +383,8 @@ alloc586( struct device *dev ) {
}
/*****************************************************************/
-__initfunc(static int
-elmc_getinfo( char* buf, int slot, void* d )) {
+static int
+elmc_getinfo( char* buf, int slot, void* d ) {
int len = 0;
struct device* dev = (struct device*) d;
int i;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 7b8f9ec10..2694dbb6c 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -83,7 +83,7 @@ static int max_interrupt_work = 20;
#if LINUX_VERSION_CODE < 0x10300
#define RUN_AT(x) (x) /* What to put in timer->expires. */
#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#if defined(__alpha)
+#if defined(__alpha__)
#error "The Alpha architecture is only support with kernel version 2.0."
#endif
#define virt_to_bus(addr) ((unsigned long)addr)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 8d3f1f40b..47738877f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -739,7 +739,21 @@ L_OBJS += mace.o
endif
ifeq ($(CONFIG_VENDOR_SANGOMA),y)
- M_OBJS += sdladrv.o
+ L_OBJS += sdladrv.o
+ L_OBJS += sdlamain.o
+ ifeq ($(CONFIG_WANPIPE_X25),y)
+ L_OBJS += sdla_x25.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_FR),y)
+ L_OBJS += sdla_fr.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_PPP),y)
+ L_OBJS += sdla_ppp.o
+ endif
+endif
+
+ifeq ($(CONFIG_VENDOR_SANGOMA),m)
+ MX_OBJS += sdladrv.o
M_OBJS += wanpipe.o
WANPIPE_OBJS = sdlamain.o
ifeq ($(CONFIG_WANPIPE_X25),y)
diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c
index 4750c18ee..3f507d248 100644
--- a/drivers/net/hamradio/soundmodem/gentbl.c
+++ b/drivers/net/hamradio/soundmodem/gentbl.c
@@ -631,7 +631,7 @@ static void gentbl_banner(FILE *f)
/* -------------------------------------------------------------------- */
-void main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
FILE *f;
@@ -681,7 +681,7 @@ void main(int argc, char *argv[])
gentbl_costab(f, 6);
gentbl_afsk2400(f, 7372800);
fclose(f);
- exit(0);
+ return(0);
}
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
index e30bede48..9c1c65af8 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/sdla_fr.c
@@ -1,4 +1,4 @@
-/****************************************************************************
+/*****************************************************************************
* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
*
* Author(s): Gene Kozin
@@ -83,85 +83,83 @@
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
-#if !defined(__KERNEL__) || !defined(MODULE)
-#error This code MUST be compiled as a kernel module!
-#endif
-
#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/string.h> /* inline memset(), etc. */
#include <linux/malloc.h> /* kmalloc(), kfree() */
-#include <linux/init.h> /* __initfunc */
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
#include <linux/if_arp.h> /* ARPHRD_* defines */
#include <asm/byteorder.h> /* htons(), etc. */
#include <asm/io.h> /* for inb(), outb(), etc. */
-#include <asm/uaccess.h>
-#include <linux/time.h> /* for do_gettimeofday */
-
+#include <linux/time.h> /* for do_gettimeofday */
#define _GNUC_
#include <linux/sdla_fr.h> /* frame relay firmware API definitions */
-/****** Defines & Macros ****************************************************/
+#include <asm/uaccess.h>
-#define MAX_CMD_RETRY 10 /* max number of firmware retries */
+/****** Defines & Macros ****************************************************/
-#define FR_HEADER_LEN 8 /* max encapsulation header size */
-#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
+#define MAX_CMD_RETRY 10 /* max number of firmware retries */
+#define FR_HEADER_LEN 8 /* max encapsulation header size */
+#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
/* Q.922 frame types */
-#define Q922_UI 0x03 /* Unnumbered Info frame */
-#define Q922_XID 0xAF /* ??? */
+
+#define Q922_UI 0x03 /* Unnumbered Info frame */
+#define Q922_XID 0xAF /* ??? */
/* DLCI configured or not */
+
#define DLCI_NOT_CONFIGURED 0x00
#define DLCI_CONFIG_PENDING 0x01
#define DLCI_CONFIGURED 0x02
/* CIR enabled or not */
+
#define CIR_ENABLED 0x00
#define CIR_DISABLED 0x01
/* Interrupt mode for DLCI = 0 */
+
#define BUFFER_INTR_MODE 0x00
#define DLCI_LIST_INTR_MODE 0x01
/* Transmit Interrupt Status */
+
#define DISABLED 0x00
#define WAITING_TO_BE_ENABLED 0x01
/* For handle_IPXWAN() */
+
#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
+
/****** Data Structures *****************************************************/
/* This is an extention of the 'struct device' we create for each network
* interface to keep the rest of channel-specific data.
*/
-typedef struct fr_channel
-{
- char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
- unsigned dlci_configured ; /* check whether configured or not */
- unsigned cir_status; /* check whether CIR enabled or not */
- unsigned dlci; /* logical channel number */
- unsigned cir; /* committed information rate */
- unsigned bc; /* committed burst size */
- unsigned be; /* excess burst size */
- unsigned mc; /* multicast support on or off */
- unsigned tx_int_status; /* Transmit Interrupt Status */
+typedef struct fr_channel {
+ char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */
+ unsigned dlci_configured; /* check whether configured or not */
+ unsigned cir_status; /* check whether CIR enabled or not */
+ unsigned dlci; /* logical channel number */
+ unsigned cir; /* committed information rate */
+ unsigned bc; /* committed burst size */
+ unsigned be; /* excess burst size */
+ unsigned mc; /* multicast support on or off */
+ unsigned tx_int_status; /* Transmit Interrupt Status */
unsigned short pkt_length; /* Packet Length */
- unsigned long router_start_time;/* Router start time in seconds */
+ unsigned long router_start_time; /* Router start time in seconds */
unsigned long tick_counter; /* counter for transmit time out */
char dev_pending_devtint; /* interface pending dev_tint() */
- char state; /* channel state */
- void* dlci_int_interface; /* pointer to the DLCI Interface */
- unsigned long IB_addr; /* physical address of Interface Byte */
+ char state; /* channel state */
+ void *dlci_int_interface; /* pointer to the DLCI Interface */
+ unsigned long IB_addr; /* physical address of Interface Byte */
unsigned long state_tick; /* time of the last state change */
- sdla_t* card; /* -> owner */
- struct enet_statistics ifstats; /* interface statistics */
-
+ sdla_t *card; /* -> owner */
+ struct enet_statistics ifstats; /* interface statistics */
unsigned long if_send_entry;
unsigned long if_send_skb_null;
unsigned long if_send_broadcast;
@@ -177,14 +175,12 @@ typedef struct fr_channel
unsigned long if_send_no_bfrs;
unsigned long if_send_adptr_bfrs_full;
unsigned long if_send_bfrs_passed_to_adptr;
-
unsigned long rx_intr_no_socket;
unsigned long rx_intr_dev_not_started;
unsigned long rx_intr_FPIPE_request;
unsigned long rx_intr_DRVSTATS_request;
unsigned long rx_intr_bfr_not_passed_to_stack;
unsigned long rx_intr_bfr_passed_to_stack;
-
unsigned long UDP_FPIPE_mgmt_kmalloc_err;
unsigned long UDP_FPIPE_mgmt_direction_err;
unsigned long UDP_FPIPE_mgmt_adptr_type_err;
@@ -206,37 +202,32 @@ typedef struct fr_channel
unsigned long router_up_time;
} fr_channel_t;
-typedef struct dlci_status
-{
- unsigned short dlci PACKED;
- unsigned char state PACKED;
+typedef struct dlci_status {
+ unsigned short dlci PACKED;
+ unsigned char state PACKED;
} dlci_status_t;
-typedef struct dlci_IB_mapping
-{
- unsigned short dlci PACKED;
- unsigned long addr_value PACKED;
+typedef struct dlci_IB_mapping {
+ unsigned short dlci PACKED;
+ unsigned long addr_value PACKED;
} dlci_IB_mapping_t;
/* This structure is used for DLCI list Tx interrupt mode. It is used to
enable interrupt bit and set the packet length for transmission
*/
-typedef struct fr_dlci_interface
-{
- unsigned char gen_interrupt PACKED;
- unsigned short packet_length PACKED;
- unsigned char reserved PACKED;
-} fr_dlci_interface_t;
+
+typedef struct fr_dlci_interface {
+ unsigned char gen_interrupt PACKED;
+ unsigned short packet_length PACKED;
+ unsigned char reserved PACKED;
+} fr_dlci_interface_t;
static unsigned short num_frames;
static unsigned long curr_trace_addr;
static unsigned long start_trace_addr;
static unsigned short available_buffer_space;
-static char TracingEnabled;
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
+static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */
static int rCount = 0;
-
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
@@ -248,73 +239,63 @@ static int Intr_test_counter;
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, struct device* dev,
- wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, struct device* dev);
-
+static int update(wan_device_t * wandev);
+static int new_if(wan_device_t * wandev, struct device *dev,
+ wanif_conf_t * conf);
+static int del_if(wan_device_t * wandev, struct device *dev);
/* WANPIPE-specific entry points */
-static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data);
-
+static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
/* Network device interface */
-static int if_init (struct device* dev);
-static int if_open (struct device* dev);
-static int if_close (struct device* dev);
-static int if_header (struct sk_buff* skb, struct device* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send (struct sk_buff* skb, struct device* dev);
-static struct enet_statistics* if_stats (struct device* dev);
-
+static int if_init(struct device *dev);
+static int if_open(struct device *dev);
+static int if_close(struct device *dev);
+static int if_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len);
+static int if_rebuild_hdr(struct sk_buff *skb);
+static int if_send(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *if_stats(struct device *dev);
/* Interrupt handlers */
-static void fr502_isr (sdla_t* card);
-static void fr508_isr (sdla_t* card);
-static void fr502_rx_intr (sdla_t* card);
-static void fr508_rx_intr (sdla_t* card);
-static void tx_intr (sdla_t* card);
-static void spur_intr (sdla_t* card);
-
+static void fr502_isr(sdla_t * card);
+static void fr508_isr(sdla_t * card);
+static void fr502_rx_intr(sdla_t * card);
+static void fr508_rx_intr(sdla_t * card);
+static void tx_intr(sdla_t * card);
+static void spur_intr(sdla_t * card);
/* Background polling routines */
-static void wpf_poll (sdla_t* card);
-
+static void wpf_poll(sdla_t * card);
/* Frame relay firmware interface functions */
-static int fr_read_version (sdla_t* card, char* str);
-static int fr_configure (sdla_t* card, fr_conf_t *conf);
-static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci);
-static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu);
-static int fr_comm_enable (sdla_t* card);
-static int fr_comm_disable (sdla_t* card);
-static int fr_get_err_stats (sdla_t* card);
-static int fr_get_stats (sdla_t* card);
-static int fr_add_dlci (sdla_t* card, int dlci, int num);
-static int fr_activate_dlci (sdla_t* card, int dlci, int num);
-static int fr_issue_isf (sdla_t* card, int isf);
-static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf);
-static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf);
-
+static int fr_read_version(sdla_t * card, char *str);
+static int fr_configure(sdla_t * card, fr_conf_t * conf);
+static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci);
+static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu);
+static int fr_comm_enable(sdla_t * card);
+static int fr_comm_disable(sdla_t * card);
+static int fr_get_err_stats(sdla_t * card);
+static int fr_get_stats(sdla_t * card);
+static int fr_add_dlci(sdla_t * card, int dlci, int num);
+static int fr_activate_dlci(sdla_t * card, int dlci, int num);
+static int fr_issue_isf(sdla_t * card, int isf);
+static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf);
+static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf);
/* Firmware asynchronous event handlers */
-static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox);
-static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox);
-static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox);
-
+static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox);
+static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox);
+static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox);
/* Miscellaneous functions */
-static int update_chan_state (struct device* dev);
-static void set_chan_state (struct device* dev, int state);
-static struct device* find_channel (sdla_t* card, unsigned dlci);
-static int is_tx_ready (sdla_t* card, fr_channel_t* chan);
-static unsigned int dec_to_uint (unsigned char* str, int len);
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-
-static int intr_test( sdla_t* card );
-static void init_chan_statistics( fr_channel_t* chan );
-static void init_global_statistics( sdla_t* card );
-static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
-
+static int update_chan_state(struct device *dev);
+static void set_chan_state(struct device *dev, int state);
+static struct device *find_channel(sdla_t * card, unsigned dlci);
+static int is_tx_ready(sdla_t * card, fr_channel_t * chan);
+static unsigned int dec_to_uint(unsigned char *str, int len);
+static int reply_udp(unsigned char *data, unsigned int mbox_len);
+static int intr_test(sdla_t * card);
+static void init_chan_statistics(fr_channel_t * chan);
+static void init_global_statistics(sdla_t * card);
+static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan);
/* Udp management functions */
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan);
-static int udp_pkt_type( struct sk_buff *skb, sdla_t* card );
-
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan);
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
/* IPX functions */
static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number);
@@ -333,15 +314,16 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
* Return: 0 o.k.
* < 0 failure.
*/
-__initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
+int wpf_init(sdla_t * card, wandev_conf_t * conf)
{
union {
char str[80];
fr_conf_t cfg;
} u;
-
+ int i;
/* Verify configuration ID */
- if (conf->config_id != WANCONFIG_FR) {
+ if (conf->config_id != WANCONFIG_FR)
+ {
printk(KERN_INFO "%s: invalid configuration ID %u!\n",
card->devname, conf->config_id);
return -EINVAL;
@@ -355,45 +337,41 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS);
card->isr = &fr502_isr;
break;
-
case SFID_FR508:
card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS);
card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS);
card->isr = &fr508_isr;
break;
-
default:
return -EINVAL;
}
-
/* Read firmware version. Note that when adapter initializes, it
* clears the mailbox, so it may appear that the first command was
* executed successfully when in fact it was merely erased. To work
* around this, we execute the first command twice.
*/
if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
- return -EIO
- ;
+ return -EIO;
printk(KERN_INFO "%s: running frame relay firmware v%s\n",
card->devname, u.str);
-
/* Adjust configuration */
conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
conf->bps = min(conf->bps, 2048000);
-
/* Configure adapter firmware */
memset(&u.cfg, 0, sizeof(u.cfg));
u.cfg.mtu = conf->mtu;
- u.cfg.t391 = 10;
- u.cfg.t392 = 15;
- u.cfg.n391 = 6;
- u.cfg.n392 = 3;
- u.cfg.n393 = 4;
u.cfg.kbps = conf->bps / 1000;
- u.cfg.cir_fwd = 16;
- u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd;
- u.cfg.options = 0x0081; /* direct Rx, no CIR check */
-
+ u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
+ u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
+ if (conf->station == WANOPT_CPE)
+ {
+ u.cfg.options = 0x0080;
+ printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
+ }
+ else
+ {
+ u.cfg.options = 0x0081;
+ }
switch (conf->u.fr.signalling)
{
case WANOPT_FR_Q933:
@@ -403,54 +381,59 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
u.cfg.options |= 0x0400;
break;
}
-
if (conf->station == WANOPT_CPE)
{
u.cfg.options |= 0x8000; /* auto config DLCI */
+ card->u.f.dlci_num = 0;
}
else
{
u.cfg.station = 1; /* switch emulation mode */
- card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16;
+ /* For switch emulation we have to create a list of dlci(s)
+ * that will be sent to be global SET_DLCI_CONFIGURATION
+ * command in fr_configure() routine.
+ */
card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100);
+ for (i = 0; i < card->u.f.dlci_num; i++)
+ {
+ card->u.f.node_dlci[i] = (unsigned short)
+ conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
+ }
}
-
if (conf->clocking == WANOPT_INTERNAL)
- u.cfg.port |= 0x0001
- ;
+ u.cfg.port |= 0x0001;
if (conf->interface == WANOPT_RS232)
- u.cfg.port |= 0x0002
- ;
+ u.cfg.port |= 0x0002;
if (conf->u.fr.t391)
u.cfg.t391 = min(conf->u.fr.t391, 30);
+ else
+ u.cfg.t391 = 5;
if (conf->u.fr.t392)
u.cfg.t392 = min(conf->u.fr.t392, 30);
+ else
+ u.cfg.t392 = 15;
if (conf->u.fr.n391)
u.cfg.n391 = min(conf->u.fr.n391, 255);
+ else
+ u.cfg.n391 = 2;
if (conf->u.fr.n392)
u.cfg.n392 = min(conf->u.fr.n392, 10);
+ else
+ u.cfg.n392 = 3;
if (conf->u.fr.n393)
u.cfg.n393 = min(conf->u.fr.n393, 10);
-
+ else
+ u.cfg.n393 = 4;
if (fr_configure(card, &u.cfg))
- return -EIO
- ;
-
+ return -EIO;
if (card->hw.fwid == SFID_FR508)
{
fr_buf_info_t *buf_info =
(void *) (card->hw.dpmbase + FR508_RXBC_OFFS);
-
- card->rxmb =
- (void *) (buf_info->rse_next -
- FR_MB_VECTOR + card->hw.dpmbase);
- card->u.f.rxmb_base =
- (void *) (buf_info->rse_base -
- FR_MB_VECTOR + card->hw.dpmbase);
- card->u.f.rxmb_last =
- (void *) (buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) -
- FR_MB_VECTOR + card->hw.dpmbase);
+ card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase);
+ card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase);
+ card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) *
+ sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase);
card->u.f.rx_base = buf_info->buf_base;
card->u.f.rx_top = buf_info->buf_top;
}
@@ -465,8 +448,19 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
card->wandev.new_if = &new_if;
card->wandev.del_if = &del_if;
card->wandev.state = WAN_DISCONNECTED;
+ card->wandev.ttl = conf->ttl;
card->wandev.udp_port = conf->udp_port;
- TracingEnabled = '0';
+ card->wandev.enable_tx_int = 0;
+ card->irq_dis_if_send_count = 0;
+ card->irq_dis_poll_count = 0;
+ card->wandev.enable_IPX = conf->enable_IPX;
+ if (conf->network_number)
+ card->wandev.network_number = conf->network_number;
+ else
+ card->wandev.network_number = 0xDEADBEEF;
+ /* Intialize global statistics for a card */
+ init_global_statistics(card);
+ TracingEnabled = 0;
return 0;
}
@@ -475,20 +469,17 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
/*============================================================================
* Update device status & statistics.
*/
+
static int update(wan_device_t * wandev)
{
sdla_t *card;
-
/* sanity checks */
if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT
- ;
+ return -EFAULT;
if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV
- ;
+ return -ENODEV;
if (test_and_set_bit(0, (void *) &wandev->critical))
- return -EAGAIN
- ;
+ return -EAGAIN;
card = wandev->private;
fr_get_err_stats(card);
fr_get_stats(card);
@@ -508,13 +499,14 @@ static int update(wan_device_t * wandev)
* Return: 0 o.k.
* < 0 failure (channel will not be created)
*/
+
static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf)
{
sdla_t *card = wandev->private;
fr_channel_t *chan;
int err = 0;
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
+ if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ))
+ {
printk(KERN_INFO "%s: invalid interface name!\n",
card->devname);
return -EINVAL;
@@ -522,73 +514,67 @@ static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf
/* allocate and initialize private data */
chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
if (chan == NULL)
- return -ENOMEM
- ;
+ return -ENOMEM;
memset(chan, 0, sizeof(fr_channel_t));
strcpy(chan->name, conf->name);
chan->card = card;
-
/* verify media address */
- if (is_digit(conf->addr[0])) {
+ if (is_digit(conf->addr[0]))
+ {
int dlci = dec_to_uint(conf->addr, 0);
-
- if (dlci && (dlci <= 4095)) {
+ if (dlci && (dlci <= 4095))
+ {
chan->dlci = dlci;
- } else {
- printk(KERN_ERR
- "%s: invalid DLCI %u on interface %s!\n",
+ }
+ else
+ {
+ printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n",
wandev->name, dlci, chan->name);
err = -EINVAL;
}
- } else {
- printk(KERN_ERR
- "%s: invalid media address on interface %s!\n",
+ }
+ else
+ {
+ printk(KERN_ERR "%s: invalid media address on interface %s!\n",
wandev->name, chan->name);
err = -EINVAL;
}
- if (err) {
+ if (err)
+ {
kfree(chan);
return err;
}
-
/* place cir,be,bc and other channel specific information into the
* chan structure
- */
+ */
if (conf->cir)
{
- chan->cir = max( 1, min( conf->cir, 512 ) );
- chan->cir_status = CIR_ENABLED;
-
+ chan->cir = max(1, min(conf->cir, 512));
+ chan->cir_status = CIR_ENABLED;
if (conf->bc)
- chan->bc = max( 1, min( conf->bc, 512 ) );
+ chan->bc = max(1, min(conf->bc, 512));
if (conf->be)
- chan->be = max( 0, min( conf->be, 511) );
-
+ chan->be = max(0, min(conf->be, 511));
}
else
chan->cir_status = CIR_DISABLED;
-
chan->mc = conf->mc;
-
- chan->dlci_configured = DLCI_NOT_CONFIGURED;
-
- chan->tx_int_status = DISABLED;
-
- init_chan_statistics( chan );
-
+ chan->dlci_configured = DLCI_NOT_CONFIGURED;
+ chan->tx_int_status = DISABLED;
+ init_chan_statistics(chan);
/* prepare network device data space for registration */
dev->name = chan->name;
dev->init = &if_init;
dev->priv = chan;
return 0;
}
-
/*============================================================================
* Delete logical channel.
*/
static int del_if(wan_device_t * wandev, struct device *dev)
{
- if (dev->priv) {
+ if (dev->priv)
+ {
kfree(dev->priv);
dev->priv = NULL;
}
@@ -606,24 +592,27 @@ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data)
int retry = MAX_CMD_RETRY;
int err, len;
fr_cmd_t cmd;
-
- if (copy_from_user((void *) &cmd, u_cmd, sizeof(cmd)))
- return -EFAULT;
+ if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd)))
+ return -EFAULT;
/* execute command */
- do {
+ do
+ {
memcpy(&mbox->cmd, &cmd, sizeof(cmd));
if (cmd.length)
- if (copy_from_user((void *) &mbox->data, u_data, cmd.length))
+ {
+ if(copy_from_user((void *) &mbox->data, u_data, cmd.length))
return -EFAULT;
+ }
if (sdla_exec(mbox))
err = mbox->cmd.result;
else
return -EIO;
- }
+ }
while (err && retry-- && fr_event(card, err, mbox));
/* return result */
- if (copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t)))
+
+ if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t)))
return -EFAULT;
len = mbox->cmd.length;
if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
@@ -632,7 +621,6 @@ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data)
}
/****** Network Device Interface ********************************************/
-
/*============================================================================
* Initialize Linux network interface.
*
@@ -645,7 +633,6 @@ static int if_init(struct device *dev)
fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
wan_device_t *wandev = &card->wandev;
- int i;
/* Initialize device driver entry points */
dev->open = &if_open;
@@ -654,27 +641,22 @@ static int if_init(struct device *dev)
dev->rebuild_header = &if_rebuild_hdr;
dev->hard_start_xmit = &if_send;
dev->get_stats = &if_stats;
-
/* Initialize media-specific parameters */
- dev->family = AF_INET; /* address family */
- dev->type = ARPHRD_DLCI; /* ARP h/w type */
+ dev->type = ARPHRD_DLCI; /* ARP h/w type */
dev->mtu = FR_CHANNEL_MTU;
- dev->hard_header_len = FR_HEADER_LEN; /* media header length */
- dev->addr_len = 2; /* hardware address length */
+ dev->hard_header_len = FR_HEADER_LEN; /* media header length */
+ dev->addr_len = 2; /* hardware address length */
*(unsigned short *) dev->dev_addr = htons(chan->dlci);
-
/* Initialize hardware parameters (just for reference) */
dev->irq = wandev->irq;
dev->dma = wandev->dma;
dev->base_addr = wandev->ioport;
dev->mem_start = wandev->maddr;
dev->mem_end = wandev->maddr + wandev->msize - 1;
-
/* Set transmit buffer queue length */
- dev->tx_queue_len = 30;
-
+ dev->tx_queue_len = 10;
+ /* Initialize socket buffers */
dev_init_buffers(dev);
-
set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -695,124 +677,93 @@ static int if_open(struct device *dev)
int err = 0;
fr508_flags_t *flags = card->flags;
struct timeval tv;
-
if (dev->start)
return -EBUSY; /* only one open is allowed */
-
if (test_and_set_bit(0, (void *) &card->wandev.critical))
return -EAGAIN;
-
if (!card->open_cnt)
{
Intr_test_counter = 0;
card->intr_mode = INTR_TEST_MODE;
- err = intr_test( card );
-
- if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) {
- printk(KERN_INFO
- "%s: Interrupt Test Failed, Counter: %i\n",
- card->devname, Intr_test_counter);
+ err = intr_test(card);
+ if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
+ printk(KERN_INFO
+ "%s: Interrupt Test Failed, Counter: %i\n",
+ card->devname, Intr_test_counter);
err = -EIO;
card->wandev.critical = 0;
return err;
}
-
printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n"
- ,card->devname, Intr_test_counter);
-
+ ,card->devname, Intr_test_counter);
/* The following allocates and intializes a circular
* link list of interfaces per card.
*/
-
card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL);
if (card->devs_struct == NULL)
- return -ENOMEM;
+ return -ENOMEM;
card->dev_to_devtint_next = card->devs_struct;
-
for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
(card->devs_struct)->dev_ptr = dev2;
- if(dev2->slave == NULL)
+ if (dev2->slave == NULL)
(card->devs_struct)->next = card->dev_to_devtint_next;
else {
(card->devs_struct)->next = kmalloc(
- sizeof(load_sharing_t), GFP_KERNEL);
+ sizeof(load_sharing_t), GFP_KERNEL);
if ((card->devs_struct)->next == NULL)
- return -ENOMEM;
+ return -ENOMEM;
card->devs_struct = (card->devs_struct)->next;
- }
+ }
}
-
card->devs_struct = card->dev_to_devtint_next;
-
- card->intr_mode = BUFFER_INTR_MODE;
-
+ card->intr_mode = BUFFER_INTR_MODE;
/*
- check all the interfaces for the device to see if CIR has
- been enabled for any DLCI(s). If so then use the DLCI list
- Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode
- */
-
+ check all the interfaces for the device to see if CIR has
+ been enabled for any DLCI(s). If so then use the DLCI list
+ Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode
+ */
for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
-
- if( ((fr_channel_t *)dev2->priv)->cir_status
- == CIR_ENABLED) {
+ if (((fr_channel_t *) dev2->priv)->cir_status
+ == CIR_ENABLED) {
card->intr_mode = DLCI_LIST_INTR_MODE;
break;
}
}
-
/*
- * If you enable comms and then set ints, you get a Tx int as you
- * perform the SET_INT_TRIGGERS command. So, we only set int
- * triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms.
+ If you enable comms and then set ints, you get a Tx int as you
+ perform the SET_INT_TRIGGERS command. So, we only set int
+ triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms.
*/
- if (card->intr_mode == BUFFER_INTR_MODE)
- {
- if (fr_set_intr_mode(card, 0x03, card->wandev.mtu))
- {
+ if (card->intr_mode == BUFFER_INTR_MODE) {
+ if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) {
err = -EIO;
card->wandev.critical = 0;
return err;
}
-
- printk( KERN_INFO
- "%s: Global Buffering Tx Interrupt Mode\n"
- , card->devname);
-
- }
- else if (card->intr_mode == DLCI_LIST_INTR_MODE)
- {
- if (fr_set_intr_mode(card, 0x83, card->wandev.mtu))
- {
+ printk(KERN_INFO
+ "%s: Global Buffering Tx Interrupt Mode\n"
+ ,card->devname);
+ } else if (card->intr_mode == DLCI_LIST_INTR_MODE) {
+ if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) {
err = -EIO;
card->wandev.critical = 0;
return err;
}
-
- printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n",
- card->devname);
-
+ printk(KERN_INFO
+ "%s: DLCI list Tx Interrupt Mode\n",
+ card->devname);
}
-
flags->imask &= ~0x02;
-
- if (fr_comm_enable(card))
- {
+ if (fr_comm_enable(card)) {
err = -EIO;
card->wandev.critical = 0;
return err;
- }
-
+ }
wanpipe_set_state(card, WAN_CONNECTED);
-
- if (card->wandev.station == WANOPT_CPE)
- {
+ if (card->wandev.station == WANOPT_CPE) {
/* CPE: issue full status enquiry */
fr_issue_isf(card, FR_ISF_FSE);
- }
- else
- { /* FR switch: activate DLCI(s) */
-
+ } else { /* FR switch: activate DLCI(s) */
/* For Switch emulation we have to ADD and ACTIVATE
* the DLCI(s) that were configured with the SET_DLCI_
* CONFIGURATION command. Add and Activate will fail if
@@ -820,12 +771,13 @@ static int if_open(struct device *dev)
*
* Also If_open is called once for each interface. But
* it does not get in here for all the interface. So
- * we have to pass the entire list of DLCI(s) to add
+ * we have to pass the entire list of DLCI(s) to add
* activate routines.
- */
-
- fr_add_dlci(card, card->u.f.node_dlci[0], card->u.f.dlci_num);
- fr_activate_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num);
+ */
+ fr_add_dlci(card,
+ card->u.f.node_dlci[0], card->u.f.dlci_num);
+ fr_activate_dlci(card,
+ card->u.f.node_dlci[0], card->u.f.dlci_num);
}
}
dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
@@ -834,8 +786,7 @@ static int if_open(struct device *dev)
dev->start = 1;
wanpipe_open(card);
update_chan_state(dev);
-
- do_gettimeofday( &tv );
+ do_gettimeofday(&tv);
chan->router_start_time = tv.tv_sec;
card->wandev.critical = 0;
return err;
@@ -846,17 +797,17 @@ static int if_open(struct device *dev)
* o if this is the last open, then disable communications and interrupts.
* o reset flags.
*/
+
static int if_close(struct device *dev)
{
fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
-
if (test_and_set_bit(0, (void *) &card->wandev.critical))
return -EAGAIN;
- ;
dev->start = 0;
wanpipe_close(card);
- if (!card->open_cnt) {
+ if (!card->open_cnt)
+ {
wanpipe_set_state(card, WAN_DISCONNECTED);
fr_set_intr_mode(card, 0, 0);
fr_comm_disable(card);
@@ -875,14 +826,15 @@ static int if_close(struct device *dev)
*
* Return: media header length.
*/
+
static int if_header(struct sk_buff *skb, struct device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
int hdr_len = 0;
-
skb->protocol = type;
hdr_len = wan_encapsulate(skb, dev);
- if (hdr_len < 0) {
+ if (hdr_len < 0)
+ {
hdr_len = 0;
skb->protocol = 0;
}
@@ -898,13 +850,14 @@ static int if_header(struct sk_buff *skb, struct device *dev,
* Return: 1 physical address resolved.
* 0 physical address not resolved
*/
+
static int if_rebuild_hdr(struct sk_buff *skb)
{
- fr_channel_t *chan = skb->dev->priv;
+ struct device *dev=skb->dev;
+ fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
-
printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, skb->dev->name);
+ card->devname, dev->name);
return 1;
}
@@ -926,80 +879,101 @@ static int if_rebuild_hdr(struct sk_buff *skb)
* 2. Setting tbusy flag will inhibit further transmit requests from the
* protocol stack and can be used for flow control with protocol layer.
*/
+
static int if_send(struct sk_buff *skb, struct device *dev)
{
fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
int retry = 0, err;
+ unsigned char *sendpacket;
struct device *dev2;
- fr508_flags_t* adptr_flags = card->flags;
- fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+ unsigned long check_braddr, check_mcaddr;
+ fr508_flags_t *adptr_flags = card->flags;
+ int udp_type, send_data;
+ fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface;
unsigned long host_cpu_flags;
- int send_data = 0;
- ++chan->if_send_entry;
+ ++chan->if_send_entry;
- if (dev->tbusy)
- {
+ if (dev->tbusy)
+ {
/* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this * is only used as a last resort.
- */
-
+ * kick start the device by making dev->tbusy = 0. We expect
+ * that our device never stays busy more than 5 seconds. So this * is only used as a last resort.
+ */
++chan->if_send_busy;
++chan->ifstats.collisions;
-
- if ((jiffies - chan->tick_counter) < (5*HZ))
+ if ((jiffies - chan->tick_counter) < (5 * HZ))
return 1;
printk(KERN_INFO "%s: Transmit timed out\n", chan->name);
-
++chan->if_send_busy_timeout;
-
/* unbusy all the interfaces on the card */
- for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
dev2->tbusy = 0;
- }
-
- if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: if_send() hit critical section!\n",
- card->devname);
-#endif
+ }
+ sendpacket = skb->data;
+ udp_type = udp_pkt_type(skb, card);
+ if (udp_type == UDP_DRVSTATS_TYPE)
+ {
+ ++chan->if_send_DRVSTATS_request;
+ process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0,
+ chan);
dev_kfree_skb(skb);
return 0;
}
- disable_irq(card->hw.irq);
+ else if (udp_type == UDP_FPIPE_TYPE)
+ ++chan->if_send_FPIPE_request;
+ /* retreive source address in two forms: broadcast & multicast */
+ check_braddr = sendpacket[17];
+ check_mcaddr = sendpacket[14];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[16];
+ check_mcaddr |= sendpacket[15];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[15];
+ check_mcaddr |= sendpacket[16];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[14];
+ check_mcaddr |= sendpacket[17];
+ /* if the Source Address is a Multicast address */
+ if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) &&
+ (check_mcaddr <= 0xFFFFFFFE))
+ {
+ printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n"
+ ,card->devname);
+ dev_kfree_skb(skb);
+ ++chan->ifstats.tx_dropped;
+ ++chan->if_send_multicast;
+ return 0;
+ }
+ disable_irq(card->hw.irq);
++card->irq_dis_if_send_count;
-
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void *) &card->wandev.critical))
{
if (card->wandev.critical == CRITICAL_IN_ISR)
- {
+ {
++chan->if_send_critical_ISR;
-
- if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
{
/* The enable_tx_int flag is set here so that if
- * the critical flag is set due to an interrupt
+ * the critical flag is set due to an interrupt
* then we want to enable transmit interrupts
* again.
- */
-
+ */
card->wandev.enable_tx_int = 1;
-
/* Setting this flag to WAITING_TO_BE_ENABLED
* specifies that interrupt bit has to be
* enabled for that particular interface.
* (delayed interrupt)
- */
-
+ */
chan->tx_int_status = WAITING_TO_BE_ENABLED;
-
/* This is used for enabling dynamic calculation
* of CIRs relative to the packet length.
- */
-
- chan->pkt_length = skb->len;
+ */
+ chan->pkt_length = skb->len;
dev->tbusy = 1;
chan->tick_counter = jiffies;
}
@@ -1011,34 +985,36 @@ static int if_send(struct sk_buff *skb, struct device *dev)
}
save_flags(host_cpu_flags);
cli();
- if ((!(--card->irq_dis_if_send_count)) &&
- (!card->irq_dis_poll_count))
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
return 1;
}
-
++chan->if_send_critical_non_ISR;
++chan->ifstats.tx_dropped;
dev_kfree_skb(skb);
save_flags(host_cpu_flags);
cli();
- if ((!(--card->irq_dis_if_send_count)) &&
- (!card->irq_dis_poll_count))
- enable_irq(card->hw.irq);
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
return 0;
}
-
card->wandev.critical = 0x21;
-
- if (card->wandev.state != WAN_CONNECTED)
+ if (udp_type == UDP_FPIPE_TYPE)
+ {
+ err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
+ dev, 0, chan);
+ }
+ else if (card->wandev.state != WAN_CONNECTED)
{
++chan->if_send_wan_disconnected;
++chan->ifstats.tx_dropped;
++card->wandev.stats.tx_dropped;
}
- else if (chan->state != WAN_CONNECTED)
+ else if (chan->state != WAN_CONNECTED)
{
++chan->if_send_dlci_disconnected;
update_chan_state(dev);
@@ -1047,313 +1023,361 @@ static int if_send(struct sk_buff *skb, struct device *dev)
}
else if (!is_tx_ready(card, chan))
{
- if (card->intr_mode == DLCI_LIST_INTR_MODE )
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
{
dlci_interface->gen_interrupt |= 0x40;
- dlci_interface->packet_length = skb->len;
- }
- dev->tbusy = 1;
+ dlci_interface->packet_length = skb->len;
+ }
+ dev->tbusy = 1;
chan->tick_counter = jiffies;
-
adptr_flags->imask |= 0x02;
-
- ++ chan->if_send_no_bfrs;
+ ++chan->if_send_no_bfrs;
retry = 1;
}
- else
+ else
{
send_data = 1;
/* If it's an IPX packet */
- if( sendpacket[1] == 0x00 &&
+ if (sendpacket[1] == 0x00 &&
sendpacket[2] == 0x80 &&
sendpacket[6] == 0x81 &&
sendpacket[7] == 0x37)
{
- if( card->wandev.enable_IPX )
+ if (card->wandev.enable_IPX)
{
- switch_net_numbers(sendpacket,
- card->wandev.network_number, 0);
- }
- else
+ switch_net_numbers(sendpacket,
+ card->wandev.network_number, 0);
+ }
+ else
{
/* increment some statistic here! */
send_data = 0;
}
}
-
- if (send_data)
+ if (send_data)
{
- err = (card->hw.fwid == SFID_FR508) ?
- fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
- fr502_send(card, chan->dlci, 0, skb->len, skb->data);
-
+ err = (card->hw.fwid == SFID_FR508) ?
+ fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
+ fr502_send(card, chan->dlci, 0, skb->len, skb->data);
if (err)
{
if (card->intr_mode == DLCI_LIST_INTR_MODE)
{
dlci_interface->gen_interrupt |= 0x40;
- dlci_interface->packet_length = skb->len;
- }
- dev->tbusy = 1;
+ dlci_interface->packet_length = skb->len;
+ }
+ dev->tbusy = 1;
chan->tick_counter = jiffies;
- adptr_flags->imask |= 0x02;
+ adptr_flags->imask |= 0x02;
retry = 1;
- ++ chan->if_send_adptr_bfrs_full;
- ++ chan->ifstats.tx_errors;
- ++ card->wandev.stats.tx_errors;
- }
- else
+ ++chan->if_send_adptr_bfrs_full;
+ ++chan->ifstats.tx_errors;
+ ++card->wandev.stats.tx_errors;
+ }
+ else
{
- ++ chan->if_send_bfrs_passed_to_adptr;
+ ++chan->if_send_bfrs_passed_to_adptr;
++chan->ifstats.tx_packets;
++card->wandev.stats.tx_packets;
}
}
}
-
if (!retry)
dev_kfree_skb(skb);
card->wandev.critical = 0;
save_flags(host_cpu_flags);
cli();
- if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
- enable_irq(card->hw.irq);
+ if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
return retry;
}
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return nothing.
+ */
+
+static int reply_udp(unsigned char *data, unsigned int mbox_len)
+{
+ unsigned short len, udp_length, temp, i, ip_length;
+ unsigned long sum;
+ /* Set length of packet */
+ len = mbox_len + 62;
+ /* fill in UDP reply */
+ data[38] = 0x02;
+ /* fill in UDP length */
+ udp_length = mbox_len + 40;
+ /* put it on an even boundary */
+ if (udp_length & 0x0001)
+ {
+ udp_length += 1;
+ len += 1;
+ }
+ temp = (udp_length << 8) | (udp_length >> 8);
+ memcpy(&data[26], &temp, 2);
+ /* swap UDP ports */
+ memcpy(&temp, &data[22], 2);
+ memcpy(&data[22], &data[24], 2);
+ memcpy(&data[24], &temp, 2);
+ /* add UDP pseudo header */
+ temp = 0x1100;
+ memcpy(&data[udp_length + 22], &temp, 2);
+ temp = (udp_length << 8) | (udp_length >> 8);
+ memcpy(&data[udp_length + 24], &temp, 2);
+ /* calculate UDP checksum */
+ data[28] = data[29] = 0;
+ sum = 0;
+ for (i = 0; i < udp_length + 12; i += 2)
+ {
+ memcpy(&temp, &data[14 + i], 2);
+ sum += (unsigned long) temp;
+ }
+ while (sum >> 16)
+ sum = (sum & 0xffffUL) + (sum >> 16);
+
+ temp = (unsigned short) sum;
+ temp = ~temp;
+ if (temp == 0)
+ temp = 0xffff;
+ memcpy(&data[28], &temp, 2);
+ /* fill in IP length */
+ ip_length = udp_length + 20;
+ temp = (ip_length << 8) | (ip_length >> 8);
+ memcpy(&data[4], &temp, 2);
+ /* swap IP addresses */
+ memcpy(&temp, &data[14], 2);
+ memcpy(&data[14], &data[18], 2);
+ memcpy(&data[18], &temp, 2);
+ memcpy(&temp, &data[16], 2);
+ memcpy(&data[16], &data[20], 2);
+ memcpy(&data[20], &temp, 2);
+ /* fill in IP checksum */
+ data[12] = data[13] = 0;
+ sum = 0;
+ for (i = 0; i < 20; i += 2)
+ {
+ memcpy(&temp, &data[2 + i], 2);
+ sum += (unsigned long) temp;
+ }
+ while (sum >> 16)
+ sum = (sum & 0xffffUL) + (sum >> 16);
+ temp = (unsigned short) sum;
+ temp = ~temp;
+ if (temp == 0)
+ temp = 0xffff;
+ memcpy(&data[12], &temp, 2);
+ return len;
+} /* reply_udp */
/*
- * If incoming is 0 (outgoing)- if the net numbers is ours make it 0
- * if incoming is 1 - if the net number is 0 make it ours
- *
+ If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+ if incoming is 1 - if the net number is 0 make it ours
*/
-
+
static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
{
unsigned long pnetwork_number;
-
- pnetwork_number = (unsigned long)((sendpacket[14] << 24) +
- (sendpacket[15] << 16) + (sendpacket[16] << 8) +
- sendpacket[17]);
-
+ pnetwork_number = (unsigned long) ((sendpacket[14] << 24) +
+ (sendpacket[15] << 16) + (sendpacket[16] << 8) +
+ sendpacket[17]);
if (!incoming) {
- if( pnetwork_number == network_number) {
- sendpacket[14] = sendpacket[15] = sendpacket[16] =
- sendpacket[17] = 0x00;
+ /* If the destination network number is ours, make it 0 */
+ if (pnetwork_number == network_number) {
+ sendpacket[14] = sendpacket[15] = sendpacket[16] =
+ sendpacket[17] = 0x00;
}
} else {
- if( pnetwork_number == 0) {
- sendpacket[14] = (unsigned char)(network_number >> 24);
- sendpacket[15] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[16] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[17] = (unsigned char)(network_number &
- 0x000000FF);
+ /* If the incoming network is 0, make it ours */
+ if (pnetwork_number == 0)
+ {
+ sendpacket[14] = (unsigned char) (network_number >> 24);
+ sendpacket[15] = (unsigned char) ((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[16] = (unsigned char) ((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[17] = (unsigned char) (network_number &
+ 0x000000FF);
}
}
-
-
- pnetwork_number = (unsigned long)((sendpacket[26] << 24) +
- (sendpacket[27] << 16) + (sendpacket[28] << 8) +
- sendpacket[29]);
-
- if( !incoming ) {
- if( pnetwork_number == network_number) {
- sendpacket[26] = sendpacket[27] = sendpacket[28] =
- sendpacket[29] = 0x00;
+ pnetwork_number = (unsigned long) ((sendpacket[26] << 24) +
+ (sendpacket[27] << 16) + (sendpacket[28] << 8) +
+ sendpacket[29]);
+ if (!incoming) {
+ /* If the source network is ours, make it 0 */
+ if (pnetwork_number == network_number)
+ {
+ sendpacket[26] = sendpacket[27] = sendpacket[28] =
+ sendpacket[29] = 0x00;
}
} else {
- if( pnetwork_number == 0 ) {
- sendpacket[26] = (unsigned char)(network_number >> 24);
- sendpacket[27] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[28] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[29] = (unsigned char)(network_number &
- 0x000000FF);
+ /* If the source network is 0, make it ours */
+ if (pnetwork_number == 0) {
+ sendpacket[26] = (unsigned char) (network_number >> 24);
+ sendpacket[27] = (unsigned char) ((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[28] = (unsigned char) ((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[29] = (unsigned char) (network_number &
+ 0x000000FF);
}
}
-} /* switch_net_numbers */
-
+} /* switch_net_numbers */
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
+
static struct net_device_stats *if_stats(struct device *dev)
{
fr_channel_t *chan = dev->priv;
-
return &chan->ifstats;
}
/****** Interrupt Handlers **************************************************/
-
/*============================================================================
* S502 frame relay interrupt service routine.
*/
+
static void fr502_isr(sdla_t * card)
{
fr502_flags_t *flags = card->flags;
-
switch (flags->iflag)
{
case 0x01: /* receive interrupt */
fr502_rx_intr(card);
break;
-
case 0x02: /* transmit interrupt */
flags->imask &= ~0x02;
tx_intr(card);
break;
-
default:
spur_intr(card);
}
flags->iflag = 0;
}
-
/*============================================================================
* S508 frame relay interrupt service routine.
*/
+
static void fr508_isr(sdla_t * card)
{
fr508_flags_t *flags = card->flags;
fr_buf_ctl_t *bctl;
char *ptr = &flags->iflag;
- struct device* dev = card->wandev.dev;
- struct device* dev2;
+ struct device *dev = card->wandev.dev;
+ struct device *dev2;
int i;
unsigned long host_cpu_flags;
- unsigned disable_tx_intr =1;
- fr_channel_t* chan;
- fr_dlci_interface_t* dlci_interface;
-
+ unsigned disable_tx_intr = 1;
+ fr_channel_t *chan;
+ fr_dlci_interface_t *dlci_interface;
/* This flag prevents nesting of interrupts. See sdla_isr() routine
- * in sdlamain.c.
+ * in sdlamain.c.
*/
card->in_isr = 1;
-
++card->statistics.isr_entry;
-
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void *) &card->wandev.critical))
{
- printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
+ printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
++card->statistics.isr_already_critical;
card->in_isr = 0;
return;
}
- int_occur = 1;
-
/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
- * If the if_send routine is called with this flag set it will set
- * the enable transmit flag to 1. (for a delayed interrupt)
- */
+ * If the if_send routine is called with this flag set it will set
+ * the enable transmit flag to 1. (for a delayed interrupt)
+ */
card->wandev.critical = CRITICAL_IN_ISR;
-
card->dlci_int_mode_unbusy = 0;
- card->buff_int_mode_unbusy = 0;
-
- switch (flags->iflag) {
- case 0x01: /* receive interrupt */
- ++card->statistics.isr_rx;
- fr508_rx_intr(card);
- break;
-
- case 0x02: /* transmit interrupt */
- ++card->statistics.isr_tx;
- bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
- card->hw.dpmbase);
+ card->buff_int_mode_unbusy = 0;
+ switch (flags->iflag)
+ {
+ case 0x01: /* receive interrupt */
+ ++card->statistics.isr_rx;
+ fr508_rx_intr(card);
+ break;
+ case 0x02: /* transmit interrupt */
+ ++card->statistics.isr_tx;
+ bctl = (void *) (flags->tse_offs - FR_MB_VECTOR +
+ card->hw.dpmbase);
bctl->flag = 0xA0;
-
- if (card->intr_mode == DLCI_LIST_INTR_MODE )
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
{
/* Find the structure and make it unbusy */
- dev = find_channel( card, flags->dlci);
+ dev = find_channel(card, flags->dlci);
dev->tbusy = 0;
-
/* This is used to perform devtint at the
* end of the isr
*/
card->dlci_int_mode_unbusy = 1;
-
/* check to see if any other interfaces are
* busy. If so then do not disable the tx
* interrupts
- */
- for (dev2 = card->wandev.dev; dev2;
- dev2 = dev2->slave)
+ */
+ for (dev2 = card->wandev.dev; dev2;
+ dev2 = dev2->slave)
{
- if ( dev2->tbusy == 1)
+ if (dev2->tbusy == 1)
{
disable_tx_intr = 0;
break;
- }
+ }
}
if (disable_tx_intr)
flags->imask &= ~0x02;
-
- }
+ }
else if (card->intr_mode == BUFFER_INTR_MODE)
{
- for (dev2 = card->wandev.dev; dev2;
- dev2 = dev2->slave)
+ for (dev2 = card->wandev.dev; dev2;
+ dev2 = dev2->slave)
{
- if ( !dev2 || !dev2->start )
+ if (!dev2 || !dev2->start)
{
- ++card->statistics.
- tx_intr_dev_not_started;
+ ++card->statistics.tx_intr_dev_not_started;
continue;
}
- if(dev2->tbusy)
+ if (dev2->tbusy)
{
card->buff_int_mode_unbusy = 1;
- ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 1;
+ ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1;
dev2->tbusy = 0;
- } else
- ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 0;
+ }
+ else
+ ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0;
}
- flags->imask &= ~0x02;
+ flags->imask &= ~0x02;
}
- break;
-
+ break;
case 0x08:
- Intr_test_counter++;
+ Intr_test_counter++;
++card->statistics.isr_intr_test;
- break;
-
+ break;
default:
- ++card->statistics.isr_spurious;
- spur_intr(card);
- printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
- card->devname, flags->iflag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
+ ++card->statistics.isr_spurious;
+ spur_intr(card);
+ printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
+ card->devname, flags->iflag);
+ printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+ for (i = 0; i < 8; i++)
printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
-
+ printk(KERN_INFO "\n");
break;
- }
-
+ }
card->wandev.critical = CRITICAL_INTR_HANDLED;
if (card->wandev.enable_tx_int)
{
- if( card->intr_mode == DLCI_LIST_INTR_MODE )
- {
- for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ {
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
{
- chan = dev2->priv;
- if ( chan->tx_int_status ==
- WAITING_TO_BE_ENABLED )
+ chan = dev2->priv;
+ if (chan->tx_int_status == WAITING_TO_BE_ENABLED)
{
- dlci_interface =
- chan->dlci_int_interface;
+ dlci_interface = chan->dlci_int_interface;
dlci_interface->gen_interrupt |= 0x40;
- dlci_interface->packet_length =
- chan->pkt_length;
+ dlci_interface->packet_length = chan->pkt_length;
chan->tx_int_status = DISABLED;
}
}
@@ -1361,7 +1385,7 @@ static void fr508_isr(sdla_t * card)
card->wandev.enable_tx_int = 0;
flags->imask |= 0x02;
++card->statistics.isr_enable_tx_int;
- }
+ }
save_flags(host_cpu_flags);
cli();
card->in_isr = 0;
@@ -1369,35 +1393,30 @@ static void fr508_isr(sdla_t * card)
flags->iflag = 0;
card->wandev.critical = 0;
restore_flags(host_cpu_flags);
-
- /*
- * Device is now ready to send. The instant this is executed the If_Send
- * routine is called. That is why this is put at the bottom of the ISR
- * to prevent a endless loop condition caused by repeated Interrupts and
- * enable_tx_int flag.
+ /* Device is now ready to send. The instant this is executed the If_Send
+ routine is called. That is why this is put at the bottom of the ISR
+ to prevent a endless loop condition caused by repeated Interrupts and
+ enable_tx_int flag.
*/
-
- if(card->dlci_int_mode_unbusy)
- dev_tint(dev);
-
- if(card->buff_int_mode_unbusy)
+ if (card->dlci_int_mode_unbusy)
+ mark_bh(NET_BH);
+ if (card->buff_int_mode_unbusy)
{
for (;;)
{
- if (((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1){
-
- ((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint=0;
- dev_tint((card->devs_struct)->dev_ptr);
+ if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1)
+ {
+ ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0;
+ mark_bh(NET_BH);
}
if ((card->devs_struct)->next == card->dev_to_devtint_next)
break;
card->devs_struct = (card->devs_struct)->next;
}
card->devs_struct = (card->dev_to_devtint_next)->next;
- card->dev_to_devtint_next = card->devs_struct;
+ card->dev_to_devtint_next = card->devs_struct;
}
}
-
/*============================================================================
* Receive interrupt handler.
*/
@@ -1410,28 +1429,31 @@ static void fr502_rx_intr(sdla_t * card)
fr_channel_t *chan;
unsigned dlci, len;
void *buf;
-
+ unsigned char *sendpacket;
+ unsigned char buf2[3];
+ int udp_type;
sdla_mapmem(&card->hw, FR502_RX_VECTOR);
-
dlci = mbox->cmd.dlci;
len = mbox->cmd.length;
-
/* Find network interface for this packet */
dev = find_channel(card, dlci);
- if (dev == NULL) {
+ if (dev == NULL)
+ {
/* Invalid channel, discard packet */
printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
card->devname, dlci);
sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
chan = dev->priv;
- if (!dev->start) {
+ if (!dev->start)
+ {
++chan->ifstats.rx_dropped;
sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
/* Allocate socket buffer */
skb = dev_alloc_skb(len);
- if (skb == NULL) {
+ if (skb == NULL)
+ {
printk(KERN_INFO "%s: no socket buffers available!\n",
card->devname);
++chan->ifstats.rx_dropped;
@@ -1441,26 +1463,50 @@ static void fr502_rx_intr(sdla_t * card)
buf = skb_put(skb, len);
memcpy(buf, mbox->data, len);
sdla_mapmem(&card->hw, FR_MB_VECTOR);
-
- /* Decapsulate packet and pass it up the protocol stack */
- skb->dev = dev;
- buf = skb_pull(skb, 1); /* remove hardware header */
- if (!wan_type_trans(skb, dev)) {
- /* can't decapsulate packet */
- dev_kfree_skb(skb);
- ++chan->ifstats.rx_errors;
- ++card->wandev.stats.rx_errors;
- } else {
- netif_rx(skb);
- ++chan->ifstats.rx_packets;
- ++card->wandev.stats.rx_packets;
+ /* Check if it's a UDP management packet */
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ udp_type = udp_pkt_type(skb, card);
+ if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE))
+ {
+ if (udp_type == UDP_DRVSTATS_TYPE)
+ {
+ ++chan->rx_intr_DRVSTATS_request;
+ process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb,
+ dev, dlci, chan);
+ }
+ else
+ {
+ ++chan->rx_intr_FPIPE_request;
+ process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb,
+ dev, dlci, chan);
+ }
+ }
+ else
+ {
+ /* Decapsulate packet and pass it up the protocol stack */
+ skb->dev = dev;
+ buf = skb_pull(skb, 1); /* remove hardware header */
+ if (!wan_type_trans(skb, dev))
+ {
+ /* can't decapsulate packet */
+ dev_kfree_skb(skb);
+ ++chan->ifstats.rx_errors;
+ ++card->wandev.stats.rx_errors;
+ }
+ else
+ {
+ netif_rx(skb);
+ ++chan->ifstats.rx_packets;
+ ++card->wandev.stats.rx_packets;
+ }
}
sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
-
/*============================================================================
* Receive interrupt handler.
*/
+
static void fr508_rx_intr(sdla_t * card)
{
fr_buf_ctl_t *frbuf = card->rxmb;
@@ -1470,134 +1516,127 @@ static void fr508_rx_intr(sdla_t * card)
unsigned dlci, len, offs;
void *buf;
unsigned rx_count = 0;
- fr508_flags_t* flags = card->flags;
+ fr508_flags_t *flags = card->flags;
char *ptr = &flags->iflag;
- int i, err;
-
- if (frbuf->flag != 0x01) {
- printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
- card->devname, (unsigned) frbuf);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
+ int i, err, udp_type;
+ if (frbuf->flag != 0x01)
+ {
+ printk(KERN_INFO
+ "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
+ card->devname, (unsigned) frbuf, frbuf->flag);
+ printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+ for (i = 0; i < 8; i++)
printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
printk(KERN_INFO "\n");
-
++card->statistics.rx_intr_corrupt_rx_bfr;
return;
}
-
- do
+
+ do
{
- len = frbuf->length;
+ len = frbuf->length;
dlci = frbuf->dlci;
offs = frbuf->offset;
-
/* Find network interface for this packet */
dev = find_channel(card, dlci);
chan = dev->priv;
-
if (dev == NULL)
{
/* Invalid channel, discard packet */
printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n"
- , card->devname, dlci);
- ++card->statistics.rx_intr_on_orphaned_DLCI;
- }
+ ,card->devname, dlci);
+ ++card->statistics.rx_intr_on_orphaned_DLCI;
+ }
else
{
- skb = dev_alloc_skb(len);
- if (!dev->start || (skb == NULL))
- {
+ skb = dev_alloc_skb(len);
+ if (!dev->start || (skb == NULL))
+ {
++chan->ifstats.rx_dropped;
- if(dev->start)
+ if (dev->start)
{
- printk(KERN_INFO
- "%s: no socket buffers available!\n",
- card->devname);
- ++chan->rx_intr_no_socket;
-
- }
- else
- ++ chan->rx_intr_dev_not_started;
- }
+ printk(KERN_INFO
+ "%s: no socket buffers available!\n",
+ card->devname);
+ ++chan->rx_intr_no_socket;
+ } else
+ ++chan->rx_intr_dev_not_started;
+ }
else
{
/* Copy data to the socket buffer */
if ((offs + len) > card->u.f.rx_top + 1)
{
- unsigned tmp = card->u.f.rx_top -
- offs + 1;
-
+ unsigned tmp = card->u.f.rx_top - offs + 1;
buf = skb_put(skb, tmp);
sdla_peek(&card->hw, offs, buf, tmp);
offs = card->u.f.rx_base;
- len -= tmp;
- }
-
+ len -= tmp;
+ }
buf = skb_put(skb, len);
sdla_peek(&card->hw, offs, buf, len);
-#ifdef CONFIG_SANGOMA_MANAGER
- if (management_check(skb,card))
+ udp_type = udp_pkt_type(skb, card);
+ if (udp_type == UDP_DRVSTATS_TYPE)
{
++chan->rx_intr_DRVSTATS_request;
- }
- else
-#endif
- if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number))
+ process_udp_driver_call(
+ UDP_PKT_FRM_NETWORK, card, skb,
+ dev, dlci, chan);
+ }
+ else if (udp_type == UDP_FPIPE_TYPE)
+ {
+ ++chan->rx_intr_FPIPE_request;
+ err = process_udp_mgmt_pkt(
+ UDP_PKT_FRM_NETWORK, card,
+ skb, dev, dlci, chan);
+ }
+ else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number))
{
if (card->wandev.enable_IPX)
- {
fr508_send(card, dlci, 0, skb->len, skb->data);
- } else {
- /* increment some statistic! */
- }
- }
- else
+ }
+ else
{
- /* Decapsulate packet and pass it up the
- protocol stack */
+ /* Decapsulate packet and pass it up the
+ protocol stack */
skb->dev = dev;
-
/* remove hardware header */
- buf = skb_pull(skb, 1);
-
+ buf = skb_pull(skb, 1);
if (!wan_type_trans(skb, dev))
{
/* can't decapsulate packet */
dev_kfree_skb(skb);
- ++chan->rx_intr_bfr_not_passed_to_stack;
- ++chan->ifstats.rx_errors;
- ++card->wandev.stats.rx_errors;
+ ++chan->
+ rx_intr_bfr_not_passed_to_stack;
+ ++chan->
+ ifstats.rx_errors;
+ ++card->
+ wandev.stats.rx_errors;
}
else
{
netif_rx(skb);
- ++ chan->rx_intr_bfr_passed_to_stack;
- ++ chan->ifstats.rx_packets;
- ++ card->wandev.stats.rx_packets;
+ ++chan->rx_intr_bfr_passed_to_stack;
+ ++chan->ifstats.rx_packets;
+ ++card->wandev.stats.rx_packets;
}
- }
- }
- }
-
- /* Release buffer element and calculate a pointer to the next
+ }
+ }
+ }
+ /* Release buffer element and calculate a pointer to the next
one */
- frbuf->flag = 0;
+ frbuf->flag = 0;
card->rxmb = ++frbuf;
-
- if ((void*)frbuf > card->u.f.rxmb_last)
+ if ((void *) frbuf > card->u.f.rxmb_last)
card->rxmb = card->u.f.rxmb_base;
-
/* The loop put in is temporary, that is why the break is
- * placed here. (?????)
+ * placed here. (?????)
*/
break;
-
- frbuf = card->rxmb;
-
- } while (frbuf->flag && ((++ rx_count) < 4));
+ frbuf = card->rxmb;
+ }
+ while (frbuf->flag && ((++rx_count) < 4));
}
-
/*============================================================================
* Transmit interrupt handler.
* o print a warning
@@ -1607,25 +1646,23 @@ static void fr508_rx_intr(sdla_t * card)
static void tx_intr(sdla_t * card)
{
struct device *dev = card->wandev.dev;
-
if (card->intr_mode == BUFFER_INTR_MODE)
- {
+ {
for (; dev; dev = dev->slave)
{
- if ( !dev || !dev->start )
- {
- ++ card->statistics.tx_intr_dev_not_started;
+ if (!dev || !dev->start)
+ {
+ ++card->statistics.tx_intr_dev_not_started;
continue;
}
-
dev->tbusy = 0;
- dev_tint(dev);
+ mark_bh(NET_BH);
}
}
else
{
dev->tbusy = 0;
- dev_tint(dev);
+ mark_bh(NET_BH);
}
}
@@ -1635,70 +1672,75 @@ static void tx_intr(sdla_t * card)
* o
* If number of spurious interrupts exceeded some limit, then ???
*/
+
static void spur_intr(sdla_t * card)
{
printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
}
/*
- Return 0 for non-IPXWAN packet
- 1 for IPXWAN packet or IPX is not enabled!
-
-*/
+ Return 0 for non-IPXWAN packet
+ 1 for IPXWAN packet or IPX is not enabled!
+ */
static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
{
int i;
-
- if( sendpacket[1] == 0x00 &&
+ if (sendpacket[1] == 0x00 &&
sendpacket[2] == 0x80 &&
sendpacket[6] == 0x81 &&
- sendpacket[7] == 0x37) {
-
- if(!enable_IPX) {
+ sendpacket[7] == 0x37)
+ {
+ /* It's an IPX packet */
+ if (!enable_IPX) {
+ /* Return 1 so we don't pass it up the stack. */
return 1;
}
- } else {
+ }
+ else
+ {
+ /* It's not IPX so return and pass it up the stack. */
return 0;
}
-
- if( sendpacket[24] == 0x90 &&
- sendpacket[25] == 0x04)
+ if (sendpacket[24] == 0x90 &&
+ sendpacket[25] == 0x04)
{
- if( sendpacket[10] == 0x02 &&
- sendpacket[42] == 0x00)
+ /* It's IPXWAN */
+ if (sendpacket[10] == 0x02 &&
+ sendpacket[42] == 0x00)
{
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
-
- for(i = 49; sendpacket[i] == 0x00; i += 5)
+ /* It's a timer request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
+ /* Go through the routing options and answer no to every */
+ /* option except Unnumbered RIP/SAP */
+ for (i = 49; sendpacket[i] == 0x00; i += 5)
{
- if( sendpacket[i + 4] != 0x02)
+ /* 0x02 is the option for Unnumbered RIP/SAP */
+ if (sendpacket[i + 4] != 0x02)
{
sendpacket[i + 1] = 0;
}
}
-
- if( sendpacket[i] == 0x04 )
- {
+ /* Skip over the extended Node ID option */
+ if (sendpacket[i] == 0x04)
i += 8;
- }
-
- for(; sendpacket[i] == 0x80 ;)
+ /* We also want to turn off all header compression opt. */
+ for (; sendpacket[i] == 0x80;)
{
sendpacket[i + 1] = 0;
i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
}
-
+ /* Set the packet type to timer response */
sendpacket[42] = 0x01;
-
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
}
- else if( sendpacket[42] == 0x02 )
+ else if (sendpacket[42] == 0x02)
{
- printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
-
+ /* This is an information request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
+ /* Set the packet type to information response */
sendpacket[42] = 0x03;
-
+ /* Set the router name */
sendpacket[59] = 'F';
sendpacket[60] = 'P';
sendpacket[61] = 'I';
@@ -1706,39 +1748,35 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
sendpacket[63] = 'E';
sendpacket[64] = '-';
sendpacket[65] = CVHexToAscii(network_number >> 28);
- sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+ sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24);
+ sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20);
+ sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16);
+ sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12);
+ sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8);
+ sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4);
sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 73; i < 107; i+= 1)
- {
+ for (i = 73; i < 107; i += 1)
sendpacket[i] = 0;
- }
-
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
}
else
{
- printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
+ printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
return 0;
}
-
- sendpacket[43] = (unsigned char)(network_number >> 24);
- sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[46] = (unsigned char)(network_number & 0x000000FF);
-
+ /* Set the WNodeID to our network address */
+ sendpacket[43] = (unsigned char) (network_number >> 24);
+ sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
+ sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
+ sendpacket[46] = (unsigned char) (network_number & 0x000000FF);
return 1;
}
-
- switch_net_numbers(sendpacket, network_number ,1);
+ /* If we get here, its an IPX-data packet so it'll get passed up the stack. */
+ /* switch the network numbers */
+ switch_net_numbers(sendpacket, network_number, 1);
return 0;
}
-
/****** Background Polling Routines ****************************************/
/*============================================================================
@@ -1755,136 +1793,127 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
static void wpf_poll(sdla_t * card)
{
- fr508_flags_t *flags;
+/* struct device* dev = card->wandev.dev; */
+ fr508_flags_t *flags = card->flags;
unsigned long host_cpu_flags;
-
++card->statistics.poll_entry;
-
- if (((jiffies - card->state_tick) < HZ) ||
- (card->intr_mode == INTR_TEST_MODE))
+ if (((jiffies - card->state_tick) < HZ) ||
+ (card->intr_mode == INTR_TEST_MODE))
return;
-
disable_irq(card->hw.irq);
++card->irq_dis_poll_count;
-
- if (test_and_set_bit(0, (void *)&card->wandev.critical))
+ if (test_and_set_bit(0, (void *) &card->wandev.critical))
{
- ++ card->statistics.poll_already_critical;
+ ++card->statistics.poll_already_critical;
save_flags(host_cpu_flags);
cli();
if ((!card->irq_dis_if_send_count) &&
- (!(--card->irq_dis_poll_count)))
- enable_irq(card->hw.irq);
+ (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
-
return;
}
-
card->wandev.critical = 0x11;
-
- ++ card->statistics.poll_processed;
-
- if (flags->event) {
- fr_mbox_t* mbox = card->mbox;
+ ++card->statistics.poll_processed;
+ /* This is to be changed later ??? */
+ /*
+ if( dev && dev->tbusy && !(flags->imask & 0x02) ) {
+ printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask);
+ }
+ */
+ if (flags->event)
+ {
+ fr_mbox_t *mbox = card->mbox;
int err;
-
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_READ_STATUS;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
if (err)
fr_event(card, err, mbox);
}
-
card->wandev.critical = 0;
-
save_flags(host_cpu_flags);
cli();
- if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+ if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
-
card->state_tick = jiffies;
}
-
/****** Frame Relay Firmware-Specific Functions *****************************/
/*============================================================================
* Read firmware code version.
* o fill string str with firmware version info.
*/
+
static int fr_read_version(sdla_t * card, char *str)
{
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_READ_CODE_VERSION;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- }
- while (err && retry-- && fr_event(card, err, mbox));
- if (!err && str) {
+ } while (err && retry-- && fr_event(card, err, mbox));
+
+ if (!err && str)
+ {
int len = mbox->cmd.length;
-
memcpy(str, mbox->data, len);
str[len] = '\0';
}
return err;
}
-
/*============================================================================
* Set global configuration.
*/
+
static int fr_configure(sdla_t * card, fr_conf_t * conf)
{
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int dlci_num = card->u.f.dlci_num;
int err, i;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
memcpy(mbox->data, conf, sizeof(fr_conf_t));
-
- if (dlci_num) for (i = 0; i < dlci_num; ++i)
- ((fr_conf_t*)mbox->data)->dlci[i] =
- card->u.f.node_dlci[i];
-
+ if (dlci_num)
+ for (i = 0; i < dlci_num; ++i)
+ ((fr_conf_t *) mbox->data)->dlci[i] =
+ card->u.f.node_dlci[i];
mbox->cmd.command = FR_SET_CONFIG;
mbox->cmd.length =
sizeof(fr_conf_t) + dlci_num * sizeof(short);
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Set DLCI configuration.
*/
-static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci)
+static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci)
{
- fr_mbox_t* mbox = card->mbox;
+ fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
do
{
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
- mbox->cmd.dlci = (unsigned short) dlci;
+ mbox->cmd.dlci = (unsigned short) dlci;
mbox->cmd.command = FR_SET_CONFIG;
mbox->cmd.length = 0x0E;
-
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry--);
-
+ }
+ while (err && retry--);
return err;
}
-
/*============================================================================
* Set interrupt mode.
*/
@@ -1893,19 +1922,20 @@ static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
- if (card->hw.fwid == SFID_FR502) {
+ if (card->hw.fwid == SFID_FR502)
+ {
fr502_intr_ctl_t *ictl = (void *) mbox->data;
-
memset(ictl, 0, sizeof(fr502_intr_ctl_t));
ictl->mode = mode;
ictl->tx_len = mtu;
mbox->cmd.length = sizeof(fr502_intr_ctl_t);
- } else {
+ }
+ else
+ {
fr508_intr_ctl_t *ictl = (void *) mbox->data;
-
memset(ictl, 0, sizeof(fr508_intr_ctl_t));
ictl->mode = mode;
ictl->tx_len = mtu;
@@ -1916,9 +1946,9 @@ static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Enable communications.
*/
@@ -1927,16 +1957,16 @@ static int fr_comm_enable(sdla_t * card)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_COMM_ENABLE;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Disable communications.
*/
@@ -1945,16 +1975,16 @@ static int fr_comm_disable(sdla_t * card)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_COMM_DISABLE;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Get communications error statistics.
*/
@@ -1963,26 +1993,26 @@ static int fr_get_err_stats(sdla_t * card)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_READ_ERROR_STATS;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
- fr_comm_stat_t* stats = (void*)mbox->data;
-
- card->wandev.stats.rx_over_errors = stats->rx_overruns;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_aborts;
- card->wandev.stats.rx_length_errors = stats->rx_too_long;
+
+ if (!err)
+ {
+ fr_comm_stat_t *stats = (void *) mbox->data;
+ card->wandev.stats.rx_over_errors = stats->rx_overruns;
+ card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+ card->wandev.stats.rx_missed_errors = stats->rx_aborts;
+ card->wandev.stats.rx_length_errors = stats->rx_too_long;
card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
}
return err;
}
-
/*============================================================================
* Get statistics.
*/
@@ -1991,74 +2021,68 @@ static int fr_get_stats(sdla_t * card)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_READ_STATISTICS;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
+
+ if (!err)
+ {
fr_link_stat_t *stats = (void *) mbox->data;
-
card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
- card->wandev.stats.rx_dropped =
- stats->rx_dropped + stats->rx_dropped2
- ;
+ card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2;
}
return err;
}
-
/*============================================================================
- * Add DLCI(s) (Access Node only!).
+ * Add DLCI(s) (Access Node only!).
+ * This routine will perform the ADD_DLCIs command for the specified DLCI.
*/
-
static int fr_add_dlci(sdla_t * card, int dlci, int num)
{
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err, i;
-
- do {
+ do
+ {
unsigned short *dlci_list = (void *) mbox->data;
-
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
for (i = 0; i < num; ++i)
dlci_list[i] = card->u.f.node_dlci[i];
-
mbox->cmd.length = num * sizeof(short);
mbox->cmd.command = FR_ADD_DLCI;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Activate DLCI(s) (Access Node only!).
+ * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs.
*/
static int fr_activate_dlci(sdla_t * card, int dlci, int num)
{
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err, i;
-
- do {
+ do
+ {
unsigned short *dlci_list = (void *) mbox->data;
-
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
for (i = 0; i < num; ++i)
dlci_list[i] = card->u.f.node_dlci[i];
-
mbox->cmd.length = num * sizeof(short);
mbox->cmd.command = FR_ACTIVATE_DLCI;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Issue in-channel signalling frame.
*/
@@ -2067,8 +2091,8 @@ static int fr_issue_isf(sdla_t * card, int isf)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->data[0] = isf;
mbox->cmd.length = 1;
@@ -2076,9 +2100,9 @@ static int fr_issue_isf(sdla_t * card, int isf)
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Send a frame (S502 version).
*/
@@ -2087,8 +2111,9 @@ static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
memcpy(mbox->data, buf, len);
mbox->cmd.dlci = dlci;
@@ -2098,9 +2123,9 @@ static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf)
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
+
return err;
}
-
/*============================================================================
* Send a frame (S508 version).
*/
@@ -2109,8 +2134,9 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
- do {
+
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.dlci = dlci;
mbox->cmd.attr = attr;
@@ -2119,8 +2145,9 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
+
+ if (!err)
+ {
fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data -
FR_MB_VECTOR + card->hw.dpmbase);
sdla_poke(&card->hw, frbuf->offset, buf, len);
@@ -2138,53 +2165,47 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
*
* Return zero if previous command has to be cancelled.
*/
+
static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox)
{
- fr508_flags_t* flags = card->flags;
+ fr508_flags_t *flags = card->flags;
char *ptr = &flags->iflag;
int i;
-
switch (event)
{
case FRRES_MODEM_FAILURE:
return fr_modem_failure(card, mbox);
-
case FRRES_CHANNEL_DOWN:
wanpipe_set_state(card, WAN_DISCONNECTED);
return 1;
-
case FRRES_CHANNEL_UP:
wanpipe_set_state(card, WAN_CONNECTED);
return 1;
-
case FRRES_DLCI_CHANGE:
return fr_dlci_change(card, mbox);
-
case FRRES_DLCI_MISMATCH:
- printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname);
+ printk(KERN_INFO "%s: DLCI list mismatch!\n",
+ card->devname);
return 1;
-
case CMD_TIMEOUT:
printk(KERN_ERR "%s: command 0x%02X timed out!\n",
card->devname, mbox->cmd.command);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+ for (i = 0; i < 8; i++)
printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
- break;
-
+ printk(KERN_INFO "\n");
+ break;
case FRRES_DLCI_INACTIVE:
- printk(KERN_ERR "%s: DLCI %u is inactive!\n",
- card->devname, mbox->cmd.dlci);
+ printk(KERN_ERR "%s: DLCI %u is inactive!\n",
+ card->devname, mbox->cmd.dlci);
break;
-
case FRRES_CIR_OVERFLOW:
break;
case FRRES_BUFFER_OVERFLOW:
- break;
+ break;
default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, mbox->cmd.command, event);
+ printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
+ ,card->devname, mbox->cmd.command, event);
}
return 0;
}
@@ -2206,7 +2227,6 @@ static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox)
}
return 1;
}
-
/*============================================================================
* Handle DLCI status change.
*
@@ -2218,18 +2238,18 @@ static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox)
int cnt = mbox->cmd.length / sizeof(dlci_status_t);
fr_dlc_conf_t cfg;
fr_channel_t *chan;
- struct device* dev2;
-
- for (; cnt; --cnt, ++status) {
+ struct device *dev2;
+ for (; cnt; --cnt, ++status)
+ {
unsigned short dlci = status->dlci;
struct device *dev = find_channel(card, dlci);
-
- if (dev == NULL)
+ if (dev == NULL)
{
- printk(KERN_INFO "%s: CPE contains unconfigured DLCI= %d\n",
- card->devname, dlci);
+ printk(KERN_INFO
+ "%s: CPE contains unconfigured DLCI= %d\n",
+ card->devname, dlci);
}
- else
+ else
{
if (status->state & 0x01)
{
@@ -2242,68 +2262,56 @@ static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox)
else if (status->state & 0x02)
{
printk(KERN_INFO
- "%s: DLCI %u becomes active!\n",
- card->devname, dlci);
+ "%s: DLCI %u becomes active!\n",
+ card->devname, dlci);
chan = dev->priv;
/* This flag is used for configuring specific
DLCI(s) when they become active.
- */
+ */
chan->dlci_configured = DLCI_CONFIG_PENDING;
-
if (dev && dev->start)
set_chan_state(dev, WAN_CONNECTED);
}
}
}
-
- for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave)
- {
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ {
chan = dev2->priv;
-
- if (chan->dlci_configured == DLCI_CONFIG_PENDING)
+ if (chan->dlci_configured == DLCI_CONFIG_PENDING)
{
memset(&cfg, 0, sizeof(cfg));
-
- if ( chan->cir_status == CIR_DISABLED)
+ if (chan->cir_status == CIR_DISABLED)
{
- cfg.cir_fwd = cfg.cir_bwd = 16;
+ cfg.cir_fwd = cfg.cir_bwd = 16;
cfg.bc_fwd = cfg.bc_bwd = 16;
- cfg.conf_flags = 0x0001;
- printk(KERN_INFO "%s: CIR Disabled for %s\n",
- card->devname, chan->name);
- }
- else if (chan->cir_status == CIR_ENABLED)
- {
+ cfg.conf_flags = 0x0001;
+ printk(KERN_INFO "%s: CIR Disabled for %s\n",
+ card->devname, chan->name);
+ } else if (chan->cir_status == CIR_ENABLED) {
cfg.cir_fwd = cfg.cir_bwd = chan->cir;
- cfg.bc_fwd = cfg.bc_bwd = chan->bc;
- cfg.be_fwd = cfg.be_bwd = chan->be;
+ cfg.bc_fwd = cfg.bc_bwd = chan->bc;
+ cfg.be_fwd = cfg.be_bwd = chan->be;
cfg.conf_flags = 0x0000;
printk(KERN_INFO "%s: CIR Enabled for %s\n",
- card->devname, chan->name);
-
+ card->devname, chan->name);
}
-
- if (fr_dlci_configure( card, &cfg , chan->dlci))
+ if (fr_dlci_configure(card, &cfg, chan->dlci))
{
- printk(KERN_INFO
- "%s: DLCI Configure failed for %d\n",
- card->devname, chan->dlci);
- return 1;
+ printk(KERN_INFO
+ "%s: DLCI Configure failed for %d\n",
+ card->devname, chan->dlci);
+ return 1;
}
-
chan->dlci_configured = DLCI_CONFIGURED;
-
- /*
- * Read the interface byte mapping into the channel
- * structure.
+ /* Read the interface byte mapping into the channel
+ structure.
*/
if (card->intr_mode == DLCI_LIST_INTR_MODE)
- read_DLCI_IB_mapping( card, chan );
- }
+ read_DLCI_IB_mapping(card, chan);
+ }
}
return 1;
}
-
/******* Miscellaneous ******************************************************/
/*============================================================================
@@ -2318,17 +2326,18 @@ static int update_chan_state(struct device *dev)
int err;
int dlci_found = 0;
- do {
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
}
while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
+ if (!err)
+ {
unsigned short *list = (void *) mbox->data;
int cnt = mbox->cmd.length / sizeof(short);
-
for (; cnt; --cnt, ++list)
{
if (*list == chan->dlci)
@@ -2338,14 +2347,13 @@ static int update_chan_state(struct device *dev)
break;
}
}
-
- if(!dlci_found)
- printk(KERN_INFO "%s: DLCI %u is inactive\n",
- card->devname, chan->dlci);
+ if (!dlci_found)
+ printk(KERN_INFO "%s: DLCI %u is inactive\n",
+ card->devname, chan->dlci);
}
+
return err;
}
-
/*============================================================================
* Set channel state.
*/
@@ -2354,27 +2362,27 @@ static void set_chan_state(struct device *dev, int state)
fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
unsigned long flags;
-
+
save_flags(flags);
cli();
-
+
if (chan->state != state)
{
switch (state)
{
case WAN_CONNECTED:
printk(KERN_INFO "%s: interface %s connected!\n"
- , card->devname, dev->name);
+ ,card->devname, dev->name);
break;
case WAN_CONNECTING:
- printk(KERN_INFO
- "%s: interface %s connecting...\n",
- card->devname, dev->name);
+ printk(KERN_INFO
+ "%s: interface %s connecting...\n",
+ card->devname, dev->name);
break;
case WAN_DISCONNECTED:
- printk (KERN_INFO
- "%s: interface %s disconnected!\n",
- card->devname, dev->name);
+ printk(KERN_INFO
+ "%s: interface %s disconnected!\n",
+ card->devname, dev->name);
break;
}
chan->state = state;
@@ -2389,14 +2397,11 @@ static void set_chan_state(struct device *dev, int state)
static struct device *find_channel(sdla_t * card, unsigned dlci)
{
struct device *dev;
-
for (dev = card->wandev.dev; dev; dev = dev->slave)
if (((fr_channel_t *) dev->priv)->dlci == dlci)
- break
- ;
+ break;
return dev;
}
-
/*============================================================================
* Check to see if a frame can be sent. If no transmit buffers available,
* enable transmit interrupts.
@@ -2405,18 +2410,18 @@ static struct device *find_channel(sdla_t * card, unsigned dlci)
* 0 - no buffers available
*/
-static int is_tx_ready(sdla_t * card)
+static int is_tx_ready(sdla_t * card, fr_channel_t * chan)
{
if (card->hw.fwid == SFID_FR508)
{
unsigned char sb = inb(card->hw.port);
-
if (sb & 0x02)
return 1;
- } else {
- fr502_flags_t* flags = card->flags;
-
- if (flags->tx_ready)
+ }
+ else
+ {
+ fr502_flags_t *flags = card->flags;
+ if (flags->tx_ready)
return 1;
flags->imask |= 0x02;
}
@@ -2430,7 +2435,6 @@ static int is_tx_ready(sdla_t * card)
static unsigned int dec_to_uint(unsigned char *str, int len)
{
unsigned val;
-
if (!len)
len = strlen(str);
for (val = 0; len && is_digit(*str); ++str, --len)
@@ -2439,109 +2443,677 @@ static unsigned int dec_to_uint(unsigned char *str, int len)
}
/*==============================================================================
+ * Process UDP call of type FPIPE8ND
+ */
+
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan)
+{
+ int c_retry = MAX_CMD_RETRY;
+ unsigned char *data;
+ unsigned char *buf;
+ unsigned char buf2[5];
+ unsigned int loops, frames, len;
+ unsigned long data_ptr;
+ unsigned short real_len, buffer_length;
+ struct sk_buff *new_skb;
+ unsigned char *sendpacket;
+ fr_mbox_t *mbox = card->mbox;
+ int err;
+ struct timeval tv;
+ int udp_mgmt_req_valid = 1;
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL)
+ {
+ printk(KERN_INFO
+ "%s: Error allocating memory for UDP management cmnd 0x%02X",
+ card->devname, data[47]);
+ ++chan->UDP_FPIPE_mgmt_kmalloc_err;
+ return 1;
+ }
+ memcpy(data, sendpacket, skb->len);
+ switch (data[47])
+ {
+ /* FPIPE_ENABLE_TRACE */
+ case 0x41:
+ /* FPIPE_DISABLE_TRACE */
+ case 0x42:
+ /* FPIPE_GET_TRACE_INFO */
+ case 0x43:
+ /* SET FT1 MODE */
+ case 0x81:
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK)
+ {
+ ++chan->UDP_FPIPE_mgmt_direction_err;
+ udp_mgmt_req_valid = 0;
+ break;
+ }
+ /* FPIPE_FT1_READ_STATUS */
+ case 0x44:
+ /* FT1 MONITOR STATUS */
+ case 0x80:
+ if (card->hw.fwid != SFID_FR508)
+ {
+ ++chan->UDP_FPIPE_mgmt_adptr_type_err;
+ udp_mgmt_req_valid = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!udp_mgmt_req_valid)
+ {
+ /* set length to 0 */
+ data[48] = data[49] = 0;
+ /* set return code */
+ data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD;
+ }
+ else
+ {
+ switch (data[47])
+ {
+ /* FPIPE_ENABLE_TRACE */
+ case 0x41:
+ if (!TracingEnabled)
+ {
+ do
+ {
+ /* SET_TRACE_CONFIGURATION */
+ mbox->cmd.command = 0x60;
+ mbox->cmd.length = 1;
+ mbox->cmd.dlci = 0x00;
+ mbox->data[0] = 0x37;
+ err = sdla_exec(mbox) ?
+ mbox->cmd.result : CMD_TIMEOUT;
+ }
+ while (err && c_retry-- && fr_event(card, err, mbox));
+
+ if (err)
+ {
+ TracingEnabled = 0;
+ /* set the return code */
+ data[50] = mbox->cmd.result;
+ mbox->cmd.length = 0;
+ break;
+ }
+ /* get num_frames */
+ sdla_peek(&card->hw, 0x9000, &num_frames, 2);
+ sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4);
+ start_trace_addr = curr_trace_addr;
+ /* MAX_SEND_BUFFER_SIZE -
+ * sizeof(UDP_MGMT_PACKET) - 41 */
+ available_buffer_space = 1926;
+ /* set return code */
+ data[50] = 0;
+ }
+ else
+ {
+ /* set return code to line trace already
+ enabled */
+ data[50] = 1;
+ }
+ mbox->cmd.length = 0;
+ TracingEnabled = 1;
+ break;
+ /* FPIPE_DISABLE_TRACE */
+ case 0x42:
+ if (TracingEnabled)
+ {
+ do
+ {
+ /* SET_TRACE_CONFIGURATION */
+ mbox->cmd.command = 0x60;
+ mbox->cmd.length = 1;
+ mbox->cmd.dlci = 0x00;
+ mbox->data[0] = 0x36;
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ }
+ while (err && c_retry-- && fr_event(card, err, mbox));
+ }
+ /* set return code */
+ data[50] = 0;
+ mbox->cmd.length = 0;
+ TracingEnabled = 0;
+ break;
+ /* FPIPE_GET_TRACE_INFO */
+ case 0x43:
+ /* Line trace cannot be performed on the 502 */
+ if (!TracingEnabled)
+ {
+ /* set return code */
+ data[50] = 1;
+ mbox->cmd.length = 0;
+ break;
+ }
+ buffer_length = 0;
+ loops = (num_frames < 20) ? num_frames : 20;
+ for (frames = 0; frames < loops; frames += 1)
+ {
+ sdla_peek(&card->hw, curr_trace_addr, &buf2, 1);
+ /* no data on board so exit */
+ if (buf2[0] == 0x00)
+ break;
+ /* 1+sizeof(FRAME_DATA) = 9 */
+ if ((available_buffer_space - buffer_length) < 9)
+ {
+ /* indicate we have more frames on board
+ and exit */
+ data[62] |= 0x02;
+ break;
+ }
+ /* get frame status */
+ sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1);
+ /* get time stamp */
+ sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2);
+ /* get frame length */
+ sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2);
+ /* get pointer to real data */
+ sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4);
+ /* see if we can fit the frame into the user buffer */
+ memcpy(&real_len, &data[64 + buffer_length], 2);
+ if (data_ptr == 0 || real_len + 8 > available_buffer_space)
+ {
+ data[63 + buffer_length] = 0x00;
+ }
+ else
+ {
+ /* we can take it next time */
+ if (available_buffer_space - buffer_length < real_len + 8)
+ {
+ data[62] |= 0x02;
+ break;
+ }
+ /* ok, get the frame */
+ data[63 + buffer_length] = 0x01;
+ /* get the data */
+ sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len);
+ /* zero the opp flag to show we got the frame */
+ buf2[0] = 0x00;
+ sdla_poke(&card->hw, curr_trace_addr, &buf2, 1);
+ /* now move onto the next frame */
+ curr_trace_addr += 16;
+ /* check if we passed the last address */
+ if (curr_trace_addr >= (start_trace_addr + num_frames * 16))
+ curr_trace_addr = start_trace_addr;
+ /* update buffer length and make sure
+ its even */
+ if (data[63 + buffer_length] == 0x01)
+ buffer_length += real_len - 1;
+ /* for the header */
+ buffer_length += 8;
+ if (buffer_length & 0x0001)
+ buffer_length += 1;
+ }
+ }
+ /* ok now set the total number of frames passed in the
+ high 5 bits */
+ data[62] = (frames << 3) | data[62];
+ /* set the data length */
+ mbox->cmd.length = buffer_length;
+ memcpy(&data[48], &buffer_length, 2);
+ data[50] = 0;
+ break;
+ /* FPIPE_FT1_READ_STATUS */
+ case 0x44:
+ sdla_peek(&card->hw, 0xF020, &data[62], 2);
+ data[48] = 2;
+ data[49] = 0;
+ data[50] = 0;
+ mbox->cmd.length = 2;
+ break;
+ /* FPIPE_FLUSH_DRIVER_STATS */
+ case 0x48:
+ init_chan_statistics(chan);
+ init_global_statistics(card);
+ mbox->cmd.length = 0;
+ break;
+ case 0x49:
+ do_gettimeofday(&tv);
+ chan->router_up_time = tv.tv_sec - chan->router_start_time;
+ *(unsigned long *) &data[62] = chan->router_up_time;
+ mbox->cmd.length = 4;
+ break;
+ /* FPIPE_KILL_BOARD */
+ case 0x50:
+ break;
+ /* FT1 MONITOR STATUS */
+ case 0x80:
+ if (data[62] == 1)
+ {
+ if (rCount++ != 0)
+ {
+ data[50] = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+ /* Disable FT1 MONITOR STATUS */
+ if (data[62] == 0)
+ {
+ if (--rCount != 0)
+ {
+ data[50] = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+ default:
+ do
+ {
+ memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
+ if (mbox->cmd.length)
+ memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length);
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ }
+ while (err && c_retry-- && fr_event(card, err, mbox));
+
+ if (!err)
+ {
+ ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
+ memcpy(data, sendpacket, skb->len);
+ memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
+ if (mbox->cmd.length)
+ {
+ memcpy(&data[62], &mbox->data,mbox->cmd.length);
+ }
+ }
+ else
+ {
+ ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+ }
+ }
+ }
+ /* Fill UDP TTL */
+ data[10] = card->wandev.ttl;
+ len = reply_udp(data, mbox->cmd.length);
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK)
+ {
+ err = fr508_send(card, dlci, 0, len, data);
+ if (err)
+ ++chan->UDP_FPIPE_mgmt_adptr_send_passed;
+ else
+ ++chan->UDP_FPIPE_mgmt_adptr_send_failed;
+ dev_kfree_skb(skb);
+ }
+ else
+ {
+ /* Allocate socket buffer */
+ if ((new_skb = dev_alloc_skb(len)) != NULL)
+ {
+ /* copy data into new_skb */
+ buf = skb_put(new_skb, len);
+ memcpy(buf, data, len);
+ /* Decapsulate packet and pass it up the protocol
+ stack */
+ new_skb->dev = dev;
+ buf = skb_pull(new_skb, 1); /* remove hardware header */
+ if (!wan_type_trans(new_skb, dev))
+ {
+ ++chan->UDP_FPIPE_mgmt_not_passed_to_stack;
+ /* can't decapsulate packet */
+ dev_kfree_skb(new_skb);
+ }
+ else
+ {
+ ++chan->UDP_FPIPE_mgmt_passed_to_stack;
+ netif_rx(new_skb);
+ }
+ }
+ else
+ {
+ ++chan->UDP_FPIPE_mgmt_no_socket;
+ printk(KERN_INFO
+ "%s: UDP mgmt cmnd, no socket buffers available!\n",
+ card->devname);
+ }
+ }
+ kfree(data);
+ return 0;
+}
+/*==============================================================================
* Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
* TEST_COUNTER times.
*/
-static int intr_test( sdla_t* card )
+
+static int intr_test(sdla_t * card)
{
- fr_mbox_t* mb = card->mbox;
- int err,i;
-
- /*
- * The critical flag is unset here because we want to get into the
- * ISR without the flag already set. The If_open sets the flag.
+ fr_mbox_t *mb = card->mbox;
+ int err, i;
+ /* The critical flag is unset here because we want to get into the
+ ISR without the flag already set. The If_open sets the flag.
*/
-
card->wandev.critical = 0;
-
- err = fr_set_intr_mode( card, 0x08, card->wandev.mtu );
-
+ err = fr_set_intr_mode(card, 0x08, card->wandev.mtu);
if (err == CMD_OK)
{
- for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ )
+ for (i = 0; i < MAX_INTR_TEST_COUNTER; i++)
{
- /* Run command READ_CODE_VERSION */
+ /* Run command READ_CODE_VERSION */
memset(&mb->cmd, 0, sizeof(fr_cmd_t));
- mb->cmd.length = 0;
+ mb->cmd.length = 0;
mb->cmd.command = 0x40;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
fr_event(card, err, mb);
}
+ }
+ else
+ {
+ return err;
}
- else
- return err;
-
- err = fr_set_intr_mode( card, 0, card->wandev.mtu );
-
- if( err != CMD_OK )
+ err = fr_set_intr_mode(card, 0, card->wandev.mtu);
+ if (err != CMD_OK)
return err;
-
card->wandev.critical = 1;
return 0;
}
+/*============================================================================
+ * Process UDP call of type DRVSTATS.
+ */
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan)
+{
+ int c_retry = MAX_CMD_RETRY;
+ unsigned char *sendpacket;
+ unsigned char buf2[5];
+ unsigned char *data;
+ unsigned char *buf;
+ unsigned int len;
+ fr_mbox_t *mbox = card->mbox;
+ struct sk_buff *new_skb;
+ int err;
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL)
+ {
+ printk(KERN_INFO
+ "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
+ ,card->devname, data[45]);
+ ++chan->UDP_DRVSTATS_mgmt_kmalloc_err;
+ return 1;
+ }
+ memcpy(data, sendpacket, skb->len);
+ switch (data[47])
+ {
+ case 0x45:
+ *(unsigned long *) &data[62] = chan->if_send_entry;
+ *(unsigned long *) &data[66] = chan->if_send_skb_null;
+ *(unsigned long *) &data[70] = chan->if_send_broadcast;
+ *(unsigned long *) &data[74] = chan->if_send_multicast;
+ *(unsigned long *) &data[78] = chan->if_send_critical_ISR;
+ *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR;
+ *(unsigned long *) &data[86] = chan->if_send_busy;
+ *(unsigned long *) &data[90] = chan->if_send_busy_timeout;
+ *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request;
+ *(unsigned long *) &data[98] = chan->if_send_FPIPE_request;
+ *(unsigned long *) &data[102] = chan->if_send_wan_disconnected;
+ *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected;
+ *(unsigned long *) &data[110] = chan->if_send_no_bfrs;
+ *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full;
+ *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr;
+ *(unsigned long *) &data[120] = card->irq_dis_if_send_count;
+ mbox->cmd.length = 62;
+ break;
+ case 0x46:
+ *(unsigned long *) &data[62] = card->statistics.isr_entry;
+ *(unsigned long *) &data[66] = card->statistics.isr_already_critical;
+ *(unsigned long *) &data[70] = card->statistics.isr_rx;
+ *(unsigned long *) &data[74] = card->statistics.isr_tx;
+ *(unsigned long *) &data[78] = card->statistics.isr_intr_test;
+ *(unsigned long *) &data[82] = card->statistics.isr_spurious;
+ *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int;
+ *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started;
+ *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr;
+ *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI;
+ *(unsigned long *) &data[102] = chan->rx_intr_no_socket;
+ *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started;
+ *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request;
+ *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request;
+ *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack;
+ *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack;
+ mbox->cmd.length = 64;
+ break;
+ case 0x47:
+ *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err;
+ *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err;
+ *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err;
+ *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+ *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
+ *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed;
+ *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed;
+ *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket;
+ *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack;
+ *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack;
+ *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err;
+ *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
+ *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
+ *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket;
+ *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
+ *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack;
+ *(unsigned long *) &data[134] = card->statistics.poll_entry;
+ *(unsigned long *) &data[138] = card->statistics.poll_already_critical;
+ *(unsigned long *) &data[142] = card->statistics.poll_processed;
+ *(unsigned long *) &data[144] = card->irq_dis_poll_count;
+ mbox->cmd.length = 86;
+ break;
+ default:
+ do
+ {
+ memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
+ if (mbox->cmd.length)
+ memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length);
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ }
+ while (err && c_retry-- && fr_event(card, err, mbox));
+
+ if (!err)
+ {
+ ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ memcpy(data, sendpacket, skb->len);
+ memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
+ if (mbox->cmd.length)
+ memcpy(&data[62], &mbox->data, mbox->cmd.length);
+ }
+ else
+ {
+ ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ }
+ }
+ /* Fill UDP TTL */
+ data[10] = card->wandev.ttl;
+ len = reply_udp(data, mbox->cmd.length);
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK)
+ {
+ err = fr508_send(card, dlci, 0, len, data);
+ if (err)
+ ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
+ else
+ ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
+ dev_kfree_skb(skb);
+ }
+ else
+ {
+ /* Allocate socket buffer */
+ if ((new_skb = dev_alloc_skb(len)) != NULL)
+ {
+ /* copy data into new_skb */
+ buf = skb_put(new_skb, len);
+ memcpy(buf, data, len);
+ /* Decapsulate packet and pass it up the
+ protocol stack */
+ new_skb->dev = dev;
+ /* remove hardware header */
+ buf = skb_pull(new_skb, 1);
+ if (!wan_type_trans(new_skb, dev))
+ {
+ /* can't decapsulate packet */
+ ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
+ dev_kfree_skb(new_skb);
+ }
+ else
+ {
+ ++chan->UDP_DRVSTATS_mgmt_passed_to_stack;
+ netif_rx(new_skb);
+ }
+ }
+ else
+ {
+ ++chan->UDP_DRVSTATS_mgmt_no_socket;
+ printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname);
+ }
+ }
+ kfree(data);
+ return 0;
+}
/*==============================================================================
+ * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ?
+ */
+
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+{
+ unsigned char *sendpacket;
+ unsigned char buf2[5];
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if (sendpacket[2] == 0x45 && /* IP packet */
+ sendpacket[11] == 0x11 && /* UDP packet */
+ sendpacket[24] == buf2[1] && /* UDP Port */
+ sendpacket[25] == buf2[0] &&
+ sendpacket[38] == 0x01)
+ {
+ if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */
+ sendpacket[31] == 0x50 &&
+ sendpacket[32] == 0x49 &&
+ sendpacket[33] == 0x50 &&
+ sendpacket[34] == 0x45 &&
+ sendpacket[35] == 0x38 &&
+ sendpacket[36] == 0x4E &&
+ sendpacket[37] == 0x44)
+ {
+ return UDP_FPIPE_TYPE;
+ } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */
+ sendpacket[31] == 0x52 &&
+ sendpacket[32] == 0x56 &&
+ sendpacket[33] == 0x53 &&
+ sendpacket[34] == 0x54 &&
+ sendpacket[35] == 0x41 &&
+ sendpacket[36] == 0x54 &&
+ sendpacket[37] == 0x53)
+ {
+ return UDP_DRVSTATS_TYPE;
+ }
+ else
+ return UDP_INVALID_TYPE;
+ }
+ else
+ return UDP_INVALID_TYPE;
+}
+/*==============================================================================
+ * Initializes the Statistics values in the fr_channel structure.
+ */
+
+void init_chan_statistics(fr_channel_t * chan)
+{
+ chan->if_send_entry = 0;
+ chan->if_send_skb_null = 0;
+ chan->if_send_broadcast = 0;
+ chan->if_send_multicast = 0;
+ chan->if_send_critical_ISR = 0;
+ chan->if_send_critical_non_ISR = 0;
+ chan->if_send_busy = 0;
+ chan->if_send_busy_timeout = 0;
+ chan->if_send_FPIPE_request = 0;
+ chan->if_send_DRVSTATS_request = 0;
+ chan->if_send_wan_disconnected = 0;
+ chan->if_send_dlci_disconnected = 0;
+ chan->if_send_no_bfrs = 0;
+ chan->if_send_adptr_bfrs_full = 0;
+ chan->if_send_bfrs_passed_to_adptr = 0;
+ chan->rx_intr_no_socket = 0;
+ chan->rx_intr_dev_not_started = 0;
+ chan->rx_intr_FPIPE_request = 0;
+ chan->rx_intr_DRVSTATS_request = 0;
+ chan->rx_intr_bfr_not_passed_to_stack = 0;
+ chan->rx_intr_bfr_passed_to_stack = 0;
+ chan->UDP_FPIPE_mgmt_kmalloc_err = 0;
+ chan->UDP_FPIPE_mgmt_direction_err = 0;
+ chan->UDP_FPIPE_mgmt_adptr_type_err = 0;
+ chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0;
+ chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0;
+ chan->UDP_FPIPE_mgmt_adptr_send_passed = 0;
+ chan->UDP_FPIPE_mgmt_adptr_send_failed = 0;
+ chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0;
+ chan->UDP_FPIPE_mgmt_passed_to_stack = 0;
+ chan->UDP_FPIPE_mgmt_no_socket = 0;
+ chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
+ chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
+ chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
+ chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0;
+ chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0;
+ chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0;
+ chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
+ chan->UDP_DRVSTATS_mgmt_no_socket = 0;
+}
+/*==============================================================================
* Initializes the Statistics values in the Sdla_t structure.
*/
-void init_global_statistics( sdla_t* card )
+void init_global_statistics(sdla_t * card)
{
/* Intialize global statistics for a card */
- card->statistics.isr_entry = 0;
- card->statistics.isr_already_critical = 0;
- card->statistics.isr_rx = 0;
- card->statistics.isr_tx = 0;
- card->statistics.isr_intr_test = 0;
- card->statistics.isr_spurious = 0;
- card->statistics.isr_enable_tx_int = 0;
- card->statistics.rx_intr_corrupt_rx_bfr = 0;
+ card->statistics.isr_entry = 0;
+ card->statistics.isr_already_critical = 0;
+ card->statistics.isr_rx = 0;
+ card->statistics.isr_tx = 0;
+ card->statistics.isr_intr_test = 0;
+ card->statistics.isr_spurious = 0;
+ card->statistics.isr_enable_tx_int = 0;
+ card->statistics.rx_intr_corrupt_rx_bfr = 0;
card->statistics.rx_intr_on_orphaned_DLCI = 0;
- card->statistics.tx_intr_dev_not_started = 0;
- card->statistics.poll_entry = 0;
- card->statistics.poll_already_critical = 0;
- card->statistics.poll_processed = 0;
+ card->statistics.tx_intr_dev_not_started = 0;
+ card->statistics.poll_entry = 0;
+ card->statistics.poll_already_critical = 0;
+ card->statistics.poll_processed = 0;
}
-static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan )
+static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan)
{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- dlci_IB_mapping_t* result;
- int err, counter, found;
-
- do {
+ fr_mbox_t *mbox = card->mbox;
+ int retry = MAX_CMD_RETRY;
+ dlci_IB_mapping_t *result;
+ int err, counter, found;
+ do
+ {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
-
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ }
+ while (err && retry-- && fr_event(card, err, mbox));
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if( mbox->cmd.result != 0)
- printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n",
- chan->name);
+ if (mbox->cmd.result != 0)
+ printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name);
counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
- result = (void *)mbox->data;
-
+ result = (void *) mbox->data;
found = 0;
- for (; counter; --counter, ++result) {
- if ( result->dlci == chan->dlci ) {
- printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
- ,card->devname,result->dlci, result->addr_value
- ,chan->name);
+ for (; counter; --counter, ++result)
+ {
+ if (result->dlci == chan->dlci)
+ {
+ printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
+ ,card->devname, result->dlci, result->addr_value ,chan->name);
chan->IB_addr = result->addr_value;
- chan->dlci_int_interface = (void*)(card->hw.dpmbase +
- ( chan->IB_addr & 0x00001FFF));
+ chan->dlci_int_interface = (void *) (card->hw.dpmbase +
+ (chan->IB_addr & 0x00001FFF));
found = 1;
- break;
- }
+ break;
+ }
}
if (!found)
- printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
- card->devname, chan->dlci);
+ printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
+ card->devname, chan->dlci);
}
/****** End *****************************************************************/
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
index 9d3e52fb0..32675d355 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/sdla_ppp.c
@@ -10,6 +10,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* Mar 15, 1998 Alan Cox o 2.1.8x basic port.
* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
* while they have been disabled.
* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by
@@ -55,11 +56,7 @@
* Jan 06, 1997 Gene Kozin Initial version.
*****************************************************************************/
-#if !defined(__KERNEL__) || !defined(MODULE)
-#error This code MUST be compiled as a kernel module!
-#endif
-
-#include <linux/config.h> /* CONFIG_SANGOMA_MANAGER */
+#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
@@ -68,10 +65,8 @@
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <linux/init.h> /* __initfunc et al. */
#include <asm/byteorder.h> /* htons(), etc. */
-#include <asm/uaccess.h>
-
+#include <asm/uaccess.h> /* copyto/from user */
#define _GNUC_
#include <linux/sdla_ppp.h> /* PPP firmware API definitions */
@@ -82,30 +77,27 @@
#else
#define STATIC static
#endif
-
-#define PPP_DFLT_MTU 1500 /* default MTU */
-#define PPP_MAX_MTU 4000 /* maximum MTU */
+#define PPP_DFLT_MTU 1500 /* default MTU */
+#define PPP_MAX_MTU 4000 /* maximum MTU */
#define PPP_HDR_LEN 1
-
-#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
-#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
+#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
+#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
/* For handle_IPXWAN() */
#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/******Data Structures*****************************************************/
+/******Data Structures*****************************************************/
/* This structure is placed in the private data area of the device structure.
* The card structure used to occupy the private area but now the following
* structure will incorporate the card structure along with PPP specific data
*/
-
-typedef struct ppp_private_area
+
+typedef struct ppp_private_area
{
- sdla_t* card;
+ sdla_t *card;
unsigned long router_start_time; /*router start time in sec */
- unsigned long tick_counter; /*used for 5 second counter*/
- unsigned mc; /*multicast support on or off*/
+ unsigned long tick_counter; /*used for 5 second counter */
+ unsigned mc; /*multicast support on or off */
/* PPP specific statistics */
unsigned long if_send_entry;
unsigned long if_send_skb_null;
@@ -122,13 +114,11 @@ typedef struct ppp_private_area
unsigned long if_send_protocol_error;
unsigned long if_send_tx_int_enabled;
unsigned long if_send_bfr_passed_to_adptr;
-
unsigned long rx_intr_no_socket;
unsigned long rx_intr_DRVSTATS_request;
unsigned long rx_intr_PTPIPE_request;
unsigned long rx_intr_bfr_not_passed_to_stack;
unsigned long rx_intr_bfr_passed_to_stack;
-
unsigned long UDP_PTPIPE_mgmt_kmalloc_err;
unsigned long UDP_PTPIPE_mgmt_adptr_type_err;
unsigned long UDP_PTPIPE_mgmt_direction_err;
@@ -136,8 +126,7 @@ typedef struct ppp_private_area
unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK;
unsigned long UDP_PTPIPE_mgmt_passed_to_adptr;
unsigned long UDP_PTPIPE_mgmt_passed_to_stack;
- unsigned long UDP_PTPIPE_mgmt_no_socket;
-
+ unsigned long UDP_PTPIPE_mgmt_no_socket;
unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
unsigned long UDP_DRVSTATS_mgmt_adptr_type_err;
unsigned long UDP_DRVSTATS_mgmt_direction_err;
@@ -145,84 +134,74 @@ typedef struct ppp_private_area
unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr;
unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
- unsigned long UDP_DRVSTATS_mgmt_no_socket;
-
- unsigned long router_up_time;
-
-}ppp_private_area_t;
+ unsigned long UDP_DRVSTATS_mgmt_no_socket;
+ unsigned long router_up_time;
+} ppp_private_area_t;
/* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
+static int rCount = 0;
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, struct device* dev,
- wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, struct device* dev);
-
+static int update(wan_device_t * wandev);
+static int new_if(wan_device_t * wandev, struct device *dev,
+ wanif_conf_t * conf);
+static int del_if(wan_device_t * wandev, struct device *dev);
/* WANPIPE-specific entry points */
-static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data);
-
+static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data);
/* Network device interface */
-static int if_init (struct device* dev);
-static int if_open (struct device* dev);
-static int if_close (struct device* dev);
-static int if_header (struct sk_buff* skb, struct device* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send (struct sk_buff* skb, struct device* dev);
-static struct enet_statistics* if_stats (struct device* dev);
-
-
+static int if_init(struct device *dev);
+static int if_open(struct device *dev);
+static int if_close(struct device *dev);
+static int if_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len);
+static int if_rebuild_hdr(struct sk_buff *skb);
+static int if_send(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *if_stats(struct device *dev);
/* PPP firmware interface functions */
-static int ppp_read_version (sdla_t* card, char* str);
-static int ppp_configure (sdla_t* card, void* data);
-static int ppp_set_intr_mode (sdla_t* card, unsigned mode);
-static int ppp_comm_enable (sdla_t* card);
-static int ppp_comm_disable (sdla_t* card);
-static int ppp_get_err_stats (sdla_t* card);
-static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto);
-static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb);
-
+static int ppp_read_version(sdla_t * card, char *str);
+static int ppp_configure(sdla_t * card, void *data);
+static int ppp_set_intr_mode(sdla_t * card, unsigned mode);
+static int ppp_comm_enable(sdla_t * card);
+static int ppp_comm_disable(sdla_t * card);
+static int ppp_get_err_stats(sdla_t * card);
+static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto);
+static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb);
/* Interrupt handlers */
-STATIC void wpp_isr (sdla_t* card);
-static void rx_intr (sdla_t* card);
-static void tx_intr (sdla_t* card);
-
+STATIC void wpp_isr(sdla_t * card);
+static void rx_intr(sdla_t * card);
+static void tx_intr(sdla_t * card);
/* Background polling routines */
-static void wpp_poll (sdla_t* card);
-static void poll_active (sdla_t* card);
-static void poll_connecting (sdla_t* card);
-static void poll_disconnected (sdla_t* card);
-
+static void wpp_poll(sdla_t * card);
+static void poll_active(sdla_t * card);
+static void poll_connecting(sdla_t * card);
+static void poll_disconnected(sdla_t * card);
/* Miscellaneous functions */
-static int config502 (sdla_t* card);
-static int config508 (sdla_t* card);
-static void show_disc_cause (sdla_t* card, unsigned cause);
-static unsigned char bps_to_speed_code (unsigned long bps);
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area);
-static void init_ppp_tx_rx_buff( sdla_t* card );
-static int intr_test( sdla_t* card );
-static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
-static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area);
-static void init_global_statistics( sdla_t* card );
-
-static int Intr_test_counter;
+static int config502(sdla_t * card);
+static int config508(sdla_t * card);
+static void show_disc_cause(sdla_t * card, unsigned cause);
+static unsigned char bps_to_speed_code(unsigned long bps);
+static int reply_udp(unsigned char *data, unsigned int mbox_len);
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area);
+static void init_ppp_tx_rx_buff(sdla_t * card);
+static int intr_test(sdla_t * card);
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
+static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area);
+static void init_global_statistics(sdla_t * card);
+static int Intr_test_counter;
static char TracingEnabled;
static unsigned long curr_trace_addr;
static unsigned long start_trace_addr;
static unsigned short available_buffer_space;
-
/* IPX functions */
static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+
/****** Public Functions ****************************************************/
/*============================================================================
@@ -237,40 +216,30 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
* Return: 0 o.k.
* < 0 failure.
*/
-int wpp_init (sdla_t* card, wandev_conf_t* conf)
+int wpp_init(sdla_t * card, wandev_conf_t * conf)
{
- union
- {
+ union {
char str[80];
} u;
-
/* Verify configuration ID */
if (conf->config_id != WANCONFIG_PPP) {
-
printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
+ card->devname, conf->config_id);
return -EINVAL;
-
}
-
/* Initialize protocol-specific fields */
switch (card->hw.fwid) {
-
- case SFID_PPP502:
- card->mbox =(void*)(card->hw.dpmbase + PPP502_MB_OFFS);
- card->flags=(void*)(card->hw.dpmbase + PPP502_FLG_OFFS);
- break;
-
- case SFID_PPP508:
- card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS);
- card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
- break;
-
- default:
- return -EINVAL;
-
+ case SFID_PPP502:
+ card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS);
+ card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS);
+ break;
+ case SFID_PPP508:
+ card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS);
+ card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS);
+ break;
+ default:
+ return -EINVAL;
}
-
/* Read firmware version. Note that when adapter initializes, it
* clears the mailbox, so it may appear that the first command was
* executed successfully when in fact it was merely erased. To work
@@ -278,38 +247,33 @@ int wpp_init (sdla_t* card, wandev_conf_t* conf)
*/
if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
return -EIO;
-
- printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str);
+ printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str);
/* Adjust configuration and set defaults */
card->wandev.mtu = (conf->mtu) ?
- min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
-
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = &wpp_isr;
- card->poll = &wpp_poll;
- card->exec = &wpp_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- card->wandev.state = WAN_DISCONNECTED;
- card->wandev.udp_port = conf->udp_port;
- card->wandev.ttl = conf->ttl;
+ min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
+ card->wandev.bps = conf->bps;
+ card->wandev.interface = conf->interface;
+ card->wandev.clocking = conf->clocking;
+ card->wandev.station = conf->station;
+ card->isr = &wpp_isr;
+ card->poll = &wpp_poll;
+ card->exec = &wpp_exec;
+ card->wandev.update = &update;
+ card->wandev.new_if = &new_if;
+ card->wandev.del_if = &del_if;
+ card->wandev.state = WAN_DISCONNECTED;
+ card->wandev.udp_port = conf->udp_port;
+ card->wandev.ttl = conf->ttl;
card->irq_dis_if_send_count = 0;
- card->irq_dis_poll_count = 0;
- TracingEnabled = 0;
-
+ card->irq_dis_poll_count = 0;
+ TracingEnabled = 0;
card->wandev.enable_IPX = conf->enable_IPX;
if (conf->network_number)
card->wandev.network_number = conf->network_number;
else
card->wandev.network_number = 0xDEADBEEF;
-
/* initialize global statistics */
- init_global_statistics( card );
-
+ init_global_statistics(card);
return 0;
}
@@ -321,19 +285,14 @@ int wpp_init (sdla_t* card, wandev_conf_t* conf)
static int update(wan_device_t * wandev)
{
sdla_t *card;
-
/* sanity checks */
if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT
- ;
+ return -EFAULT;
if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV
- ;
+ return -ENODEV;
if (test_and_set_bit(0, (void *) &wandev->critical))
- return -EAGAIN
- ;
+ return -EAGAIN;
card = wandev->private;
-
ppp_get_err_stats(card);
wandev->critical = 0;
return 0;
@@ -351,41 +310,29 @@ static int update(wan_device_t * wandev)
* Return: 0 o.k.
* < 0 failure (channel will not be created)
*/
-static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
-{
- sdla_t* card = wandev->private;
- ppp_private_area_t* ppp_priv_area;
+static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf)
+{
+ sdla_t *card = wandev->private;
+ ppp_private_area_t *ppp_priv_area;
if (wandev->ndev)
return -EEXIST;
-
if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-
printk(KERN_INFO "%s: invalid interface name!\n",
- card->devname);
+ card->devname);
return -EINVAL;
-
}
-
/* allocate and initialize private data */
ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
-
- if( ppp_priv_area == NULL )
- return -ENOMEM;
-
+ if (ppp_priv_area == NULL)
+ return -ENOMEM;
memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
-
- ppp_priv_area->card = card;
-
+ ppp_priv_area->card = card;
/* initialize data */
strcpy(card->u.p.if_name, conf->name);
-
/* initialize data in ppp_private_area structure */
-
- init_ppp_priv_struct( ppp_priv_area );
-
+ init_ppp_priv_struct(ppp_priv_area);
ppp_priv_area->mc = conf->mc;
-
/* prepare network device data space for registration */
dev->name = card->u.p.if_name;
dev->init = &if_init;
@@ -396,14 +343,13 @@ static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
/*============================================================================
* Delete logical channel.
*/
-static int del_if (wan_device_t* wandev, struct device* dev)
+
+static int del_if(wan_device_t * wandev, struct device *dev)
{
if (dev->priv) {
-
- kfree(dev->priv);
- dev->priv = NULL;
- }
-
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
return 0;
}
@@ -412,24 +358,23 @@ static int del_if (wan_device_t* wandev, struct device* dev)
/*============================================================================
* Execute adapter interface command.
*/
+
static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
{
ppp_mbox_t *mbox = card->mbox;
int len;
-
- if (copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
+ if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
return -EFAULT;
len = mbox->cmd.length;
if (len) {
- if (copy_from_user((void *) &mbox->data, u_data, len))
+ if(copy_from_user((void *) &mbox->data, u_data, len))
return -EFAULT;
}
/* execute command */
if (!sdla_exec(mbox))
return -EIO;
-
/* return result */
- if (copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t)))
+ if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t)))
return -EFAULT;
len = mbox->cmd.length;
if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
@@ -446,41 +391,34 @@ static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
* interface registration. Returning anything but zero will fail interface
* registration.
*/
-static int if_init (struct device* dev)
+
+static int if_init(struct device *dev)
{
- ppp_private_area_t* ppp_priv_area = dev->priv;
- sdla_t* card = ppp_priv_area->card;
- wan_device_t* wandev = &card->wandev;
- int i;
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
+ wan_device_t *wandev = &card->wandev;
/* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
-
-
+ dev->open = &if_open;
+ dev->stop = &if_close;
+ dev->hard_header = &if_header;
+ dev->rebuild_header = &if_rebuild_hdr;
+ dev->hard_start_xmit = &if_send;
+ dev->get_stats = &if_stats;
/* Initialize media-specific parameters */
- dev->family = AF_INET; /* address family */
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- dev->mtu = wandev->mtu;
- dev->hard_header_len = PPP_HDR_LEN; /* media header length */
-
+ dev->type = ARPHRD_PPP; /* ARP h/w type */
+ dev->mtu = wandev->mtu;
+ dev->hard_header_len = PPP_HDR_LEN; /* media header length */
/* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 100;
-
+ dev->irq = wandev->irq;
+ dev->dma = wandev->dma;
+ dev->base_addr = wandev->ioport;
+ dev->mem_start = wandev->maddr;
+ dev->mem_end = wandev->maddr + wandev->msize - 1;
+ /* Set transmit buffer queue length */
+ dev->tx_queue_len = 100;
/* Initialize socket buffers */
dev_init_buffers(dev);
-
return 0;
}
@@ -491,72 +429,54 @@ static int if_init (struct device* dev)
*
* Return 0 if O.k. or errno.
*/
-static int if_open (struct device* dev)
+
+static int if_open(struct device *dev)
{
- ppp_private_area_t* ppp_priv_area = dev->priv;
- sdla_t* card = ppp_priv_area->card;
- ppp_flags_t* flags = card->flags;
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
+ ppp_flags_t *flags = card->flags;
struct timeval tv;
int err = 0;
-
if (dev->start)
- return -EBUSY; /* only one open is allowed */
-
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ return -EBUSY; /* only one open is allowed */
+ if (test_and_set_bit(0, (void *) &card->wandev.critical))
return -EAGAIN;
-
- if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)){
-
+ if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {
err = -EIO;
card->wandev.critical = 0;
return err;
-
}
-
Intr_test_counter = 0;
- err = intr_test( card );
-
- if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
-
- printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
- card->devname, Intr_test_counter);
+ err = intr_test(card);
+ if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
+ printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
+ card->devname, Intr_test_counter);
err = -EIO;
card->wandev.critical = 0;
return err;
-
}
-
- printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
- card->devname, Intr_test_counter);
-
+ printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
+ card->devname, Intr_test_counter);
/* Initialize Rx/Tx buffer control fields */
- init_ppp_tx_rx_buff( card );
-
+ init_ppp_tx_rx_buff(card);
if (ppp_set_intr_mode(card, 0x03)) {
-
err = -EIO;
card->wandev.critical = 0;
return err;
-
}
-
flags->imask &= ~0x02;
-
if (ppp_comm_enable(card)) {
-
err = -EIO;
card->wandev.critical = 0;
return err;
-
}
-
wanpipe_set_state(card, WAN_CONNECTING);
wanpipe_open(card);
dev->mtu = min(dev->mtu, card->wandev.mtu);
dev->interrupt = 0;
dev->tbusy = 0;
dev->start = 1;
- do_gettimeofday( &tv );
+ do_gettimeofday(&tv);
ppp_priv_area->router_start_time = tv.tv_sec;
card->wandev.critical = 0;
return err;
@@ -567,14 +487,13 @@ static int if_open (struct device* dev)
* o if this is the last open, then disable communications and interrupts.
* o reset flags.
*/
-static int if_close (struct device* dev)
-{
- ppp_private_area_t* ppp_priv_area = dev->priv;
- sdla_t* card = ppp_priv_area->card;
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
+static int if_close(struct device *dev)
+{
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
+ if (test_and_set_bit(0, (void *) &card->wandev.critical))
return -EAGAIN;
-
dev->start = 0;
wanpipe_close(card);
wanpipe_set_state(card, WAN_DISCONNECTED);
@@ -593,21 +512,19 @@ static int if_close (struct device* dev)
*
* Return: media header length.
*/
-static int if_header (struct sk_buff* skb, struct device* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len)
+
+static int if_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
{
- switch (type)
+ switch (type)
{
case ETH_P_IP:
-
case ETH_P_IPX:
skb->protocol = type;
break;
-
default:
skb->protocol = 0;
}
-
return PPP_HDR_LEN;
}
@@ -617,13 +534,14 @@ static int if_header (struct sk_buff* skb, struct device* dev,
* Return: 1 physical address resolved.
* 0 physical address not resolved
*/
-static int if_rebuild_hdr (struct sk_buff* skb)
-{
- ppp_private_area_t* ppp_priv_area = skb->dev->priv;
- sdla_t* card = ppp_priv_area->card;
+static int if_rebuild_hdr(struct sk_buff *skb)
+{
+ struct device *dev=skb->dev;
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, dev->name);
+ card->devname, dev->name);
return 1;
}
@@ -644,133 +562,133 @@ static int if_rebuild_hdr (struct sk_buff* skb)
* 2. Setting tbusy flag will inhibit further transmit requests from the
* protocol stack and can be used for flow control with protocol layer.
*/
-static int if_send (struct sk_buff* skb, struct device* dev)
+
+static int if_send(struct sk_buff *skb, struct device *dev)
{
- ppp_private_area_t* ppp_priv_area = dev->priv;
- sdla_t* card = ppp_priv_area->card;
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
unsigned char *sendpacket;
unsigned long check_braddr, check_mcaddr;
unsigned long host_cpu_flags;
- ppp_flags_t* flags = card->flags;
+ ppp_flags_t *flags = card->flags;
int retry = 0;
int err, udp_type;
-
++ppp_priv_area->if_send_entry;
-
if (skb == NULL) {
-
/* If we get here, some higher layer thinks we've missed an
* tx-done interrupt.
*/
printk(KERN_INFO "%s: interface %s got kicked!\n",
- card->devname, dev->name);
-
+ card->devname, dev->name);
++ppp_priv_area->if_send_skb_null;
-
- dev_tint(dev);
+ mark_bh(NET_BH);
return 0;
-
}
-
if (dev->tbusy) {
-
/* If our device stays busy for at least 5 seconds then we will
* kick start the device by making dev->tbusy = 0. We expect
* that our device never stays busy more than 5 seconds. So this
* is only used as a last resort.
*/
-
++ppp_priv_area->if_send_busy;
- ++card->wandev.stats.collisions;
-
- if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) {
+ ++card->wandev.stats.collisions;
+ if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) {
return 1;
}
-
- printk (KERN_INFO "%s: Transmit times out\n",card->devname);
-
+ printk(KERN_INFO "%s: Transmit times out\n", card->devname);
++ppp_priv_area->if_send_busy_timeout;
-
- /* unbusy the card (because only one interface per card)*/
+ /* unbusy the card (because only one interface per card) */
dev->tbusy = 0;
- }
+ }
sendpacket = skb->data;
-#ifdef CONFIG_SANGOMA_MANAGER
- if(sangoma_ppp_manager(skb,card))
- {
+ udp_type = udp_pkt_type(skb, card);
+ if (udp_type == UDP_DRVSTATS_TYPE) {
+ ++ppp_priv_area->if_send_DRVSTATS_request;
+ process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev,
+ ppp_priv_area);
dev_kfree_skb(skb);
return 0;
+ } else if (udp_type == UDP_PTPIPE_TYPE)
+ ++ppp_priv_area->if_send_PTPIPE_request;
+ /* retreive source address in two forms: broadcast & multicast */
+ check_braddr = sendpacket[15];
+ check_mcaddr = sendpacket[12];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[14];
+ check_mcaddr |= sendpacket[13];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[13];
+ check_mcaddr |= sendpacket[14];
+ check_braddr = check_braddr << 8;
+ check_mcaddr = check_mcaddr << 8;
+ check_braddr |= sendpacket[12];
+ check_mcaddr |= sendpacket[15];
+ /* if the Source Address is a Multicast address */
+ if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001)
+ && (check_mcaddr <= 0xFFFFFFFE)) {
+ printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n"
+ ,card->devname);
+ dev_kfree_skb(skb);
+ ++ppp_priv_area->if_send_multicast;
+ ++card->wandev.stats.tx_dropped;
+ return 0;
}
-#endif
disable_irq(card->hw.irq);
++card->irq_dis_if_send_count;
-
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
- {
- if (card->wandev.critical == CRITICAL_IN_ISR)
- {
+ if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
+ if (card->wandev.critical == CRITICAL_IN_ISR) {
/* If the critical flag is set due to an Interrupt
* then set enable transmit interrupt flag to enable
* transmit interrupt. (delay interrupt)
*/
card->wandev.enable_tx_int = 1;
- dev->tbusy = 1;
-
+ dev->tbusy = 1;
/* set the counter to see if we get the interrupt in
* 5 seconds.
*/
ppp_priv_area->tick_counter = jiffies;
- ++ppp_priv_area->if_send_critical_ISR;
-
+ ++ppp_priv_area->if_send_critical_ISR;
save_flags(host_cpu_flags);
- cli();
- if ((!(--card->irq_dis_if_send_count)) &&
- (!card->irq_dis_poll_count))
- enable_irq(card->hw.irq);
- restore_flags(host_cpu_flags);
-
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
return 1;
-
}
-
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
++ppp_priv_area->if_send_critical_non_ISR;
-
save_flags(host_cpu_flags);
- cli();
- if ((!(--card->irq_dis_if_send_count)) &&
- (!card->irq_dis_poll_count))
- enable_irq(card->hw.irq);
- restore_flags(host_cpu_flags);
-
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
return 0;
}
-
-
- if (card->wandev.state != WAN_CONNECTED) {
-
+ if (udp_type == UDP_PTPIPE_TYPE) {
+ err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
+ dev, ppp_priv_area);
+ } else if (card->wandev.state != WAN_CONNECTED) {
++ppp_priv_area->if_send_wan_disconnected;
- ++card->wandev.stats.tx_dropped;
-
- } else if (!skb->protocol) {
+ ++card->wandev.stats.tx_dropped;
+ } else if (!skb->protocol) {
++ppp_priv_area->if_send_protocol_error;
- ++card->wandev.stats.tx_errors;
-
+ ++card->wandev.stats.tx_errors;
} else {
-
- /*If it's IPX change the network numbers to 0 if they're ours.*/
- if( skb->protocol == ETH_P_IPX ) {
- if(card->wandev.enable_IPX) {
- switch_net_numbers( skb->data,
- card->wandev.network_number, 0);
+ /*If it's IPX change the network numbers to 0 if they're ours. */
+ if (skb->protocol == ETH_P_IPX) {
+ if (card->wandev.enable_IPX) {
+ switch_net_numbers(skb->data,
+ card->wandev.network_number, 0);
} else {
++card->wandev.stats.tx_dropped;
goto tx_done;
}
}
-
if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
-
retry = 1;
dev->tbusy = 1;
++ppp_priv_area->if_send_adptr_bfrs_full;
@@ -778,105 +696,160 @@ static int if_send (struct sk_buff* skb, struct device* dev)
ppp_priv_area->tick_counter = jiffies;
++card->wandev.stats.tx_errors;
flags->imask |= 0x02; /* unmask Tx interrupts */
-
} else {
++ppp_priv_area->if_send_bfr_passed_to_adptr;
++card->wandev.stats.tx_packets;
}
- }
-
-tx_done:
- if (!retry){
+ }
+tx_done:
+ if (!retry) {
dev_kfree_skb(skb);
}
-
card->wandev.critical = 0;
-
save_flags(host_cpu_flags);
- cli();
- if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
- enable_irq(card->hw.irq);
- restore_flags(host_cpu_flags);
-
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
return retry;
}
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return length of reply.
+ */
+
+static int reply_udp(unsigned char *data, unsigned int mbox_len)
+{
+ unsigned short len, udp_length, temp, i, ip_length;
+ unsigned long sum;
+ /* Set length of packet */
+ len = mbox_len + 60;
+ /* fill in UDP reply */
+ data[36] = 0x02;
+ /* fill in UDP length */
+ udp_length = mbox_len + 40;
+ /* put it on an even boundary */
+ if (udp_length & 0x0001) {
+ udp_length += 1;
+ len += 1;
+ }
+ temp = (udp_length << 8) | (udp_length >> 8);
+ memcpy(&data[24], &temp, 2);
+ /* swap UDP ports */
+ memcpy(&temp, &data[20], 2);
+ memcpy(&data[20], &data[22], 2);
+ memcpy(&data[22], &temp, 2);
+ /* add UDP pseudo header */
+ temp = 0x1100;
+ memcpy(&data[udp_length + 20], &temp, 2);
+ temp = (udp_length << 8) | (udp_length >> 8);
+ memcpy(&data[udp_length + 22], &temp, 2);
+ /* calculate UDP checksum */
+ data[26] = data[27] = 0;
+ sum = 0;
+ for (i = 0; i < udp_length + 12; i += 2) {
+ memcpy(&temp, &data[12 + i], 2);
+ sum += (unsigned long) temp;
+ }
+ while (sum >> 16) {
+ sum = (sum & 0xffffUL) + (sum >> 16);
+ }
+ temp = (unsigned short) sum;
+ temp = ~temp;
+ if (temp == 0)
+ temp = 0xffff;
+ memcpy(&data[26], &temp, 2);
+ /* fill in IP length */
+ ip_length = udp_length + 20;
+ temp = (ip_length << 8) | (ip_length >> 8);
+ memcpy(&data[2], &temp, 2);
+ /* swap IP addresses */
+ memcpy(&temp, &data[12], 2);
+ memcpy(&data[12], &data[16], 2);
+ memcpy(&data[16], &temp, 2);
+ memcpy(&temp, &data[14], 2);
+ memcpy(&data[14], &data[18], 2);
+ memcpy(&data[18], &temp, 2);
+ /* fill in IP checksum */
+ data[10] = data[11] = 0;
+ sum = 0;
+ for (i = 0; i < 20; i += 2) {
+ memcpy(&temp, &data[i], 2);
+ sum += (unsigned long) temp;
+ }
+ while (sum >> 16) {
+ sum = (sum & 0xffffUL) + (sum >> 16);
+ }
+ temp = (unsigned short) sum;
+ temp = ~temp;
+ if (temp == 0)
+ temp = 0xffff;
+ memcpy(&data[10], &temp, 2);
+ return len;
+} /* reply_udp */
+
/*
If incoming is 0 (outgoing)- if the net numbers is ours make it 0
if incoming is 1 - if the net number is 0 make it ours
+ */
-*/
static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
{
unsigned long pnetwork_number;
-
- pnetwork_number = (unsigned long)((sendpacket[6] << 24) +
- (sendpacket[7] << 16) + (sendpacket[8] << 8) +
- sendpacket[9]);
-
- if (!incoming)
- {
+ pnetwork_number = (unsigned long) ((sendpacket[6] << 24) +
+ (sendpacket[7] << 16) + (sendpacket[8] << 8) +
+ sendpacket[9]);
+ if (!incoming) {
/* If the destination network number is ours, make it 0 */
- if( pnetwork_number == network_number)
- {
- sendpacket[6] = sendpacket[7] = sendpacket[8] =
- sendpacket[9] = 0x00;
+ if (pnetwork_number == network_number) {
+ sendpacket[6] = sendpacket[7] = sendpacket[8] =
+ sendpacket[9] = 0x00;
}
- }
- else
- {
+ } else {
/* If the incoming network is 0, make it ours */
- if( pnetwork_number == 0)
- {
- sendpacket[6] = (unsigned char)(network_number >> 24);
- sendpacket[7] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[8] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[9] = (unsigned char)(network_number &
- 0x000000FF);
+ if (pnetwork_number == 0) {
+ sendpacket[6] = (unsigned char) (network_number >> 24);
+ sendpacket[7] = (unsigned char) ((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[8] = (unsigned char) ((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[9] = (unsigned char) (network_number &
+ 0x000000FF);
}
}
-
-
- pnetwork_number = (unsigned long)((sendpacket[18] << 24) +
- (sendpacket[19] << 16) + (sendpacket[20] << 8) +
- sendpacket[21]);
-
- if( !incoming )
- {
+ pnetwork_number = (unsigned long) ((sendpacket[18] << 24) +
+ (sendpacket[19] << 16) + (sendpacket[20] << 8) +
+ sendpacket[21]);
+ if (!incoming) {
/* If the source network is ours, make it 0 */
- if( pnetwork_number == network_number)
- {
- sendpacket[18] = sendpacket[19] = sendpacket[20] =
- sendpacket[21] = 0x00;
+ if (pnetwork_number == network_number) {
+ sendpacket[18] = sendpacket[19] = sendpacket[20] =
+ sendpacket[21] = 0x00;
}
- }
- else
- {
+ } else {
/* If the source network is 0, make it ours */
- if( pnetwork_number == 0 )
- {
- sendpacket[18] = (unsigned char)(network_number >> 24);
- sendpacket[19] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[20] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[21] = (unsigned char)(network_number &
- 0x000000FF);
+ if (pnetwork_number == 0) {
+ sendpacket[18] = (unsigned char) (network_number >> 24);
+ sendpacket[19] = (unsigned char) ((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[20] = (unsigned char) ((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[21] = (unsigned char) (network_number &
+ 0x000000FF);
}
}
-} /* switch_net_numbers */
+} /* switch_net_numbers */
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
-static struct net_device_stats* if_stats (struct device* dev)
-{
- ppp_private_area_t* ppp_priv_area = dev->priv;
- sdla_t* card = ppp_priv_area->card;
+static struct enet_statistics *if_stats(struct device *dev)
+{
+ ppp_private_area_t *ppp_priv_area = dev->priv;
+ sdla_t *card = ppp_priv_area->card;
return &card->wandev.stats;
}
@@ -886,146 +859,122 @@ static struct net_device_stats* if_stats (struct device* dev)
* Read firmware code version.
* Put code version as ASCII string in str.
*/
-static int ppp_read_version (sdla_t* card, char* str)
+
+static int ppp_read_version(sdla_t * card, char *str)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_READ_CODE_VERSION;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
if (err != CMD_OK)
-
ppp_error(card, err, mb);
-
else if (str) {
-
int len = mb->cmd.length;
-
memcpy(str, mb->data, len);
str[len] = '\0';
-
}
-
return err;
}
/*============================================================================
* Configure PPP firmware.
*/
-static int ppp_configure (sdla_t* card, void* data)
+
+static int ppp_configure(sdla_t * card, void *data)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int data_len = (card->hw.fwid == SFID_PPP502) ?
- sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
+ sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
memcpy(mb->data, data, data_len);
- mb->cmd.length = data_len;
+ mb->cmd.length = data_len;
mb->cmd.command = PPP_SET_CONFIG;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
ppp_error(card, err, mb);
-
return err;
}
/*============================================================================
* Set interrupt mode.
*/
-static int ppp_set_intr_mode (sdla_t* card, unsigned mode)
+
+static int ppp_set_intr_mode(sdla_t * card, unsigned mode)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->data[0] = mode;
-
- switch (card->hw.fwid)
- {
- case SFID_PPP502:
- mb->cmd.length = 1;
- break;
-
- case SFID_PPP508:
-
- default:
- mb->data[1] = card->hw.irq;
- mb->cmd.length = 2;
+ switch (card->hw.fwid) {
+ case SFID_PPP502:
+ mb->cmd.length = 1;
+ break;
+ case SFID_PPP508:
+ default:
+ mb->data[1] = card->hw.irq;
+ mb->cmd.length = 2;
}
-
mb->cmd.command = PPP_SET_INTR_FLAGS;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
ppp_error(card, err, mb);
-
return err;
}
/*============================================================================
* Enable communications.
*/
-static int ppp_comm_enable (sdla_t* card)
+
+static int ppp_comm_enable(sdla_t * card)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_COMM_ENABLE;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
ppp_error(card, err, mb);
-
return err;
}
/*============================================================================
* Disable communications.
*/
-static int ppp_comm_disable (sdla_t* card)
+
+static int ppp_comm_disable(sdla_t * card)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_COMM_DISABLE;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
ppp_error(card, err, mb);
-
return err;
}
/*============================================================================
* Get communications error statistics.
*/
-static int ppp_get_err_stats (sdla_t* card)
+
+static int ppp_get_err_stats(sdla_t * card)
{
- ppp_mbox_t* mb = card->mbox;
+ ppp_mbox_t *mb = card->mbox;
int err;
-
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_READ_ERROR_STATS;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err == CMD_OK)
- {
- ppp_err_stats_t* stats = (void*)mb->data;
- card->wandev.stats.rx_over_errors = stats->rx_overrun;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_abort;
- card->wandev.stats.rx_length_errors = stats->rx_lost;
+ if (err == CMD_OK) {
+ ppp_err_stats_t *stats = (void *) mb->data;
+ card->wandev.stats.rx_over_errors = stats->rx_overrun;
+ card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+ card->wandev.stats.rx_missed_errors = stats->rx_abort;
+ card->wandev.stats.rx_length_errors = stats->rx_lost;
card->wandev.stats.tx_aborted_errors = stats->tx_abort;
-
- } else
+ } else
ppp_error(card, err, mb);
-
return err;
}
@@ -1034,36 +983,27 @@ static int ppp_get_err_stats (sdla_t* card)
* Return: 0 - o.k.
* 1 - no transmit buffers available
*/
-
-static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto)
+
+static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
{
- ppp_buf_ctl_t* txbuf = card->u.p.txbuf;
+ ppp_buf_ctl_t *txbuf = card->u.p.txbuf;
unsigned long addr;
-
if (txbuf->flag)
- return 1;
-
+ return 1
+ ;
if (card->hw.fwid == SFID_PPP502)
- addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
- else
+ addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
+ else
addr = txbuf->buf.ptr;
-
-
sdla_poke(&card->hw, addr, data, len);
-
- txbuf->length = len; /* frame length */
-
+ txbuf->length = len; /* frame length */
if (proto == ETH_P_IPX)
txbuf->proto = 0x01; /* protocol ID */
-
- txbuf->flag = 1; /* start transmission */
-
+ txbuf->flag = 1; /* start transmission */
/* Update transmit buffer control fields */
card->u.p.txbuf = ++txbuf;
-
- if ((void*)txbuf > card->u.p.txbuf_last)
+ if ((void *) txbuf > card->u.p.txbuf_last)
card->u.p.txbuf = card->u.p.txbuf_base;
-
return 0;
}
@@ -1076,23 +1016,19 @@ static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto)
*
* Return zero if previous command has to be cancelled.
*/
-
-static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb)
+
+static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
{
unsigned cmd = mb->cmd.command;
-
- switch (err)
- {
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
- , card->devname, cmd, err);
+ switch (err) {
+ case CMD_TIMEOUT:
+ printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+ card->devname, cmd);
+ break;
+ default:
+ printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
+ ,card->devname, cmd, err);
}
-
return 0;
}
@@ -1101,81 +1037,65 @@ static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb)
/*============================================================================
* PPP interrupt service routine.
*/
-STATIC void wpp_isr (sdla_t* card)
+
+STATIC void wpp_isr(sdla_t * card)
{
- ppp_flags_t* flags = card->flags;
+ ppp_flags_t *flags = card->flags;
char *ptr = &flags->iflag;
unsigned long host_cpu_flags;
- struct device* dev = card->wandev.dev;
+ struct device *dev = card->wandev.dev;
int i;
-
card->in_isr = 1;
-
++card->statistics.isr_entry;
-
- if (set_bit(0, (void*)&card->wandev.critical)) {
-
+ if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
++card->statistics.isr_already_critical;
- printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname);
+ printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname);
card->in_isr = 0;
return;
-
}
-
/* For all interrupts set the critical flag to CRITICAL_IN_ISR.
* If the if_send routine is called with this flag set it will set
* the enable transmit flag to 1. (for a delayed interrupt)
*/
card->wandev.critical = CRITICAL_IN_ISR;
-
card->buff_int_mode_unbusy = 0;
-
switch (flags->iflag) {
-
- case 0x01: /* receive interrupt */
- ++card->statistics.isr_rx;
- rx_intr(card);
- break;
-
- case 0x02: /* transmit interrupt */
- ++card->statistics.isr_tx;
- flags->imask &= ~0x02;
- dev->tbusy = 0;
- card->buff_int_mode_unbusy = 1;
- break;
-
- case 0x08:
- ++Intr_test_counter;
- ++card->statistics.isr_intr_test;
- break;
-
- default: /* unexpected interrupt */
- ++card->statistics.isr_spurious;
- printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
- card->devname, flags->iflag);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
+ case 0x01: /* receive interrupt */
+ ++card->statistics.isr_rx;
+ rx_intr(card);
+ break;
+ case 0x02: /* transmit interrupt */
+ ++card->statistics.isr_tx;
+ flags->imask &= ~0x02;
+ dev->tbusy = 0;
+ card->buff_int_mode_unbusy = 1;
+ break;
+ case 0x08:
+ ++Intr_test_counter;
+ ++card->statistics.isr_intr_test;
+ break;
+ default: /* unexpected interrupt */
+ ++card->statistics.isr_spurious;
+ printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
+ card->devname, flags->iflag);
+ printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+ for (i = 0; i < 8; i++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
}
-
/* The critical flag is set to CRITICAL_INTR_HANDLED to let the
* if_send call know that the interrupt is handled so that
* transmit interrupts are not enabled again.
- */
-
+ */
card->wandev.critical = CRITICAL_INTR_HANDLED;
-
/* If the enable transmit interrupt flag is set then enable transmit
* interrupt on the board. This only goes through if if_send is called
* and the critical flag is set due to an Interrupt.
*/
- if(card->wandev.enable_tx_int) {
-
+ if (card->wandev.enable_tx_int) {
flags->imask |= 0x02;
card->wandev.enable_tx_int = 0;
++card->statistics.isr_enable_tx_int;
-
}
save_flags(host_cpu_flags);
cli();
@@ -1183,236 +1103,174 @@ STATIC void wpp_isr (sdla_t* card)
flags->iflag = 0;
card->wandev.critical = 0;
restore_flags(host_cpu_flags);
-
- if(card->buff_int_mode_unbusy)
+ if (card->buff_int_mode_unbusy)
mark_bh(NET_BH);
-
}
/*============================================================================
* Receive interrupt handler.
*/
-static void rx_intr (sdla_t* card)
+
+static void rx_intr(sdla_t * card)
{
- ppp_buf_ctl_t* rxbuf = card->rxmb;
- struct device* dev = card->wandev.dev;
- ppp_private_area_t* ppp_priv_area;
- struct sk_buff* skb;
+ ppp_buf_ctl_t *rxbuf = card->rxmb;
+ struct device *dev = card->wandev.dev;
+ ppp_private_area_t *ppp_priv_area;
+ struct sk_buff *skb;
unsigned len;
- void* buf;
+ void *buf;
int i, err;
- ppp_flags_t* flags = card->flags;
- char *ptr = &flags->iflag;
+ ppp_flags_t *flags = card->flags;
+ char *ptr = &flags->iflag;
int udp_type;
-
-
if (rxbuf->flag != 0x01) {
-
-
- printk(KERN_INFO
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
- card->devname, (unsigned)rxbuf, rxbuf->flag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
-
- for(i = 0; i < 8; i ++)
+ printk(KERN_INFO
+ "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
+ card->devname, (unsigned) rxbuf, rxbuf->flag);
+ printk(KERN_INFO "%s: ID Bytes = ", card->devname);
+ for (i = 0; i < 8; i++)
printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
-
+ printk(KERN_INFO "\n");
++card->statistics.rx_intr_corrupt_rx_bfr;
return;
-
}
-
-
if (dev && dev->start) {
-
- len = rxbuf->length;
+ len = rxbuf->length;
ppp_priv_area = dev->priv;
-
/* Allocate socket buffer */
skb = dev_alloc_skb(len);
-
if (skb != NULL) {
-
/* Copy data to the socket buffer */
if (card->hw.fwid == SFID_PPP502) {
-
- unsigned addr = (rxbuf->buf.o_p[1] << 8) +
- rxbuf->buf.o_p[0];
+ unsigned addr = (rxbuf->buf.o_p[1] << 8) +
+ rxbuf->buf.o_p[0];
buf = skb_put(skb, len);
sdla_peek(&card->hw, addr, buf, len);
-
} else {
-
unsigned addr = rxbuf->buf.ptr;
-
if ((addr + len) > card->u.p.rx_top + 1) {
-
- unsigned tmp = card->u.p.rx_top - addr
- + 1;
+ unsigned tmp = card->u.p.rx_top - addr
+ + 1;
buf = skb_put(skb, tmp);
sdla_peek(&card->hw, addr, buf, tmp);
addr = card->u.p.rx_base;
len -= tmp;
-
}
-
buf = skb_put(skb, len);
sdla_peek(&card->hw, addr, buf, len);
}
-
/* Decapsulate packet */
- switch (rxbuf->proto) {
-
- case 0x00:
- skb->protocol = htons(ETH_P_IP);
- break;
-
- case 0x01:
- skb->protocol = htons(ETH_P_IPX);
- break;
+ switch (rxbuf->proto) {
+ case 0x00:
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case 0x01:
+ skb->protocol = htons(ETH_P_IPX);
+ break;
}
-#ifdef CONFIG_SANGOMA_MANAGER
- udp_type = udp_pkt_type( skb, card );
-
- if (udp_type == UDP_DRVSTATS_TYPE){
- ++ppp_priv_area->rx_intr_DRVSTATS_request;
+ udp_type = udp_pkt_type(skb, card);
+ if (udp_type == UDP_DRVSTATS_TYPE) {
+ ++ppp_priv_area->rx_intr_DRVSTATS_request;
process_udp_driver_call(
- UDP_PKT_FRM_NETWORK, card, skb,
- dev, ppp_priv_area);
- dev_kfree_skb(skb);
-
- } else if (udp_type == UDP_PTPIPE_TYPE){
+ UDP_PKT_FRM_NETWORK, card, skb,
+ dev, ppp_priv_area);
+ dev_kfree_skb(skb);
+ } else if (udp_type == UDP_PTPIPE_TYPE) {
++ppp_priv_area->rx_intr_PTPIPE_request;
err = process_udp_mgmt_pkt(
- UDP_PKT_FRM_NETWORK, card,
- skb, dev, ppp_priv_area);
+ UDP_PKT_FRM_NETWORK, card,
+ skb, dev, ppp_priv_area);
dev_kfree_skb(skb);
- } else
-#endif
- if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
-
- if( card->wandev.enable_IPX) {
+ } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
+ if (card->wandev.enable_IPX) {
ppp_send(card, skb->data, skb->len, ETH_P_IPX);
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
} else {
++card->wandev.stats.rx_dropped;
}
} else {
/* Pass it up the protocol stack */
- skb->dev = dev;
- skb->mac.raw = skb->data;
- netif_rx(skb);
- ++card->wandev.stats.rx_packets;
- ++ppp_priv_area->rx_intr_bfr_passed_to_stack;
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ ++card->wandev.stats.rx_packets;
+ ++ppp_priv_area->rx_intr_bfr_passed_to_stack;
}
-
} else {
-
printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
+ card->devname);
++card->wandev.stats.rx_dropped;
++ppp_priv_area->rx_intr_no_socket;
-
}
-
} else
++card->statistics.rx_intr_dev_not_started;
-
/* Release buffer element and calculate a pointer to the next one */
rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
card->rxmb = ++rxbuf;
-
- if ((void*)rxbuf > card->u.p.rxbuf_last)
+ if ((void *) rxbuf > card->u.p.rxbuf_last)
card->rxmb = card->u.p.rxbuf_base;
}
/*============================================================================
* Transmit interrupt handler.
*/
-static void tx_intr (sdla_t* card)
-{
- struct device* dev = card->wandev.dev;
- if (!dev || !dev->start)
- {
+static void tx_intr(sdla_t * card)
+{
+ struct device *dev = card->wandev.dev;
+ if (!dev || !dev->start) {
++card->statistics.tx_intr_dev_not_started;
- return;
- }
-
+ return;
+ }
dev->tbusy = 0;
- dev_tint(dev);
+ mark_bh(NET_BH);
}
static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
{
int i;
-
- if( proto == htons(ETH_P_IPX) )
- {
+ if (proto == htons(ETH_P_IPX)) {
/* It's an IPX packet */
- if(!enable_IPX)
- {
- //Return 1 so we don't pass it up the stack.
+ if (!enable_IPX) {
+ /* Return 1 so we don't pass it up the stack. */
return 1;
}
- }
- else
- {
+ } else {
/* It's not IPX so pass it up the stack. */
return 0;
}
-
- if( sendpacket[16] == 0x90 &&
- sendpacket[17] == 0x04)
- {
+ if (sendpacket[16] == 0x90 &&
+ sendpacket[17] == 0x04) {
/* It's IPXWAN */
-
- if( sendpacket[2] == 0x02 &&
- sendpacket[34] == 0x00)
- {
+ if (sendpacket[2] == 0x02 &&
+ sendpacket[34] == 0x00) {
/* It's a timer request packet */
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
-
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
/* Go through the routing options and answer no to every */
/* option except Unnumbered RIP/SAP */
- for(i = 41; sendpacket[i] == 0x00; i += 5)
- {
+ for (i = 41; sendpacket[i] == 0x00; i += 5) {
/* 0x02 is the option for Unnumbered RIP/SAP */
- if( sendpacket[i + 4] != 0x02)
- {
+ if (sendpacket[i + 4] != 0x02) {
sendpacket[i + 1] = 0;
}
}
-
/* Skip over the extended Node ID option */
- if( sendpacket[i] == 0x04 )
- {
+ if (sendpacket[i] == 0x04) {
i += 8;
}
-
/* We also want to turn off all header compression opt. */
- for(; sendpacket[i] == 0x80 ;)
- {
+ for (; sendpacket[i] == 0x80;) {
sendpacket[i + 1] = 0;
i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
}
-
/* Set the packet type to timer response */
sendpacket[34] = 0x01;
-
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
- }
- else if( sendpacket[34] == 0x02 )
- {
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
+ } else if (sendpacket[34] == 0x02) {
/* This is an information request packet */
- printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
-
+ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
/* Set the packet type to information response */
sendpacket[34] = 0x03;
-
/* Set the router name */
sendpacket[51] = 'P';
sendpacket[52] = 'T';
@@ -1422,38 +1280,30 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
sendpacket[56] = 'E';
sendpacket[57] = '-';
sendpacket[58] = CVHexToAscii(network_number >> 28);
- sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+ sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24);
+ sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20);
+ sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16);
+ sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12);
+ sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8);
+ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4);
sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 66; i < 99; i+= 1)
- {
+ for (i = 66; i < 99; i += 1)
sendpacket[i] = 0;
- }
-
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
- }
- else
- {
- printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
+ } else {
+ printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
return 0;
}
-
/* Set the WNodeID to our network address */
- sendpacket[35] = (unsigned char)(network_number >> 24);
- sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
-
+ sendpacket[35] = (unsigned char) (network_number >> 24);
+ sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
+ sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
+ sendpacket[38] = (unsigned char) (network_number & 0x000000FF);
return 1;
} else {
/* If we get here's its an IPX-data packet, so it'll get passed up the stack. */
-
/* switch the network numbers */
- switch_net_numbers(sendpacket, network_number, 1);
+ switch_net_numbers(sendpacket, network_number, 1);
return 0;
}
}
@@ -1469,100 +1319,80 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
* 1. This routine may be called on interrupt context with all interrupts
* enabled. Beware!
*/
-static void wpp_poll (sdla_t* card)
+
+static void wpp_poll(sdla_t * card)
{
- struct device* dev = card->wandev.dev;
- ppp_flags_t* adptr_flags = card->flags;
+ struct device *dev = card->wandev.dev;
+ ppp_flags_t *adptr_flags = card->flags;
unsigned long host_cpu_flags;
-
++card->statistics.poll_entry;
-
/* The wpp_poll is called continously by the WANPIPE thread to allow
* for line state housekeeping. However if we are in a connected state
* then we do not need to go through all the checks everytime. When in
* connected state execute wpp_poll once every second.
*/
-
- if (card->wandev.state == WAN_CONNECTED)
- {
- if ((jiffies - card->state_tick) < HZ )
- return;
+ if (card->wandev.state == WAN_CONNECTED) {
+ if ((jiffies - card->state_tick) < HZ)
+ return;
}
-
- disable_irq(card->hw.irq);
- ++card->irq_dis_poll_count;
-
- if (set_bit(0, (void *)&card->wandev.critical))
- {
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_poll_count;
+ if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
++card->statistics.poll_already_critical;
- printk(KERN_INFO "%s: critical inside wpp_poll\n",
- card->devname);
+ printk(KERN_INFO "%s: critical inside wpp_poll\n",
+ card->devname);
save_flags(host_cpu_flags);
- cli();
- if ((!card->irq_dis_if_send_count) &&
- (!(--card->irq_dis_poll_count)))
- enable_irq(card->hw.irq);
- restore_flags(host_cpu_flags);
-
+ cli();
+ if ((!card->irq_dis_if_send_count) &&
+ (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
return;
}
-
- ++card->statistics.poll_processed;
-
- if (dev && dev->tbusy && !(adptr_flags->imask & 0x02))
- {
+ ++card->statistics.poll_processed;
+ if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) {
++card->statistics.poll_tbusy_bad_status;
printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n"
- , card->devname, adptr_flags->imask);
- }
-
- switch(card->wandev.state)
- {
- case WAN_CONNECTED:
- card->state_tick = jiffies;
- poll_active(card);
- break;
-
- case WAN_CONNECTING:
- poll_connecting(card);
- break;
-
- case WAN_DISCONNECTED:
- poll_disconnected(card);
- break;
-
- default:
- printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
- card->devname, card->wandev.state);
- break;
+ ,card->devname, adptr_flags->imask);
+ }
+ switch (card->wandev.state) {
+ case WAN_CONNECTED:
+ card->state_tick = jiffies;
+ poll_active(card);
+ break;
+ case WAN_CONNECTING:
+ poll_connecting(card);
+ break;
+ case WAN_DISCONNECTED:
+ poll_disconnected(card);
+ break;
+ default:
+ printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
+ card->devname, card->wandev.state);
+ break;
}
-
card->wandev.critical = 0;
-
save_flags(host_cpu_flags);
- cli();
- if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
- enable_irq(card->hw.irq);
- restore_flags(host_cpu_flags);
-
+ cli();
+ if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
}
/*============================================================================
* Monitor active link phase.
*/
-static void poll_active (sdla_t* card)
-{
- ppp_flags_t* flags = card->flags;
+static void poll_active(sdla_t * card)
+{
+ ppp_flags_t *flags = card->flags;
/* We check the lcp_state to see if we are in DISCONNECTED state.
* We are considered to be connected for lcp states 0x06, 0x07, 0x08
* and 0x09.
*/
if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) {
-
wanpipe_set_state(card, WAN_DISCONNECTED);
show_disc_cause(card, flags->disc_cause);
-
}
}
@@ -1570,16 +1400,13 @@ static void poll_active (sdla_t* card)
* Monitor link establishment phase.
* o if connection timed out, disconnect the link.
*/
-static void poll_connecting (sdla_t* card)
+
+static void poll_connecting(sdla_t * card)
{
- ppp_flags_t* flags = card->flags;
-
- if (flags->lcp_state == 0x09)
- {
+ ppp_flags_t *flags = card->flags;
+ if (flags->lcp_state == 0x09) {
wanpipe_set_state(card, WAN_CONNECTED);
- }
- else if (flags->disc_cause & 0x03)
- {
+ } else if (flags->disc_cause & 0x03) {
wanpipe_set_state(card, WAN_DISCONNECTED);
show_disc_cause(card, flags->disc_cause);
}
@@ -1590,16 +1417,15 @@ static void poll_connecting (sdla_t* card)
* o if interface is up and the hold-down timeout has expired, then retry
* connection.
*/
-static void poll_disconnected (sdla_t* card)
-{
- struct device* dev = card->wandev.dev;
+static void poll_disconnected(sdla_t * card)
+{
+ struct device *dev = card->wandev.dev;
if (dev && dev->start &&
- ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
- {
- wanpipe_set_state(card, WAN_CONNECTING);
- if(ppp_comm_enable(card) == CMD_OK)
- init_ppp_tx_rx_buff( card );
+ ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
+ wanpipe_set_state(card, WAN_CONNECTING);
+ if (ppp_comm_enable(card) == CMD_OK)
+ init_ppp_tx_rx_buff(card);
}
}
@@ -1608,319 +1434,818 @@ static void poll_disconnected (sdla_t* card)
/*============================================================================
* Configure S502 adapter.
*/
-static int config502 (sdla_t* card)
+
+static int config502(sdla_t * card)
{
ppp502_conf_t cfg;
-
/* Prepare PPP configuration structure */
memset(&cfg, 0, sizeof(ppp502_conf_t));
-
if (card->wandev.clocking)
cfg.line_speed = bps_to_speed_code(card->wandev.bps);
-
- cfg.txbuf_num = 4;
- cfg.mtu_local = card->wandev.mtu;
- cfg.mtu_remote = card->wandev.mtu;
- cfg.restart_tmr = 30;
- cfg.auth_rsrt_tmr = 30;
- cfg.auth_wait_tmr = 300;
- cfg.mdm_fail_tmr = 5;
- cfg.dtr_drop_tmr = 1;
- cfg.connect_tmout = 0; /* changed it from 900 */
- cfg.conf_retry = 10;
- cfg.term_retry = 2;
- cfg.fail_retry = 5;
- cfg.auth_retry = 10;
- cfg.ip_options = 0x80;
- cfg.ipx_options = 0xA0;
- cfg.conf_flags |= 0x0E;
+ cfg.txbuf_num = 4;
+ cfg.mtu_local = card->wandev.mtu;
+ cfg.mtu_remote = card->wandev.mtu;
+ cfg.restart_tmr = 30;
+ cfg.auth_rsrt_tmr = 30;
+ cfg.auth_wait_tmr = 300;
+ cfg.mdm_fail_tmr = 5;
+ cfg.dtr_drop_tmr = 1;
+ cfg.connect_tmout = 0; /* changed it from 900 */
+ cfg.conf_retry = 10;
+ cfg.term_retry = 2;
+ cfg.fail_retry = 5;
+ cfg.auth_retry = 10;
+ cfg.ip_options = 0x80;
+ cfg.ipx_options = 0xA0;
+ cfg.conf_flags |= 0x0E;
/*
- cfg.ip_local = dev->pa_addr;
- cfg.ip_remote = dev->pa_dstaddr;
-*/
+ cfg.ip_local = dev->pa_addr;
+ cfg.ip_remote = dev->pa_dstaddr;
+ */
return ppp_configure(card, &cfg);
}
/*============================================================================
* Configure S508 adapter.
*/
-static int config508 (sdla_t* card)
+
+static int config508(sdla_t * card)
{
ppp508_conf_t cfg;
-
/* Prepare PPP configuration structure */
memset(&cfg, 0, sizeof(ppp508_conf_t));
-
if (card->wandev.clocking)
cfg.line_speed = card->wandev.bps;
-
if (card->wandev.interface == WANOPT_RS232)
cfg.conf_flags |= 0x0020;
-
- cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/
- cfg.txbuf_percent = 60; /* % of Tx bufs */
- cfg.mtu_local = card->wandev.mtu;
- cfg.mtu_remote = card->wandev.mtu;
- cfg.restart_tmr = 30;
- cfg.auth_rsrt_tmr = 30;
- cfg.auth_wait_tmr = 300;
- cfg.mdm_fail_tmr = 100;
- cfg.dtr_drop_tmr = 1;
- cfg.connect_tmout = 0; /* changed it from 900 */
- cfg.conf_retry = 10;
- cfg.term_retry = 2;
- cfg.fail_retry = 5;
- cfg.auth_retry = 10;
- cfg.ip_options = 0x80;
- cfg.ipx_options = 0xA0;
+ cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */
+ cfg.txbuf_percent = 60; /* % of Tx bufs */
+ cfg.mtu_local = card->wandev.mtu;
+ cfg.mtu_remote = card->wandev.mtu;
+ cfg.restart_tmr = 30;
+ cfg.auth_rsrt_tmr = 30;
+ cfg.auth_wait_tmr = 300;
+ cfg.mdm_fail_tmr = 100;
+ cfg.dtr_drop_tmr = 1;
+ cfg.connect_tmout = 0; /* changed it from 900 */
+ cfg.conf_retry = 10;
+ cfg.term_retry = 2;
+ cfg.fail_retry = 5;
+ cfg.auth_retry = 10;
+ cfg.ip_options = 0x80;
+ cfg.ipx_options = 0xA0;
/*
- cfg.ip_local = dev->pa_addr;
- cfg.ip_remote = dev->pa_dstaddr;
-*/
+ cfg.ip_local = dev->pa_addr;
+ cfg.ip_remote = dev->pa_dstaddr;
+ */
return ppp_configure(card, &cfg);
}
/*============================================================================
* Show disconnection cause.
*/
-static void show_disc_cause (sdla_t* card, unsigned cause)
-{
- if (cause & 0x0002)
- printk(KERN_INFO "%s: link terminated by peer\n",
- card->devname);
- else if (cause & 0x0004)
- printk(KERN_INFO "%s: link terminated by user\n",
- card->devname);
-
- else if (cause & 0x0008)
+static void show_disc_cause(sdla_t * card, unsigned cause)
+{
+ if (cause & 0x0002)
+ printk(KERN_INFO "%s: link terminated by peer\n",
+ card->devname);
+ else if (cause & 0x0004)
+ printk(KERN_INFO "%s: link terminated by user\n",
+ card->devname);
+ else if (cause & 0x0008)
printk(KERN_INFO "%s: authentication failed\n", card->devname);
-
else if (cause & 0x0010)
- printk(KERN_INFO
- "%s: authentication protocol negotiation failed\n",
- card->devname);
-
- else if (cause & 0x0020)
printk(KERN_INFO
- "%s: peer's request for authentication rejected\n",
- card->devname);
-
- else if (cause & 0x0040)
- printk(KERN_INFO "%s: MRU option rejected by peer\n",
- card->devname);
-
- else if (cause & 0x0080)
- printk(KERN_INFO "%s: peer's MRU was too small\n",
- card->devname);
-
- else if (cause & 0x0100)
+ "%s: authentication protocol negotiation failed\n",
+ card->devname);
+ else if (cause & 0x0020)
+ printk(KERN_INFO
+ "%s: peer's request for authentication rejected\n",
+ card->devname);
+ else if (cause & 0x0040)
+ printk(KERN_INFO "%s: MRU option rejected by peer\n",
+ card->devname);
+ else if (cause & 0x0080)
+ printk(KERN_INFO "%s: peer's MRU was too small\n",
+ card->devname);
+ else if (cause & 0x0100)
printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n",
- card->devname);
-
- else if (cause & 0x0200)
+ card->devname);
+ else if (cause & 0x0200)
printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n"
- , card->devname);
-
- else if (cause & 0x0400)
- printk(KERN_INFO
- "%s: failed to negotiate peer's IPXCP options\n",
- card->devname);
+ ,card->devname);
+ else if (cause & 0x0400)
+ printk(KERN_INFO
+ "%s: failed to negotiate peer's IPXCP options\n",
+ card->devname);
}
/*============================================================================
* Convert line speed in bps to a number used by S502 code.
*/
-static unsigned char bps_to_speed_code (unsigned long bps)
-{
- unsigned char number;
- if (bps <= 1200)
+static unsigned char bps_to_speed_code(unsigned long bps)
+{
+ unsigned char number;
+ if (bps <= 1200)
number = 0x01;
- else if (bps <= 2400)
+ else if (bps <= 2400)
number = 0x02;
- else if (bps <= 4800)
+ else if (bps <= 4800)
number = 0x03;
- else if (bps <= 9600)
+ else if (bps <= 9600)
number = 0x04;
- else if (bps <= 19200)
+ else if (bps <= 19200)
number = 0x05;
- else if (bps <= 38400)
+ else if (bps <= 38400)
number = 0x06;
- else if (bps <= 45000)
+ else if (bps <= 45000)
number = 0x07;
- else if (bps <= 56000)
+ else if (bps <= 56000)
number = 0x08;
- else if (bps <= 64000)
+ else if (bps <= 64000)
number = 0x09;
- else if (bps <= 74000)
+ else if (bps <= 74000)
number = 0x0A;
- else if (bps <= 112000)
+ else if (bps <= 112000)
number = 0x0B;
- else if (bps <= 128000)
+ else if (bps <= 128000)
number = 0x0C;
- else
+ else
number = 0x0D;
-
return number;
}
+/*============================================================================
+ * Process UDP call of type DRVSTATS.
+ */
+
+static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area)
+{
+ unsigned char *sendpacket;
+ unsigned char buf2[5];
+ unsigned char *data;
+ unsigned char *buf;
+ unsigned int len;
+ ppp_mbox_t *mbox = card->mbox;
+ struct sk_buff *new_skb;
+ int err;
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
+ printk(KERN_INFO
+ "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
+ ,card->devname, data[45]);
+ ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
+ return 1;
+ }
+ memcpy(data, sendpacket, skb->len);
+ switch (data[45]) {
+ /* PPIPE_DRIVER_STATISTICS */
+ case 0x26:
+ *(unsigned long *) &data[60] =
+ ppp_priv_area->if_send_entry;
+ *(unsigned long *) &data[64] =
+ ppp_priv_area->if_send_skb_null;
+ *(unsigned long *) &data[68] =
+ ppp_priv_area->if_send_broadcast;
+ *(unsigned long *) &data[72] =
+ ppp_priv_area->if_send_multicast;
+ *(unsigned long *) &data[76] =
+ ppp_priv_area->if_send_critical_ISR;
+ *(unsigned long *) &data[80] =
+ ppp_priv_area->if_send_critical_non_ISR;
+ *(unsigned long *) &data[84] =
+ ppp_priv_area->if_send_busy;
+ *(unsigned long *) &data[88] =
+ ppp_priv_area->if_send_busy_timeout;
+ *(unsigned long *) &data[92] =
+ ppp_priv_area->if_send_DRVSTATS_request;
+ *(unsigned long *) &data[96] =
+ ppp_priv_area->if_send_PTPIPE_request;
+ *(unsigned long *) &data[100] =
+ ppp_priv_area->if_send_wan_disconnected;
+ *(unsigned long *) &data[104] =
+ ppp_priv_area->if_send_adptr_bfrs_full;
+ *(unsigned long *) &data[108] =
+ ppp_priv_area->if_send_protocol_error;
+ *(unsigned long *) &data[112] =
+ ppp_priv_area->if_send_tx_int_enabled;
+ *(unsigned long *) &data[116] =
+ ppp_priv_area->if_send_bfr_passed_to_adptr;
+ *(unsigned long *) &data[118] =
+ card->irq_dis_if_send_count;
+ mbox->cmd.length = 62;
+ break;
+ case 0x27:
+ *(unsigned long *) &data[60] = card->statistics.isr_entry;
+ *(unsigned long *) &data[64] =
+ card->statistics.isr_already_critical;
+ *(unsigned long *) &data[68] = card->statistics.isr_rx;
+ *(unsigned long *) &data[72] = card->statistics.isr_tx;
+ *(unsigned long *) &data[76] =
+ card->statistics.isr_intr_test;
+ *(unsigned long *) &data[80] =
+ card->statistics.isr_spurious;
+ *(unsigned long *) &data[84] =
+ card->statistics.isr_enable_tx_int;
+ *(unsigned long *) &data[88] =
+ card->statistics.rx_intr_corrupt_rx_bfr;
+ *(unsigned long *) &data[92] =
+ ppp_priv_area->rx_intr_no_socket;
+ *(unsigned long *) &data[96] =
+ ppp_priv_area->rx_intr_DRVSTATS_request;
+ *(unsigned long *) &data[100] =
+ ppp_priv_area->rx_intr_PTPIPE_request;
+ *(unsigned long *) &data[104] =
+ ppp_priv_area->rx_intr_bfr_passed_to_stack;
+ *(unsigned long *) &data[108] =
+ card->statistics.rx_intr_dev_not_started;
+ *(unsigned long *) &data[112] =
+ card->statistics.tx_intr_dev_not_started;
+ mbox->cmd.length = 56;
+ break;
+ case 0x28:
+ *(unsigned long *) &data[60] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
+ *(unsigned long *) &data[64] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
+ *(unsigned long *) &data[68] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
+ *(unsigned long *) &data[72] =
+ ppp_priv_area->
+ UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+ *(unsigned long *) &data[76] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+ *(unsigned long *) &data[80] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
+ *(unsigned long *) &data[84] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
+ *(unsigned long *) &data[88] =
+ ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
+ *(unsigned long *) &data[92] =
+ ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
+ *(unsigned long *) &data[96] =
+ ppp_priv_area->
+ UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ *(unsigned long *) &data[100] =
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ *(unsigned long *) &data[104] =
+ ppp_priv_area->
+ UDP_DRVSTATS_mgmt_passed_to_adptr;
+ *(unsigned long *) &data[108] =
+ ppp_priv_area->
+ UDP_DRVSTATS_mgmt_passed_to_stack;
+ *(unsigned long *) &data[112] =
+ ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
+ *(unsigned long *) &data[116] =
+ card->statistics.poll_entry;
+ *(unsigned long *) &data[120] =
+ card->statistics.poll_already_critical;
+ *(unsigned long *) &data[124] =
+ card->statistics.poll_processed;
+ *(unsigned long *) &data[126] =
+ card->irq_dis_poll_count;
+ mbox->cmd.length = 70;
+ break;
+ default:
+ /* it's a board command */
+ memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
+ if (mbox->cmd.length) {
+ memcpy(&mbox->data, &sendpacket[60],
+ mbox->cmd.length);
+ }
+ /* run the command on the board */
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ if (err != CMD_OK) {
+ ppp_error(card, err, mbox);
+ ++ppp_priv_area->
+ UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ break;
+ }
+ ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ /* copy the result back to our buffer */
+ memcpy(data, sendpacket, skb->len);
+ memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
+ if (mbox->cmd.length) {
+ memcpy(&data[60], &mbox->data, mbox->cmd.length);
+ }
+ }
+ /* Fill UDP TTL */
+ data[8] = card->wandev.ttl;
+ len = reply_udp(data, mbox->cmd.length);
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+ ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr;
+ ppp_send(card, data, len, skb->protocol);
+ } else {
+ /* Pass it up the stack
+ Allocate socket buffer */
+ if ((new_skb = dev_alloc_skb(len)) != NULL) {
+ /* copy data into new_skb */
+ buf = skb_put(new_skb, len);
+ memcpy(buf, data, len);
+ ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack;
+ /* Decapsulate packet and pass it up the protocol
+ stack */
+ new_skb->protocol = htons(ETH_P_IP);
+ new_skb->dev = dev;
+ new_skb->mac.raw = new_skb->data;
+ netif_rx(new_skb);
+ } else {
+ ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
+ printk(KERN_INFO "no socket buffers available!\n");
+ }
+ }
+ kfree(data);
+ return 0;
+}
+
+/*=============================================================================
+ * Process UDP call of type PTPIPEAB.
+ */
+
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card,
+ struct sk_buff *skb, struct device *dev,
+ ppp_private_area_t * ppp_priv_area)
+{
+ unsigned char *sendpacket;
+ unsigned char buf2[5];
+ unsigned char *data;
+ unsigned char *buf;
+ unsigned int frames, len;
+ struct sk_buff *new_skb;
+ unsigned short buffer_length, real_len;
+ unsigned long data_ptr;
+ int udp_mgmt_req_valid = 1;
+ ppp_mbox_t *mbox = card->mbox;
+ struct timeval tv;
+ int err;
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
+ printk(KERN_INFO
+ "%s: Error allocating memory for UDP management cmnd0x%02X"
+ ,card->devname, data[45]);
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
+ return 1;
+ }
+ memcpy(data, sendpacket, skb->len);
+ switch (data[45]) {
+ /* FT1 MONITOR STATUS */
+ case 0x80:
+ if (card->hw.fwid != SFID_PPP508) {
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
+ udp_mgmt_req_valid = 0;
+ break;
+ }
+ /* PPIPE_ENABLE_TRACING */
+ case 0x20:
+ /* PPIPE_DISABLE_TRACING */
+ case 0x21:
+ /* PPIPE_GET_TRACE_INFO */
+ case 0x22:
+ /* SET FT1 MODE */
+ case 0x81:
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
+ udp_mgmt_req_valid = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!udp_mgmt_req_valid) {
+ /* set length to 0 */
+ data[46] = data[47] = 0;
+ /* set return code */
+ data[48] = 0xCD;
+ } else {
+ switch (data[45]) {
+ /* PPIPE_ENABLE_TRACING */
+ case 0x20:
+ if (!TracingEnabled) {
+ /* OPERATE_DATALINE_MONITOR */
+ mbox->cmd.command = 0x33;
+ mbox->cmd.length = 1;
+ mbox->data[0] = 0x03;
+ err = sdla_exec(mbox) ?
+ mbox->cmd.result : CMD_TIMEOUT;
+ if (err != CMD_OK) {
+ ppp_error(card, err, mbox);
+ TracingEnabled = 0;
+ /* set the return code */
+ data[48] = mbox->cmd.result;
+ mbox->cmd.length = 0;
+ break;
+ }
+ if (card->hw.fwid == SFID_PPP502) {
+ sdla_peek(&card->hw, 0x9000, &buf2, 2);
+ } else {
+ sdla_peek(&card->hw, 0xC000, &buf2, 2);
+ }
+ curr_trace_addr = 0;
+ memcpy(&curr_trace_addr, &buf2, 2);
+ start_trace_addr = curr_trace_addr;
+ /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET)
+ - 41 */
+ available_buffer_space = 1926;
+ }
+ data[48] = 0;
+ mbox->cmd.length = 0;
+ TracingEnabled = 1;
+ break;
+ /* PPIPE_DISABLE_TRACING */
+ case 0x21:
+ if (TracingEnabled) {
+ /* OPERATE_DATALINE_MONITOR */
+ mbox->cmd.command = 0x3;
+ mbox->cmd.length = 1;
+ mbox->data[0] = 0x00;
+ err = sdla_exec(mbox) ?
+ mbox->cmd.result : CMD_TIMEOUT;
+ }
+ /*set return code */
+ data[48] = 0;
+ mbox->cmd.length = 0;
+ TracingEnabled = 0;
+ break;
+ /* PPIPE_GET_TRACE_INFO */
+ case 0x22:
+ if (TracingEnabled) {
+ buffer_length = 0;
+ /* frames < NUM_TRACE_FRAMES */
+ for (frames = 0; frames < 62; frames += 1) {
+ sdla_peek(&card->hw, curr_trace_addr,
+ &buf2, 1);
+ /* no data on board so exit */
+ if (buf2[0] == 0x00)
+ break;
+ /*1+sizeof(FRAME_DATA) = 9 */
+ if ((available_buffer_space -
+ buffer_length) < 9) {
+ /*indicate we have more frames
+ on board and exit */
+ data[60] |= 0x02;
+ break;
+ }
+ /* get frame status */
+ sdla_peek(&card->hw, curr_trace_addr +
+ 0x01, &data[60 + buffer_length], 1);
+ /* get time stamp */
+ sdla_peek(&card->hw, curr_trace_addr +
+ 0x06, &data[64 + buffer_length], 2);
+ /* get frame length */
+ sdla_peek(&card->hw, curr_trace_addr +
+ 0x02, &data[62 + buffer_length], 2);
+ /* get pointer to real data */
+ sdla_peek(&card->hw, curr_trace_addr +
+ 0x04, &buf2, 2);
+ data_ptr = 0;
+ memcpy(&data_ptr, &buf2, 2);
+ /* see if we can fit the frame into the
+ user buffer */
+ memcpy(&real_len,
+ &data[62 + buffer_length], 2);
+ if ((data_ptr == 0) ||
+ ((real_len + 8) >
+ available_buffer_space)) {
+ data[61 + buffer_length] = 0x00;
+ } else {
+ /* we can take it next time */
+ if ((available_buffer_space -
+ buffer_length) <
+ (real_len + 8)) {
+ data[60] |= 0x02;
+ break;
+ }
+ /* ok, get the frame */
+ data[61 + buffer_length] = 0x01;
+ /* get the data */
+ sdla_peek(&card->hw, data_ptr,
+ &data[66 + buffer_length],
+ real_len);
+ /* zero the opp flag to
+ show we got the frame */
+ buf2[0] = 0x00;
+ sdla_poke(&card->hw,
+ curr_trace_addr, &buf2, 1);
+ /* now move onto the next
+ frame */
+ curr_trace_addr += 8;
+ /* check if we passed the last
+ address */
+ if (curr_trace_addr >=
+ start_trace_addr + 0x1F0) {
+ curr_trace_addr =
+ start_trace_addr;
+ }
+ /* update buffer length and make sure its even */
+ if (data[61 + buffer_length]
+ == 0x01) {
+ buffer_length +=
+ real_len - 1;
+ }
+ /* for the header */
+ buffer_length += 8;
+ if (buffer_length & 0x0001)
+ buffer_length += 1;
+ }
+ }
+ /* ok now set the total number of frames passed
+ in the high 5 bits */
+ data[60] = (frames << 2) | data[60];
+ /* set the data length */
+ mbox->cmd.length = buffer_length;
+ memcpy(&data[46], &buffer_length, 2);
+ /* set return code */
+ data[48] = 0;
+ } else {
+ /* set return code */
+ data[48] = 1;
+ mbox->cmd.length = 0;
+ }
+ break;
+ /* PPIPE_GET_IBA_DATA */
+ case 0x23:
+ mbox->cmd.length = 0x09;
+ if (card->hw.fwid == SFID_PPP502) {
+ sdla_peek(&card->hw, 0xA003, &data[60],
+ mbox->cmd.length);
+ } else {
+ sdla_peek(&card->hw, 0xF003, &data[60],
+ mbox->cmd.length);
+ }
+ /* set the length of the data */
+ data[46] = 0x09;
+ /* set return code */
+ data[48] = 0x00;
+ break;
+ /* PPIPE_KILL_BOARD */
+ case 0x24:
+ break;
+ /* PPIPE_FT1_READ_STATUS */
+ case 0x25:
+ sdla_peek(&card->hw, 0xF020, &data[60], 2);
+ data[46] = 2;
+ data[47] = 0;
+ data[48] = 0;
+ mbox->cmd.length = 2;
+ break;
+ case 0x29:
+ init_ppp_priv_struct(ppp_priv_area);
+ init_global_statistics(card);
+ mbox->cmd.length = 0;
+ break;
+ case 0x30:
+ do_gettimeofday(&tv);
+ ppp_priv_area->router_up_time = tv.tv_sec -
+ ppp_priv_area->router_start_time;
+ *(unsigned long *) &data[60] =
+ ppp_priv_area->router_up_time;
+ mbox->cmd.length = 4;
+ break;
+ /* FT1 MONITOR STATUS */
+ case 0x80:
+ /* Enable FT1 MONITOR STATUS */
+ if (data[60] == 1) {
+ if (rCount++ != 0) {
+ data[48] = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+ /* Disable FT1 MONITOR STATUS */
+ if (data[60] == 0) {
+ if (--rCount != 0) {
+ data[48] = 0;
+ mbox->cmd.length = 1;
+ break;
+ }
+ }
+ default:
+ /* it's a board command */
+ memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
+ if (mbox->cmd.length) {
+ memcpy(&mbox->data, &sendpacket[60],
+ mbox->cmd.length);
+ }
+ /* run the command on the board */
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+ if (err != CMD_OK) {
+ ppp_error(card, err, mbox);
+ ++ppp_priv_area->
+ UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+ break;
+ }
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+ /* copy the result back to our buffer */
+ memcpy(data, sendpacket, skb->len);
+ memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
+ if (mbox->cmd.length) {
+ memcpy(&data[60], &mbox->data, mbox->cmd.length);
+ }
+ } /* end of switch */
+ } /* end of else */
+ /* Fill UDP TTL */
+ data[8] = card->wandev.ttl;
+ len = reply_udp(data, mbox->cmd.length);
+ if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
+ ppp_send(card, data, len, skb->protocol);
+ } else {
+ /* Pass it up the stack
+ Allocate socket buffer */
+ if ((new_skb = dev_alloc_skb(len)) != NULL) {
+ /* copy data into new_skb */
+ buf = skb_put(new_skb, len);
+ memcpy(buf, data, len);
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
+ /* Decapsulate packet and pass it up the protocol
+ stack */
+ new_skb->protocol = htons(ETH_P_IP);
+ new_skb->dev = dev;
+ new_skb->mac.raw = new_skb->data;
+ netif_rx(new_skb);
+ } else {
+ ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
+ printk(KERN_INFO "no socket buffers available!\n");
+ }
+ }
+ kfree(data);
+ return 0;
+}
+
/*=============================================================================
* Initial the ppp_private_area structure.
*/
-static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area )
+static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area)
{
- ppp_priv_area->if_send_entry = 0;
- ppp_priv_area->if_send_skb_null = 0;
- ppp_priv_area->if_send_broadcast = 0;
- ppp_priv_area->if_send_multicast = 0;
- ppp_priv_area->if_send_critical_ISR = 0;
- ppp_priv_area->if_send_critical_non_ISR = 0;
- ppp_priv_area->if_send_busy = 0;
- ppp_priv_area->if_send_busy_timeout = 0;
- ppp_priv_area->if_send_DRVSTATS_request = 0;
- ppp_priv_area->if_send_PTPIPE_request = 0;
- ppp_priv_area->if_send_wan_disconnected = 0;
- ppp_priv_area->if_send_adptr_bfrs_full = 0;
- ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
-
- ppp_priv_area->rx_intr_no_socket = 0;
- ppp_priv_area->rx_intr_DRVSTATS_request = 0;
- ppp_priv_area->rx_intr_PTPIPE_request = 0;
- ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
- ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
-
- ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
- ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
-
- ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
- ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
+ ppp_priv_area->if_send_entry = 0;
+ ppp_priv_area->if_send_skb_null = 0;
+ ppp_priv_area->if_send_broadcast = 0;
+ ppp_priv_area->if_send_multicast = 0;
+ ppp_priv_area->if_send_critical_ISR = 0;
+ ppp_priv_area->if_send_critical_non_ISR = 0;
+ ppp_priv_area->if_send_busy = 0;
+ ppp_priv_area->if_send_busy_timeout = 0;
+ ppp_priv_area->if_send_DRVSTATS_request = 0;
+ ppp_priv_area->if_send_PTPIPE_request = 0;
+ ppp_priv_area->if_send_wan_disconnected = 0;
+ ppp_priv_area->if_send_adptr_bfrs_full = 0;
+ ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
+ ppp_priv_area->rx_intr_no_socket = 0;
+ ppp_priv_area->rx_intr_DRVSTATS_request = 0;
+ ppp_priv_area->rx_intr_PTPIPE_request = 0;
+ ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
+ ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
}
/*============================================================================
* Initialize Global Statistics
*/
-static void init_global_statistics( sdla_t* card )
+
+static void init_global_statistics(sdla_t * card)
{
- card->statistics.isr_entry = 0;
- card->statistics.isr_already_critical = 0;
- card->statistics.isr_tx = 0;
- card->statistics.isr_rx = 0;
- card->statistics.isr_intr_test = 0;
- card->statistics.isr_spurious = 0;
- card->statistics.isr_enable_tx_int = 0;
+ card->statistics.isr_entry = 0;
+ card->statistics.isr_already_critical = 0;
+ card->statistics.isr_tx = 0;
+ card->statistics.isr_rx = 0;
+ card->statistics.isr_intr_test = 0;
+ card->statistics.isr_spurious = 0;
+ card->statistics.isr_enable_tx_int = 0;
card->statistics.rx_intr_corrupt_rx_bfr = 0;
- card->statistics.rx_intr_dev_not_started= 0;
- card->statistics.tx_intr_dev_not_started= 0;
- card->statistics.poll_entry = 0;
- card->statistics.poll_already_critical = 0;
- card->statistics.poll_processed = 0;
- card->statistics.poll_tbusy_bad_status = 0;
-
+ card->statistics.rx_intr_dev_not_started = 0;
+ card->statistics.tx_intr_dev_not_started = 0;
+ card->statistics.poll_entry = 0;
+ card->statistics.poll_already_critical = 0;
+ card->statistics.poll_processed = 0;
+ card->statistics.poll_tbusy_bad_status = 0;
}
/*============================================================================
* Initialize Receive and Transmit Buffers.
*/
-static void init_ppp_tx_rx_buff( sdla_t* card )
-{
-
- if (card->hw.fwid == SFID_PPP502)
- {
- ppp502_buf_info_t* info =
- (void*)(card->hw.dpmbase + PPP502_BUF_OFFS);
-
- card->u.p.txbuf_base =
- (void*)(card->hw.dpmbase + info->txb_offs);
-
- card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
- (info->txb_num - 1);
-
- card->u.p.rxbuf_base =
- (void*)(card->hw.dpmbase + info->rxb_offs);
-
- card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
- (info->rxb_num - 1);
- }
- else
- {
- ppp508_buf_info_t* info =
- (void*)(card->hw.dpmbase + PPP508_BUF_OFFS);
-
- card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
- (info->txb_ptr - PPP508_MB_VECT));
-
- card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
- (info->txb_num - 1);
-
- card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
- (info->rxb_ptr - PPP508_MB_VECT));
-
- card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
- (info->rxb_num - 1);
+static void init_ppp_tx_rx_buff(sdla_t * card)
+{
+ if (card->hw.fwid == SFID_PPP502) {
+ ppp502_buf_info_t *info =
+ (void *) (card->hw.dpmbase + PPP502_BUF_OFFS);
+ card->u.p.txbuf_base =
+ (void *) (card->hw.dpmbase + info->txb_offs);
+ card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
+ (info->txb_num - 1);
+ card->u.p.rxbuf_base =
+ (void *) (card->hw.dpmbase + info->rxb_offs);
+ card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
+ (info->rxb_num - 1);
+ } else {
+ ppp508_buf_info_t *info =
+ (void *) (card->hw.dpmbase + PPP508_BUF_OFFS);
+ card->u.p.txbuf_base = (void *) (card->hw.dpmbase +
+ (info->txb_ptr - PPP508_MB_VECT));
+ card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
+ (info->txb_num - 1);
+ card->u.p.rxbuf_base = (void *) (card->hw.dpmbase +
+ (info->rxb_ptr - PPP508_MB_VECT));
+ card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
+ (info->rxb_num - 1);
card->u.p.rx_base = info->rxb_base;
- card->u.p.rx_top = info->rxb_end;
+ card->u.p.rx_top = info->rxb_end;
}
-
card->u.p.txbuf = card->u.p.txbuf_base;
card->rxmb = card->u.p.rxbuf_base;
-
}
/*=============================================================================
* Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
* _TEST_COUNTER times.
*/
-static int intr_test( sdla_t* card )
-{
- ppp_mbox_t* mb = card->mbox;
- int err,i;
+static int intr_test(sdla_t * card)
+{
+ ppp_mbox_t *mb = card->mbox;
+ int err, i;
/* The critical flag is unset because during intialization (if_open)
* we want the interrupts to be enabled so that when the wpp_isr is
* called it does not exit due to critical flag set.
- */
-
+ */
card->wandev.critical = 0;
-
- err = ppp_set_intr_mode( card, 0x08 );
-
- if ( err == CMD_OK )
- {
- for (i=0; i<MAX_INTR_TEST_COUNTER; i++)
- {
+ err = ppp_set_intr_mode(card, 0x08);
+ if (err == CMD_OK) {
+ for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) {
/* Run command READ_CODE_VERSION */
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.length = 0;
+ mb->cmd.length = 0;
mb->cmd.command = 0x10;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
+ if (err != CMD_OK)
ppp_error(card, err, mb);
}
- }
- else return err;
-
- err = ppp_set_intr_mode( card, 0 );
- if (err != CMD_OK)
+ } else
+ return err;
+ err = ppp_set_intr_mode(card, 0);
+ if (err != CMD_OK)
return err;
-
card->wandev.critical = 1;
return 0;
}
+/*==============================================================================
+ * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ?
+ */
+
+static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+{
+ unsigned char *sendpacket;
+ unsigned char buf2[5];
+ sendpacket = skb->data;
+ memcpy(&buf2, &card->wandev.udp_port, 2);
+ if (sendpacket[0] == 0x45 && /* IP packet */
+ sendpacket[9] == 0x11 && /* UDP packet */
+ sendpacket[22] == buf2[1] && /* UDP Port */
+ sendpacket[23] == buf2[0] &&
+ sendpacket[36] == 0x01) {
+ if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */
+ sendpacket[29] == 0x54 &&
+ sendpacket[30] == 0x50 &&
+ sendpacket[31] == 0x49 &&
+ sendpacket[32] == 0x50 &&
+ sendpacket[33] == 0x45 &&
+ sendpacket[34] == 0x41 &&
+ sendpacket[35] == 0x42) {
+ return UDP_PTPIPE_TYPE;
+ } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */
+ sendpacket[29] == 0x52 &&
+ sendpacket[30] == 0x56 &&
+ sendpacket[31] == 0x53 &&
+ sendpacket[32] == 0x54 &&
+ sendpacket[33] == 0x41 &&
+ sendpacket[34] == 0x54 &&
+ sendpacket[35] == 0x53) {
+ return UDP_DRVSTATS_TYPE;
+ } else
+ return UDP_INVALID_TYPE;
+ } else
+ return UDP_INVALID_TYPE;
+}
+
/****** End *****************************************************************/
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
index 15844a3ab..6a649a2d2 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/sdla_x25.c
@@ -10,6 +10,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* Mar 15, 1998 Alan Cox o 2.1.x porting
* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
* when they are disabled.
* Nov 17, 1997 Farhan Thawar o Added IPX support
@@ -41,6 +42,7 @@
#error This code MUST be compiled as a kernel module!
#endif
+#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
@@ -48,9 +50,8 @@
#include <linux/malloc.h> /* kmalloc(), kfree() */
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/init.h> /* __initfunc et al. */
#include <asm/byteorder.h> /* htons(), etc. */
-#include <asm/uaccess.h> /* copy_from_user, etc */
+#include <asm/uaccess.h>
#define _GNUC_
#include <linux/sdla_x25.h> /* X.25 firmware API definitions */
@@ -132,7 +133,7 @@ static int if_header (struct sk_buff* skb, struct device* dev,
unsigned short type, void* daddr, void* saddr, unsigned len);
static int if_rebuild_hdr (struct sk_buff* skb);
static int if_send (struct sk_buff* skb, struct device* dev);
-static struct enet_statistics* if_stats (struct device* dev);
+static struct net_device_stats * if_stats (struct device* dev);
/* Interrupt handlers */
static void wpx_isr (sdla_t* card);
@@ -211,7 +212,7 @@ extern void enable_irq(unsigned int);
* Return: 0 o.k.
* < 0 failure.
*/
-__initfunc(int wpx_init (sdla_t* card, wandev_conf_t* conf))
+int wpx_init (sdla_t* card, wandev_conf_t* conf)
{
union
{
@@ -372,14 +373,11 @@ static int update (wan_device_t* wandev)
/* sanity checks */
if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT
- ;
+ return -EFAULT;
if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV
- ;
+ return -ENODEV;
if (test_and_set_bit(0, (void*)&wandev->critical))
- return -EAGAIN
- ;
+ return -EAGAIN;
card = wandev->private;
x25_get_err_stats(card);
@@ -476,7 +474,6 @@ static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
/*============================================================================
* Delete logical channel.
*/
-
static int del_if (wan_device_t* wandev, struct device* dev)
{
if (dev->priv)
@@ -502,18 +499,21 @@ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
return -EFAULT;
-
+
/* execute command */
+
do
{
memcpy(&mbox->cmd, &cmd, sizeof(cmd));
if (cmd.length)
+ {
if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
- return -EFAULT;
+ return-EFAULT;
+ }
if (sdla_exec(mbox))
- err = mbox->cmd.result;
- else
- return -EIO;
+ err = mbox->cmd.result
+ ;
+ else return -EIO;
}
while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn));
@@ -521,9 +521,8 @@ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd)))
return -EFAULT;
len = mbox->cmd.length;
- if (len && u_data)
- if(copy_to_user(u_data, (void*)&mbox->data, len))
- return -EFAULT;
+ if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
+ return -EFAULT;
return 0;
}
@@ -541,7 +540,6 @@ static int if_init (struct device* dev)
x25_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
wan_device_t* wandev = &card->wandev;
- int i;
/* Initialize device driver entry points */
dev->open = &if_open;
@@ -552,14 +550,12 @@ static int if_init (struct device* dev)
dev->get_stats = &if_stats;
/* Initialize media-specific parameters */
- dev->family = AF_INET; /* address family */
dev->type = 30; /* ARP h/w type */
dev->mtu = X25_CHAN_MTU;
dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */
dev->addr_len = 2; /* hardware address length */
if (!chan->svc)
- *(unsigned short*)dev->dev_addr = htons(chan->lcn)
- ;
+ *(unsigned short*)dev->dev_addr = htons(chan->lcn);
/* Initialize hardware parameters (just for reference) */
dev->irq = wandev->irq;
@@ -572,8 +568,8 @@ static int if_init (struct device* dev)
dev->tx_queue_len = 10;
/* Initialize socket buffers */
- dev_init_buffers(dev);
+ dev_init_buffers(dev);
set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -591,11 +587,10 @@ static int if_open (struct device* dev)
sdla_t* card = chan->card;
if (dev->start)
- return -EBUSY /* only one open is allowed */
- ;
+ return -EBUSY; /* only one open is allowed */
+
if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
- ;
dev->interrupt = 0;
dev->tbusy = 0;
@@ -604,8 +599,7 @@ static int if_open (struct device* dev)
/* If this is the first open, initiate physical connection */
if (card->open_cnt == 1)
- connect(card)
- ;
+ connect(card);
card->wandev.critical = 0;
return 0;
}
@@ -622,17 +616,17 @@ static int if_close (struct device* dev)
if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
- ;
+
dev->start = 0;
if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING))
- chan_disc(dev)
- ;
+ chan_disc(dev);
+
wanpipe_close(card);
/* If this is the last close, disconnect physical link */
if (!card->open_cnt)
- disconnect(card)
- ;
+ disconnect(card);
+
card->wandev.critical = 0;
return 0;
}
@@ -672,14 +666,15 @@ static int if_header (struct sk_buff* skb, struct device* dev,
* Return: 1 physical address resolved.
* 0 physical address not resolved
*/
+
static int if_rebuild_hdr (struct sk_buff* skb)
{
- x25_channel_t* chan = skb->dev->priv;
+ struct device *dev=skb->dev;
+ x25_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, skb->dev->name)
- ;
+ card->devname, dev->name);
return 1;
}
@@ -700,6 +695,7 @@ static int if_rebuild_hdr (struct sk_buff* skb)
* 2. Setting tbusy flag will inhibit further transmit requests from the
* protocol stack and can be used for flow control with protocol layer.
*/
+
static int if_send (struct sk_buff* skb, struct device* dev)
{
x25_channel_t* chan = dev->priv;
@@ -708,20 +704,6 @@ static int if_send (struct sk_buff* skb, struct device* dev)
TX25Status* status = card->flags;
unsigned long host_cpu_flags;
- if (skb == NULL)
- {
- /* If we get here, some higher layer thinks we've missed a
- * tx-done interrupt.
- */
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: interface %s got kicked!\n",
- card->devname, dev->name)
- ;
-#endif
- dev_tint(dev);
- return 0;
- }
-
if (dev->tbusy)
{
++chan->ifstats.rx_dropped;
@@ -742,7 +724,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
disable_irq(card->hw.irq);
++card->irq_dis_if_send_count;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
printk(KERN_INFO "Hit critical in if_send()!\n");
if (card->wandev.critical == CRITICAL_IN_ISR)
@@ -773,85 +755,81 @@ static int if_send (struct sk_buff* skb, struct device* dev)
/* Below is only until we have per-channel IPX going.... */
if(!(chan->svc))
- {
chan->protocol = skb->protocol;
- }
if (card->wandev.state != WAN_CONNECTED)
- {
- ++chan->ifstats.tx_dropped
- ;
- }
+ ++chan->ifstats.tx_dropped;
+
/* Below is only until we have per-channel IPX going.... */
else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol)))
{
printk(KERN_INFO
"%s: unsupported Ethertype 0x%04X on interface %s!\n",
- card->devname, skb->protocol, dev->name)
- ;
+ card->devname, skb->protocol, dev->name);
++chan->ifstats.tx_errors;
}
else switch (chan->state)
{
- case WAN_DISCONNECTED:
- /* Try to establish connection. If succeded, then start
- * transmission, else drop a packet.
- */
- if (chan_connect(dev) != 0)
- {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- /* fall through */
-
- case WAN_CONNECTED:
- if( skb->protocol == ETH_P_IPX ) {
- if(card->wandev.enable_IPX) {
- switch_net_numbers( skb->data,
- card->wandev.network_number, 0);
- } else {
- ++card->wandev.stats.tx_dropped;
+ case WAN_DISCONNECTED:
+ /* Try to establish connection. If succeded, then start
+ * transmission, else drop a packet.
+ */
+ if (chan_connect(dev) != 0)
+ {
++chan->ifstats.tx_dropped;
- goto tx_done;
+ ++card->wandev.stats.tx_dropped;
+ break;
}
- }
- dev->trans_start = jiffies;
- if(chan_send(dev, skb))
- {
- dev->tbusy = 1;
- status->imask |= 0x2;
- }
- break;
+ /* fall through */
- default:
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- }
+ case WAN_CONNECTED:
+ if( skb->protocol == ETH_P_IPX )
+ {
+ if(card->wandev.enable_IPX)
+ {
+ switch_net_numbers( skb->data,
+ card->wandev.network_number, 0);
+ }
+ else
+ {
+ ++card->wandev.stats.tx_dropped;
+ ++chan->ifstats.tx_dropped;
+ goto tx_done;
+ }
+ }
+ dev->trans_start = jiffies;
+ if(chan_send(dev, skb))
+ {
+ dev->tbusy = 1;
+ status->imask |= 0x2;
+ }
+ break;
+ default:
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
+ }
tx_done:
if (!dev->tbusy)
- {
dev_kfree_skb(skb);
- }
+
card->wandev.critical = 0;
save_flags(host_cpu_flags);
cli();
if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
-
return dev->tbusy;
}
/*============================================================================
* Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
+ * Return a pointer to struct net_device_stats
*/
-static struct enet_statistics* if_stats (struct device* dev)
+
+static struct net_device_stats* if_stats (struct device* dev)
{
x25_channel_t* chan = dev->priv;
-
return &chan->ifstats;
}
@@ -860,6 +838,7 @@ static struct enet_statistics* if_stats (struct device* dev)
/*============================================================================
* X.25 Interrupt Service Routine.
*/
+
static void wpx_isr (sdla_t* card)
{
TX25Status* status = card->flags;
@@ -869,7 +848,8 @@ static void wpx_isr (sdla_t* card)
card->in_isr = 1;
card->buff_int_mode_unbusy = 0;
- if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ {
printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags);
card->in_isr = 0;
@@ -884,28 +864,27 @@ static void wpx_isr (sdla_t* card)
switch (status->iflags)
{
- case 0x01: /* receive interrupt */
- rx_intr(card);
- break;
+ case 0x01: /* receive interrupt */
+ rx_intr(card);
+ break;
- case 0x02: /* transmit interrupt */
- tx_intr(card);
- card->buff_int_mode_unbusy = 1;
- status->imask &= ~0x2;
- break;
+ case 0x02: /* transmit interrupt */
+ tx_intr(card);
+ card->buff_int_mode_unbusy = 1;
+ status->imask &= ~0x2;
+ break;
- case 0x04: /* modem status interrupt */
- status_intr(card);
- break;
+ case 0x04: /* modem status interrupt */
+ status_intr(card);
+ break;
- case 0x10: /* network event interrupt */
- event_intr(card);
- break;
+ case 0x10: /* network event interrupt */
+ event_intr(card);
+ break;
- default: /* unwanted interrupt */
- spur_intr(card);
+ default: /* unwanted interrupt */
+ spur_intr(card);
}
-
card->wandev.critical = CRITICAL_INTR_HANDLED;
if( card->wandev.enable_tx_int)
{
@@ -925,7 +904,8 @@ static void wpx_isr (sdla_t* card)
{
if(((x25_channel_t*)dev->priv)->devtint)
{
- dev_tint(dev);
+ mark_bh(NET_BH);
+ return;
}
}
}
@@ -947,6 +927,7 @@ static void wpx_isr (sdla_t* card)
* 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
* socket buffers available) the whole packet sequence must be discarded.
*/
+
static void rx_intr (sdla_t* card)
{
TX25Mbox* rxmb = card->rxmb;
@@ -963,8 +944,7 @@ static void rx_intr (sdla_t* card)
{
/* Invalid channel, discard packet */
printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
- card->devname, lcn)
- ;
+ card->devname, lcn);
return;
}
@@ -986,8 +966,7 @@ static void rx_intr (sdla_t* card)
if (skb == NULL)
{
printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname)
- ;
+ card->devname);
chan->drop_sequence = 1; /* set flag */
++chan->ifstats.rx_dropped;
return;
@@ -1005,8 +984,7 @@ static void rx_intr (sdla_t* card)
if (qdm & 0x01) chan->drop_sequence = 1;
printk(KERN_INFO "%s: unexpectedly long packet sequence "
- "on interface %s!\n", card->devname, dev->name)
- ;
+ "on interface %s!\n", card->devname, dev->name);
++chan->ifstats.rx_length_errors;
return;
}
@@ -1014,7 +992,9 @@ static void rx_intr (sdla_t* card)
/* Append packet to the socket buffer */
bufptr = skb_put(skb, len);
memcpy(bufptr, rxmb->data, len);
- if (qdm & 0x01) return; /* more data is comming */
+
+ if (qdm & 0x01)
+ return; /* more data is comming */
dev->last_rx = jiffies; /* timestamp */
chan->rx_skb = NULL; /* dequeue packet */
@@ -1043,7 +1023,7 @@ static void rx_intr (sdla_t* card)
}
else
{
- /* increment IPX packet dropped statistic */
+ /* FIXME: increment IPX packet dropped statistic */
}
}
else
@@ -1059,11 +1039,11 @@ static void rx_intr (sdla_t* card)
* o Release socket buffer
* o Clear 'tbusy' flag
*/
+
static void tx_intr (sdla_t* card)
{
struct device *dev;
-
/* unbusy all devices and then dev_tint(); */
for(dev = card->wandev.dev; dev; dev = dev->slave)
{
@@ -1102,13 +1082,14 @@ static void spur_intr (sdla_t* card)
/*============================================================================
* Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thead' to allow for
+ * This routine is repeatedly called by the WANPIPE 'thread' to allow for
* time-dependent housekeeping work.
*
* Notes:
* 1. This routine may be called on interrupt context with all interrupts
* enabled. Beware!
*/
+
static void wpx_poll (sdla_t* card)
{
unsigned long host_cpu_flags;
@@ -1116,42 +1097,37 @@ static void wpx_poll (sdla_t* card)
disable_irq(card->hw.irq);
++card->irq_dis_poll_count;
- if (set_bit(0, (void*)&card->wandev.critical)) {
-
- printk(KERN_INFO "%s: critical in polling!\n",card->devname);
-
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ {
+ printk(KERN_INFO "%s: critical in polling!\n",card->devname);
save_flags(host_cpu_flags);
cli();
if ((!card->irq_dis_if_send_count) &&
(!(--card->irq_dis_poll_count)))
enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
-
return;
}
switch(card->wandev.state)
{
- case WAN_CONNECTED:
- poll_active(card);
- break;
+ case WAN_CONNECTED:
+ poll_active(card);
+ break;
- case WAN_CONNECTING:
- poll_connecting(card);
- break;
+ case WAN_CONNECTING:
+ poll_connecting(card);
+ break;
- case WAN_DISCONNECTED:
- poll_disconnected(card);
+ case WAN_DISCONNECTED:
+ poll_disconnected(card);
}
-
card->wandev.critical = 0;
-
save_flags(host_cpu_flags);
cli();
if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
enable_irq(card->hw.irq);
restore_flags(host_cpu_flags);
-
}
/*============================================================================
@@ -1169,8 +1145,7 @@ static void poll_connecting (sdla_t* card)
status->imask &= ~0x2; /* mask Tx interupts */
}
else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
- disconnect(card)
- ;
+ disconnect(card);
}
/*============================================================================
@@ -1181,8 +1156,7 @@ static void poll_connecting (sdla_t* card)
static void poll_disconnected (sdla_t* card)
{
if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
- connect(card)
- ;
+ connect(card);
}
/*============================================================================
@@ -1220,7 +1194,7 @@ static void poll_active (sdla_t* card)
{
if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout )
{
- //Close svc
+ /* Close svc */
printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn);
chan->i_timeout_sofar = jiffies;
chan_disc(dev);
@@ -1255,13 +1229,11 @@ static int x25_get_version (sdla_t* card, char* str)
mbox->cmd.command = X25_READ_CODE_VERSION;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
} while (err && retry-- &&
- x25_error(card, err, X25_READ_CODE_VERSION, 0))
- ;
+ x25_error(card, err, X25_READ_CODE_VERSION, 0));
if (!err && str)
{
int len = mbox->cmd.length;
-
memcpy(str, mbox->data, len);
str[len] = '\0';
}
@@ -1271,6 +1243,7 @@ static int x25_get_version (sdla_t* card, char* str)
/*============================================================================
* Configure adapter.
*/
+
static int x25_configure (sdla_t* card, TX25Config* conf)
{
TX25Mbox* mbox = card->mbox;
@@ -1284,9 +1257,7 @@ static int x25_configure (sdla_t* card, TX25Config* conf)
mbox->cmd.length = sizeof(TX25Config);
mbox->cmd.command = X25_SET_CONFIGURATION;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_SET_CONFIGURATION, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
return err;
}
@@ -1304,9 +1275,8 @@ static int x25_get_err_stats (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
+
if (!err)
{
THdlcCommErr* stats = (void*)mbox->data;
@@ -1333,9 +1303,8 @@ static int x25_get_stats (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_READ_STATISTICS;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_READ_STATISTICS, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0));
+
if (!err)
{
TX25Stats* stats = (void*)mbox->data;
@@ -1360,9 +1329,8 @@ static int x25_close_hdlc (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_HDLC_LINK_CLOSE;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_HDLC_LINK_CLOSE, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
+
return err;
}
@@ -1380,9 +1348,8 @@ static int x25_open_hdlc (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_HDLC_LINK_OPEN;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_HDLC_LINK_OPEN, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
+
return err;
}
@@ -1400,9 +1367,8 @@ static int x25_setup_hdlc (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_HDLC_LINK_SETUP;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_HDLC_LINK_SETUP, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0));
+
return err;
}
@@ -1424,9 +1390,8 @@ static int x25_set_dtr (sdla_t* card, int dtr)
mbox->cmd.length = 3;
mbox->cmd.command = X25_SET_GLOBAL_VARS;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_SET_GLOBAL_VARS, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
+
return err;
}
@@ -1451,9 +1416,7 @@ static int x25_set_intr_mode (sdla_t* card, int mode)
else mbox->cmd.length = 1;
mbox->cmd.command = X25_SET_INTERRUPT_MODE;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_SET_INTERRUPT_MODE, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ;
return err;
}
@@ -1473,9 +1436,7 @@ static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
mbox->cmd.lcn = lcn;
mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn));
if (!err)
{
@@ -1483,19 +1444,23 @@ static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
/* calculate an offset into the array of status bytes */
if (card->u.x.hi_svc <= 255)
- chan->ch_idx = lcn - 1
- ;
+ chan->ch_idx = lcn - 1;
else
{
int offset;
switch (mbox->data[0] && 0x1F)
{
- case 0x01: offset = status->pvc_map; break;
- case 0x03: offset = status->icc_map; break;
- case 0x07: offset = status->twc_map; break;
- case 0x0B: offset = status->ogc_map; break;
- default: offset = 0;
+ case 0x01:
+ offset = status->pvc_map; break;
+ case 0x03:
+ offset = status->icc_map; break;
+ case 0x07:
+ offset = status->twc_map; break;
+ case 0x0B:
+ offset = status->ogc_map; break;
+ default:
+ offset = 0;
}
chan->ch_idx = lcn - 1 - offset;
}
@@ -1503,17 +1468,30 @@ static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
/* get actual transmit packet size on this channel */
switch(mbox->data[1] & 0x38)
{
- case 0x00: chan->tx_pkt_size = 16; break;
- case 0x08: chan->tx_pkt_size = 32; break;
- case 0x10: chan->tx_pkt_size = 64; break;
- case 0x18: chan->tx_pkt_size = 128; break;
- case 0x20: chan->tx_pkt_size = 256; break;
- case 0x28: chan->tx_pkt_size = 512; break;
- case 0x30: chan->tx_pkt_size = 1024; break;
+ case 0x00:
+ chan->tx_pkt_size = 16;
+ break;
+ case 0x08:
+ chan->tx_pkt_size = 32;
+ break;
+ case 0x10:
+ chan->tx_pkt_size = 64;
+ break;
+ case 0x18:
+ chan->tx_pkt_size = 128;
+ break;
+ case 0x20:
+ chan->tx_pkt_size = 256;
+ break;
+ case 0x28:
+ chan->tx_pkt_size = 512;
+ break;
+ case 0x30:
+ chan->tx_pkt_size = 1024;
+ break;
}
printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
- card->devname, lcn, chan->tx_pkt_size)
- ;
+ card->devname, lcn, chan->tx_pkt_size);
}
return err;
}
@@ -1521,6 +1499,7 @@ static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
/*============================================================================
* Place X.25 call.
*/
+
static int x25_place_call (sdla_t* card, x25_channel_t* chan)
{
TX25Mbox* mbox = card->mbox;
@@ -1536,9 +1515,8 @@ static int x25_place_call (sdla_t* card, x25_channel_t* chan)
mbox->cmd.length = strlen(str);
mbox->cmd.command = X25_PLACE_CALL;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_PLACE_CALL, 0))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0));
+
if (!err)
{
chan->lcn = mbox->cmd.lcn;
@@ -1550,6 +1528,7 @@ static int x25_place_call (sdla_t* card, x25_channel_t* chan)
/*============================================================================
* Accept X.25 call.
*/
+
static int x25_accept_call (sdla_t* card, int lcn, int qdm)
{
TX25Mbox* mbox = card->mbox;
@@ -1563,9 +1542,8 @@ static int x25_accept_call (sdla_t* card, int lcn, int qdm)
mbox->cmd.qdm = qdm;
mbox->cmd.command = X25_ACCEPT_CALL;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_ACCEPT_CALL, lcn))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn));
+
return err;
}
@@ -1586,9 +1564,8 @@ static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
mbox->cmd.diagn = diagn;
mbox->cmd.command = X25_CLEAR_CALL;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_CLEAR_CALL, lcn))
- ;
+ } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn));
+
return err;
}
@@ -1600,7 +1577,7 @@ static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
TX25Mbox* mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
-
+
do
{
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
@@ -1628,7 +1605,8 @@ static int x25_fetch_events (sdla_t* card)
memset(&mbox->cmd, 0, sizeof(TX25Cmd));
mbox->cmd.command = X25_IS_DATA_AVAILABLE;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
+ if (err)
+ x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
}
return err;
}
@@ -1656,99 +1634,90 @@ static int x25_error (sdla_t* card, int err, int cmd, int lcn)
if (mb == NULL)
{
printk(KERN_ERR "%s: x25_error() out of memory!\n",
- card->devname)
- ;
+ card->devname);
return 0;
}
memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
switch (err)
{
- case 0x40: /* X.25 asynchronous packet was received */
- mb->data[dlen] = '\0';
- switch (mb->cmd.pktType & 0x7F)
- {
- case 0x30: /* incomming call */
- retry = incomming_call(card, cmd, lcn, mb);
+ case 0x40: /* X.25 asynchronous packet was received */
+ mb->data[dlen] = '\0';
+ switch (mb->cmd.pktType & 0x7F)
+ {
+ case 0x30: /* incomming call */
+ retry = incomming_call(card, cmd, lcn, mb);
+ break;
+
+ case 0x31: /* connected */
+ retry = call_accepted(card, cmd, lcn, mb);
+ break;
+
+ case 0x02: /* call clear request */
+ retry = call_cleared(card, cmd, lcn, mb);
+ break;
+
+ case 0x04: /* reset request */
+ printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
+ "Cause:0x%02X Diagn:0x%02X\n",
+ card->devname, mb->cmd.lcn, mb->cmd.cause,
+ mb->cmd.diagn);
+ break;
+
+ case 0x08: /* restart request */
+ retry = restart_event(card, cmd, lcn, mb);
+ break;
+
+ default:
+ printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
+ "Cause:0x%02X Diagn:0x%02X\n",
+ card->devname, mb->cmd.pktType,
+ mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
+ }
break;
- case 0x31: /* connected */
- retry = call_accepted(card, cmd, lcn, mb);
+ case 0x41: /* X.25 protocol violation indication */
+ printk(KERN_INFO
+ "%s: X.25 protocol violation on LCN %d! "
+ "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
+ card->devname, mb->cmd.lcn,
+ mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
break;
- case 0x02: /* call clear request */
- retry = call_cleared(card, cmd, lcn, mb);
+ case 0x42: /* X.25 timeout */
+ retry = timeout_event(card, cmd, lcn, mb);
break;
- case 0x04: /* reset request */
- printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
- "Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.lcn, mb->cmd.cause,
- mb->cmd.diagn)
- ;
+ case 0x43: /* X.25 retry limit exceeded */
+ printk(KERN_INFO
+ "%s: exceeded X.25 retry limit on LCN %d! "
+ "Packet:0x%02X Diagn:0x%02X\n", card->devname,
+ mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn);
break;
- case 0x08: /* restart request */
- retry = restart_event(card, cmd, lcn, mb);
+ case 0x08: /* modem failure */
+ printk(KERN_INFO "%s: modem failure!\n", card->devname);
break;
- default:
- printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
- "Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.pktType,
- mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn)
- ;
- }
- break;
-
- case 0x41: /* X.25 protocol violation indication */
- printk(KERN_INFO
- "%s: X.25 protocol violation on LCN %d! "
- "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.lcn,
- mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn)
- ;
- break;
-
- case 0x42: /* X.25 timeout */
- retry = timeout_event(card, cmd, lcn, mb);
- break;
-
- case 0x43: /* X.25 retry limit exceeded */
- printk(KERN_INFO
- "%s: exceeded X.25 retry limit on LCN %d! "
- "Packet:0x%02X Diagn:0x%02X\n", card->devname,
- mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn)
- ;
- break;
-
- case 0x08: /* modem failure */
- printk(KERN_INFO "%s: modem failure!\n", card->devname);
- break;
-
- case 0x09: /* N2 retry limit */
- printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
- card->devname)
- ;
- break;
+ case 0x09: /* N2 retry limit */
+ printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
+ card->devname);
+ break;
- case 0x06: /* unnumbered frame was received while in ABM */
- printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
- card->devname, mb->data[0])
- ;
- break;
+ case 0x06: /* unnumbered frame was received while in ABM */
+ printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
+ card->devname, mb->data[0]);
+ break;
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd)
- ;
- retry = 0; /* abort command */
- break;
+ case CMD_TIMEOUT:
+ printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+ card->devname, cmd);
+ retry = 0; /* abort command */
+ break;
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, cmd, err)
- ;
- retry = 0; /* abort command */
+ default:
+ printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+ card->devname, cmd, err);
+ retry = 0; /* abort command */
}
kfree(mb);
return retry;
@@ -1772,6 +1741,7 @@ static int x25_error (sdla_t* card, int err, int cmd, int lcn)
* (i.e. call collision has occured), the incomming call shall be
* rejected and call request shall be retried.
*/
+
static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
wan_device_t* wandev = &card->wandev;
@@ -1786,8 +1756,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
printk(KERN_INFO
"%s: X.25 incomming call collision on LCN %d!\n",
- card->devname, new_lcn)
- ;
+ card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
}
@@ -1797,8 +1766,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
printk(KERN_INFO
"%s: X.25 incomming call on LCN %d with D-bit set!\n",
- card->devname, new_lcn)
- ;
+ card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
}
@@ -1815,8 +1783,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
}
parse_call_info(mb->data, info);
printk(KERN_INFO "%s: X.25 incomming call on LCN %d! Call data: %s\n",
- card->devname, new_lcn, mb->data)
- ;
+ card->devname, new_lcn, mb->data);
/* Find available channel */
for (dev = wandev->dev; dev; dev = dev->slave)
@@ -1824,22 +1791,18 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
chan = dev->priv;
if (!chan->svc || (chan->state != WAN_DISCONNECTED))
- continue
- ;
+ continue;
if (strcmp(info->src, chan->addr) == 0)
- break
- ;
- // If just an '@' is specified, accept all incomming calls
+ break;
+ /* If just an '@' is specified, accept all incomming calls */
if (strcmp(chan->addr, "") == 0)
- break
- ;
+ break;
}
if (dev == NULL)
{
printk(KERN_INFO "%s: no channels available!\n",
- card->devname)
- ;
+ card->devname);
x25_clear_call(card, new_lcn, 0, 0);
}
@@ -1848,41 +1811,39 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
printk(KERN_INFO
"%s: no user data in incomming call on LCN %d!\n",
- card->devname, new_lcn)
- ;
+ card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
}
else switch (info->user[0])
{
- case 0: /* multiplexed */
- chan->protocol = 0;
- accept = 1;
- break;
+ case 0: /* multiplexed */
+ chan->protocol = 0;
+ accept = 1;
+ break;
- case NLPID_IP: /* IP datagrams */
- chan->protocol = ETH_P_IP;
- accept = 1;
- break;
-
- case NLPID_SNAP: /* IPX datagrams */
- chan->protocol = ETH_P_IPX;
- accept = 1;
- break;
- default:
- printk(KERN_INFO
- "%s: unsupported NLPID 0x%02X in incomming call "
- "on LCN %d!\n", card->devname, info->user[0], new_lcn)
- ;
- x25_clear_call(card, new_lcn, 0, 249);
+ case NLPID_IP: /* IP datagrams */
+ chan->protocol = ETH_P_IP;
+ accept = 1;
+ break;
+
+ case NLPID_SNAP: /* IPX datagrams */
+ chan->protocol = ETH_P_IPX;
+ accept = 1;
+ break;
+ default:
+ printk(KERN_INFO
+ "%s: unsupported NLPID 0x%02X in incomming call "
+ "on LCN %d!\n", card->devname, info->user[0], new_lcn);
+ x25_clear_call(card, new_lcn, 0, 249);
}
if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK))
{
chan->lcn = new_lcn;
if (x25_get_chan_conf(card, chan) == CMD_OK)
- set_chan_state(dev, WAN_CONNECTED)
- ;
- else x25_clear_call(card, new_lcn, 0, 0);
+ set_chan_state(dev, WAN_CONNECTED);
+ else
+ x25_clear_call(card, new_lcn, 0, 0);
}
kfree(info);
return 1;
@@ -1891,6 +1852,7 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
/*============================================================================
* Handle accepted call.
*/
+
static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
unsigned new_lcn = mb->cmd.lcn;
@@ -1898,14 +1860,12 @@ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
x25_channel_t* chan;
printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n",
- card->devname, new_lcn)
- ;
+ card->devname, new_lcn);
if (dev == NULL)
{
printk(KERN_INFO
"%s: clearing orphaned connection on LCN %d!\n",
- card->devname, new_lcn)
- ;
+ card->devname, new_lcn);
x25_clear_call(card, new_lcn, 0, 0);
return 1;
}
@@ -1924,6 +1884,7 @@ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
/*============================================================================
* Handle cleared call.
*/
+
static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
unsigned new_lcn = mb->cmd.lcn;
@@ -1931,17 +1892,17 @@ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
"Diagn:0x%02X\n",
- card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn)
- ;
- if (dev == NULL) return 1;
+ card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn);
+ if (dev == NULL)
+ return 1;
set_chan_state(dev, WAN_DISCONNECTED);
-
return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
}
/*============================================================================
* Handle X.25 restart event.
*/
+
static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
{
wan_device_t* wandev = &card->wandev;
@@ -1949,13 +1910,11 @@ static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
printk(KERN_INFO
"%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.cause, mb->cmd.diagn)
- ;
+ card->devname, mb->cmd.cause, mb->cmd.diagn);
/* down all logical channels */
for (dev = wandev->dev; dev; dev = dev->slave)
- set_chan_state(dev, WAN_DISCONNECTED)
- ;
+ set_chan_state(dev, WAN_DISCONNECTED);
return (cmd == X25_WRITE) ? 0 : 1;
}
@@ -1971,13 +1930,12 @@ static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn);
printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
- card->devname, new_lcn)
- ;
- if (dev) set_chan_state(dev, WAN_DISCONNECTED);
+ card->devname, new_lcn);
+ if (dev)
+ set_chan_state(dev, WAN_DISCONNECTED);
}
else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
- card->devname, mb->cmd.pktType, new_lcn)
- ;
+ card->devname, mb->cmd.pktType, new_lcn);
return 1;
}
@@ -1994,8 +1952,7 @@ static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
static int connect (sdla_t* card)
{
if (x25_open_hdlc(card) || x25_setup_hdlc(card))
- return -EIO
- ;
+ return -EIO;
wanpipe_set_state(card, WAN_CONNECTING);
return 1;
}
@@ -2025,8 +1982,8 @@ static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
struct device* dev;
for (dev = wandev->dev; dev; dev = dev->slave)
- if (((x25_channel_t*)dev->priv)->lcn == lcn) break
- ;
+ if (((x25_channel_t*)dev->priv)->lcn == lcn)
+ break;
return dev;
}
@@ -2047,22 +2004,18 @@ static int chan_connect (struct device* dev)
if (chan->svc)
{
if (!chan->addr[0])
- return -EINVAL /* no destination address */
- ;
+ return -EINVAL; /* no destination address */
printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
- card->devname, chan->addr)
- ;
+ card->devname, chan->addr);
if (x25_place_call(card, chan) != CMD_OK)
- return -EIO
- ;
+ return -EIO;
set_chan_state(dev, WAN_CONNECTING);
return 1;
}
else
{
if (x25_get_chan_conf(card, chan) != CMD_OK)
- return -EIO
- ;
+ return -EIO;
set_chan_state(dev, WAN_CONNECTED);
}
return 0;
@@ -2076,7 +2029,8 @@ static int chan_disc (struct device* dev)
{
x25_channel_t* chan = dev->priv;
- if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0);
+ if (chan->svc)
+ x25_clear_call(chan->card, chan->lcn, 0, 0);
set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -2096,29 +2050,27 @@ static void set_chan_state (struct device* dev, int state)
{
switch (state)
{
- case WAN_CONNECTED:
- printk (KERN_INFO "%s: interface %s connected!\n",
- card->devname, dev->name)
- ;
- *(unsigned short*)dev->dev_addr = htons(chan->lcn);
- chan->i_timeout_sofar = jiffies;
- break;
+ case WAN_CONNECTED:
+ printk (KERN_INFO "%s: interface %s connected!\n",
+ card->devname, dev->name);
+ *(unsigned short*)dev->dev_addr = htons(chan->lcn);
+ chan->i_timeout_sofar = jiffies;
+ break;
- case WAN_CONNECTING:
- printk (KERN_INFO "%s: interface %s connecting...\n",
- card->devname, dev->name)
- ;
- break;
+ case WAN_CONNECTING:
+ printk (KERN_INFO "%s: interface %s connecting...\n",
+ card->devname, dev->name);
+ break;
- case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: interface %s disconnected!\n",
- card->devname, dev->name)
- ;
- if (chan->svc) {
- *(unsigned short*)dev->dev_addr = 0;
- chan->lcn = 0;
- }
- break;
+ case WAN_DISCONNECTED:
+ printk (KERN_INFO "%s: interface %s disconnected!\n",
+ card->devname, dev->name);
+ if (chan->svc)
+ {
+ *(unsigned short*)dev->dev_addr = 0;
+ chan->lcn = 0;
+ }
+ break;
}
chan->state = state;
}
@@ -2150,8 +2102,8 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
/* Check to see if channel is ready */
if (!(status->cflags[chan->ch_idx] & 0x40))
- return 1
- ;
+ return 1;
+
if (skb->len > chan->tx_pkt_size)
{
len = chan->tx_pkt_size;
@@ -2164,22 +2116,22 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
}
switch(x25_send(card, chan->lcn, qdm, len, skb->data))
{
- case 0x00: /* success */
- chan->i_timeout_sofar = jiffies;
- if (qdm)
- {
- skb_pull(skb, len);
- return 1;
- }
- ++chan->ifstats.tx_packets;
- break;
+ case 0x00: /* success */
+ chan->i_timeout_sofar = jiffies;
+ if (qdm)
+ {
+ skb_pull(skb, len);
+ return 1;
+ }
+ ++chan->ifstats.tx_packets;
+ break;
- case 0x33: /* Tx busy */
- return 1;
+ case 0x33: /* Tx busy */
+ return 1;
- default: /* failure */
- ++chan->ifstats.tx_errors;
-/* return 1; */
+ default: /* failure */
+ ++chan->ifstats.tx_errors;
+/* return 1; */
}
return 0;
}
@@ -2187,6 +2139,7 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
/*============================================================================
* Parse X.25 call request data and fill x25_call_info_t structure.
*/
+
static void parse_call_info (unsigned char* str, x25_call_info_t* info)
{
memset(info, 0, sizeof(x25_call_info_t));
@@ -2197,50 +2150,53 @@ static void parse_call_info (unsigned char* str, x25_call_info_t* info)
if (*str == '-') switch (str[1])
{
- case 'd': /* destination address */
- for (i = 0; i < 16; ++i)
- {
- ch = str[2+i];
- if (!is_digit(ch)) break;
- info->dest[i] = ch;
- }
- break;
-
- case 's': /* source address */
- for (i = 0; i < 16; ++i)
- {
- ch = str[2+i];
- if (!is_digit(ch)) break;
- info->src[i] = ch;
- }
- break;
+ case 'd': /* destination address */
+ for (i = 0; i < 16; ++i)
+ {
+ ch = str[2+i];
+ if (!is_digit(ch))
+ break;
+ info->dest[i] = ch;
+ }
+ break;
+
+ case 's': /* source address */
+ for (i = 0; i < 16; ++i)
+ {
+ ch = str[2+i];
+ if (!is_digit(ch))
+ break;
+ info->src[i] = ch;
+ }
+ break;
- case 'u': /* user data */
- for (i = 0; i < 127; ++i)
- {
- ch = str[2+2*i];
- if (!is_hex_digit(ch)) break;
- info->user[i] = hex_to_uint(&str[2+2*i], 2);
- }
- info->nuser = i;
- break;
+ case 'u': /* user data */
+ for (i = 0; i < 127; ++i)
+ {
+ ch = str[2+2*i];
+ if (!is_hex_digit(ch))
+ break;
+ info->user[i] = hex_to_uint(&str[2+2*i], 2);
+ }
+ info->nuser = i;
+ break;
- case 'f': /* facilities */
- for (i = 0; i < 64; ++i)
- {
- ch = str[2+4*i];
- if (!is_hex_digit(ch)) break;
- info->facil[i].code =
- hex_to_uint(&str[2+4*i], 2)
- ;
- ch = str[4+4*i];
- if (!is_hex_digit(ch)) break;
- info->facil[i].parm =
- hex_to_uint(&str[4+4*i], 2)
- ;
- }
- info->nfacil = i;
- break;
+ case 'f': /* facilities */
+ for (i = 0; i < 64; ++i)
+ {
+ ch = str[2+4*i];
+ if (!is_hex_digit(ch))
+ break;
+ info->facil[i].code =
+ hex_to_uint(&str[2+4*i], 2);
+ ch = str[4+4*i];
+ if (!is_hex_digit(ch))
+ break;
+ info->facil[i].parm =
+ hex_to_uint(&str[4+4*i], 2);
+ }
+ info->nfacil = i;
+ break;
}
}
}
@@ -2279,8 +2235,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len)
if (!len) len = strlen(str);
for (val = 0; len && is_digit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned)'0')
- ;
+ val = (val * 10) + (*str - (unsigned)'0');
return val;
}
@@ -2297,12 +2252,11 @@ static unsigned int hex_to_uint (unsigned char* str, int len)
{
ch = *str;
if (is_digit(ch))
- val = (val << 4) + (ch - (unsigned)'0')
- ;
+ val = (val << 4) + (ch - (unsigned)'0');
else if (is_hex_digit(ch))
- val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
- ;
- else break;
+ val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
+ else
+ break;
}
return val;
}
@@ -2334,22 +2288,18 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
/* It's a timer request packet */
printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
- /* Go through the routing options and answer no to every */
- /* option except Unnumbered RIP/SAP */
+ /* Go through the routing options and answer no to every
+ * option except Unnumbered RIP/SAP */
for(i = 41; sendpacket[i] == 0x00; i += 5)
{
/* 0x02 is the option for Unnumbered RIP/SAP */
if( sendpacket[i + 4] != 0x02)
- {
sendpacket[i + 1] = 0;
- }
}
/* Skip over the extended Node ID option */
if( sendpacket[i] == 0x04 )
- {
i += 8;
- }
/* We also want to turn off all header compression opt. */
for(; sendpacket[i] == 0x80 ;)
@@ -2388,15 +2338,13 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
for(i = 66; i < 99; i+= 1)
- {
sendpacket[i] = 0;
- }
- /* printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); */
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
}
else
{
- printk(KERN_WARNING "%s: Unknown IPXWAN packet!\n",devname);
+ printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
return 0;
}
@@ -2408,9 +2356,8 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
return 1;
} else {
- /* If we get here its an IPX-data packet, so it'll get passed up the stack. */
-
- /* switch the network numbers */
+ /* If we get here its an IPX-data packet, so it'll get passed up the stack.
+ switch the network numbers */
switch_net_numbers(sendpacket, network_number, 1);
return 0;
}
@@ -2421,6 +2368,7 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char
if incoming is 1 - if the net number is 0 make it ours
*/
+
static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
{
unsigned long pnetwork_number;
@@ -2429,15 +2377,20 @@ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_
(sendpacket[7] << 16) + (sendpacket[8] << 8) +
sendpacket[9]);
- if (!incoming) {
+ if (!incoming)
+ {
/* If the destination network number is ours, make it 0 */
- if( pnetwork_number == network_number) {
+ if( pnetwork_number == network_number)
+ {
sendpacket[6] = sendpacket[7] = sendpacket[8] =
sendpacket[9] = 0x00;
}
- } else {
+ }
+ else
+ {
/* If the incoming network is 0, make it ours */
- if( pnetwork_number == 0) {
+ if( pnetwork_number == 0)
+ {
sendpacket[6] = (unsigned char)(network_number >> 24);
sendpacket[7] = (unsigned char)((network_number &
0x00FF0000) >> 16);
@@ -2453,15 +2406,20 @@ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_
(sendpacket[19] << 16) + (sendpacket[20] << 8) +
sendpacket[21]);
- if( !incoming ) {
+ if( !incoming )
+ {
/* If the source network is ours, make it 0 */
- if( pnetwork_number == network_number) {
+ if( pnetwork_number == network_number)
+ {
sendpacket[18] = sendpacket[19] = sendpacket[20] =
sendpacket[21] = 0x00;
}
- } else {
+ }
+ else
+ {
/* If the source network is 0, make it ours */
- if( pnetwork_number == 0 ) {
+ if( pnetwork_number == 0 )
+ {
sendpacket[18] = (unsigned char)(network_number >> 24);
sendpacket[19] = (unsigned char)((network_number &
0x00FF0000) >> 16);
diff --git a/drivers/net/sdladrv.c b/drivers/net/sdladrv.c
index e756d8fdc..3adc0ba8e 100644
--- a/drivers/net/sdladrv.c
+++ b/drivers/net/sdladrv.c
@@ -324,6 +324,9 @@ void cleanup_module (void)
* Return: 0 ok.
* < 0 error
*/
+
+EXPORT_SYMBOL(sdla_setup);
+
int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
{
unsigned* irq_opt = NULL; /* IRQ options */
@@ -449,6 +452,9 @@ int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
/*============================================================================
* Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
*/
+
+EXPORT_SYMBOL(sdla_down);
+
int sdla_down (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -491,6 +497,9 @@ int sdla_down (sdlahw_t* hw)
/*============================================================================
* Map shared memory window into SDLA adress space.
*/
+
+EXPORT_SYMBOL(sdla_mapmem);
+
int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
{
unsigned port = hw->port;
@@ -552,6 +561,9 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
/*============================================================================
* Enable interrupt generation.
*/
+
+EXPORT_SYMBOL(sdla_inten);
+
int sdla_inten (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -606,6 +618,9 @@ int sdla_inten (sdlahw_t* hw)
/*============================================================================
* Disable interrupt generation.
*/
+
+EXPORT_SYMBOL(sdla_intde);
+
int sdla_intde (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -662,6 +677,9 @@ int sdla_intde (sdlahw_t* hw)
/*============================================================================
* Acknowledge SDLA hardware interrupt.
*/
+
+EXPORT_SYMBOL(sdla_intack);
+
int sdla_intack (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -711,6 +729,9 @@ int sdla_intack (sdlahw_t* hw)
/*============================================================================
* Generate an interrupt to adapter's CPU.
*/
+
+EXPORT_SYMBOL(sdla_intr);
+
int sdla_intr (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -756,6 +777,9 @@ int sdla_intr (sdlahw_t* hw)
* o Busy-wait until flag is reset.
* o Return number of loops made, or 0 if command timed out.
*/
+
+EXPORT_SYMBOL(sdla_exec);
+
int sdla_exec (void* opflag)
{
volatile unsigned char* flag = opflag;
@@ -784,6 +808,9 @@ int sdla_exec (void* opflag)
* This function is not atomic, so caller must disable interrupt if
* interrupt routines are accessing adapter shared memory.
*/
+
+EXPORT_SYMBOL(sdla_peek);
+
int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
{
unsigned long oldvec = hw->vector;
@@ -823,6 +850,9 @@ int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
* This function is not atomic, so caller must disable interrupt if
* interrupt routines are accessing adapter shared memory.
*/
+
+EXPORT_SYMBOL(sdla_poke);
+
int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
{
unsigned long oldvec = hw->vector;
@@ -1827,4 +1857,5 @@ static unsigned short checksum (unsigned char* buf, unsigned len)
return crc;
}
+
/****** End *****************************************************************/
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index c66f58e7c..82f75efbb 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,7 +1,9 @@
-/* $Id: sgiseeq.c,v 1.5 1997/12/06 23:53:49 ralf Exp $
+/*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: sgiseeq.c,v 1.3 1997/11/16 13:57:45 alan Exp $
*/
#include <linux/kernel.h>
@@ -15,6 +17,7 @@
#include <linux/string.h>
#include <linux/delay.h>
+#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -173,7 +176,7 @@ static void seeq_init_ring(struct device *dev)
buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer);
- flush_cache_all();
+// flush_cache_all();
}
ib->tx_desc[i].tdma.cntinfo = (TCNTINFO_INIT);
}
@@ -186,7 +189,7 @@ static void seeq_init_ring(struct device *dev)
buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer);
- flush_cache_all();
+// flush_cache_all();
}
ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT);
}
@@ -662,15 +665,17 @@ int sgiseeq_init(struct device *dev, struct sgiseeq_regs *sregs,
sp->name = sgiseeqstr;
sp->srings.rx_desc = (struct sgiseeq_rx_desc *)
- (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])));
+ (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])));
+ dma_cache_wback_inv((unsigned long)&sp->srings.rxvector,
+ sizeof(sp->srings.rxvector));
sp->srings.tx_desc = (struct sgiseeq_tx_desc *)
- (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])));
- flush_cache_all();
+ (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])));
+ dma_cache_wback_inv((unsigned long)&sp->srings.txvector,
+ sizeof(sp->srings.txvector));
/* A couple calculations now, saves many cycles later. */
setup_rx_ring(sp->srings.rx_desc, SEEQ_RX_BUFFERS);
setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS);
- flush_cache_all();
/* Reset the chip. */
hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs);
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 6ef0a66f8..4dbaad977 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -762,17 +762,17 @@ __initfunc(int SK_probe(struct device *dev, short ioaddr))
dev->dev_addr[4],
dev->dev_addr[5]);
- /* Grab the I/O Port region */
- request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16");
-
- /* Initialize device structure */
-
/* Allocate memory for private structure */
p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL);
- if (p == NULL)
+ if (p == NULL) {
+ printk("%s: ERROR - no memory for driver data!\n", dev->name);
return -ENOMEM;
+ }
memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */
+ /* Grab the I/O Port region */
+ request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16");
+
/* Assign our Device Driver functions */
dev->open = &SK_open;
diff --git a/drivers/nubus/Makefile b/drivers/nubus/Makefile
new file mode 100644
index 000000000..781edd052
--- /dev/null
+++ b/drivers/nubus/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the nubus specific drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+L_OBJS := nubus.o
+L_TARGET := nubus.a
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
new file mode 100644
index 000000000..d266c64b7
--- /dev/null
+++ b/drivers/nubus/nubus.c
@@ -0,0 +1,629 @@
+/*
+ * Macintosh Nubus Interface Code
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <linux/errno.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/page.h>
+/* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */
+#include <asm/macintosh.h>
+
+#undef LCIII_WEIRDNESS
+
+static struct nubus_slot nubus_slots[16];
+
+/*
+ * Please skip to the bottom of this file if you ate lunch recently
+ * -- Alan
+ */
+
+
+
+/* This function tests for the presence of an address, specially a
+ * hardware register address. It is called very early in the kernel
+ * initialization process, when the VBR register isn't set up yet. On
+ * an Atari, it still points to address 0, which is unmapped. So a bus
+ * error would cause another bus error while fetching the exception
+ * vector, and the CPU would do nothing at all. So we needed to set up
+ * a temporary VBR and a vector table for the duration of the test.
+ *
+ * See the atari/config.c code we nicked it from for more clues.
+ */
+
+int nubus_hwreg_present( volatile void *regp )
+{
+ int ret = 0;
+ long save_sp, save_vbr;
+ long tmp_vectors[3];
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ __asm__ __volatile__
+ ( "movec %/vbr,%2\n\t"
+ "movel #Lberr1,%4@(8)\n\t"
+ "movec %4,%/vbr\n\t"
+ "movel %/sp,%1\n\t"
+ "moveq #0,%0\n\t"
+ "tstb %3@\n\t"
+ "nop\n\t"
+ "moveq #1,%0\n"
+ "Lberr1:\n\t"
+ "movel %1,%/sp\n\t"
+ "movec %2,%/vbr"
+ : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+ : "a" (regp), "a" (tmp_vectors)
+ );
+ restore_flags(flags);
+ return( ret );
+}
+
+
+
+/*
+ * Yes this sucks. The ROM can appear on arbitary bytes of the long
+ * word. We are not amused.
+ */
+
+extern __inline__ int not_useful(void *p, int map)
+{
+ unsigned long pv=(unsigned long)p;
+ pv&=3;
+ if(map&(1<<pv))
+ return 0;
+ return 1;
+}
+
+static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
+{
+ unsigned long v=0;
+ unsigned char *p=*ptr; /* as v|=*((*ptr)++) upset someone */
+ while(len)
+ {
+ v<<=8;
+ while(not_useful(p,map))
+ p++;
+ v|=*p++;
+ len--;
+ }
+ *ptr=p;
+ return v;
+}
+
+static void nubus_rewind(unsigned char **ptr, int len, int map)
+{
+ unsigned char *p=*ptr;
+
+ if(len>8192)
+ printk("rewind of %d!\n", len);
+ while(len)
+ {
+ do
+ {
+ p--;
+ }
+ while(not_useful(p,map));
+ len--;
+ }
+ *ptr=p;
+}
+
+static void nubus_advance(unsigned char **ptr, int len, int map)
+{
+ unsigned char *p=*ptr;
+ if(len>8192)
+ printk("advance of %d!\n", len);
+ while(len)
+ {
+ while(not_useful(p,map))
+ p++;
+ p++;
+ len--;
+ }
+ *ptr=p;
+}
+
+/*
+ * 24bit signed offset to 32bit
+ */
+
+static unsigned long nubus_expand32(unsigned long foo)
+{
+ if(foo&0x00800000) /* 24bit negative */
+ foo|=0xFF000000;
+ return foo;
+}
+
+static void nubus_move(unsigned char **ptr, int len, int map)
+{
+ if(len>0)
+ nubus_advance(ptr,len,map);
+ else if(len<0)
+ nubus_rewind(ptr,-len,map);
+}
+
+static void *nubus_rom_addr(int slot)
+{
+ /*
+ * Returns the first byte after the card. We then walk
+ * backwards to get the lane register and the config
+ */
+ return (void *)(0xF1000000+(slot<<24));
+}
+
+void nubus_memcpy(int slot, void *to, unsigned char *p, int len)
+{
+ unsigned char *t=(unsigned char *)to;
+ while(len)
+ {
+ *t++=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes);
+ len--;
+ }
+}
+
+void nubus_strncpy(int slot, void *to, unsigned char *p, int len)
+{
+ unsigned char *t=(unsigned char *)to;
+ while(len)
+ {
+ *t=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes);
+ if(!*t++)
+ break;
+ len--;
+ }
+}
+
+
+
+
+unsigned char *nubus_dirptr(struct nubus_dirent *nd)
+{
+ unsigned char *p=(unsigned char *)(nd->base);
+
+ nubus_move(&p, nubus_expand32(nd->value), nd->mask);
+ return p;
+}
+
+
+struct nubus_dir *nubus_openrootdir(int slot)
+{
+ static struct nubus_dir nbdir;
+ unsigned char *rp=nubus_rom_addr(slot);
+
+ nubus_rewind(&rp,20, nubus_slots[slot].slot_lanes);
+
+ nubus_move(&rp, nubus_expand32(nubus_slots[slot].slot_directory),
+ nubus_slots[slot].slot_lanes);
+
+ nbdir.base=rp;
+ nbdir.length=nubus_slots[slot].slot_dlength;
+ nbdir.count=0;
+ nbdir.mask=nubus_slots[slot].slot_lanes;
+ return &nbdir;
+}
+
+struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d)
+{
+ static struct nubus_dir nbdir;
+ unsigned char *rp=nubus_dirptr(d);
+ nbdir.base=rp;
+ nbdir.length=99999;/*slots[i].slot_dlength;*/
+ nbdir.count=0;
+ nbdir.mask=d->mask;
+ return &nbdir;
+}
+
+void nubus_closedir(struct nubus_dir *nd)
+{
+ ;
+}
+
+struct nubus_dirent *nubus_readdir(struct nubus_dir *nd)
+{
+ u32 resid;
+ u8 rescode;
+ static struct nubus_dirent d;
+
+ if(nd->count==nd->length)
+ return NULL;
+
+ d.base=(unsigned long)nd->base;
+
+ resid=nubus_get_rom(&nd->base, 4, nd->mask);
+ nd->count++;
+ rescode=resid>>24;
+ if(rescode==0xFF)
+ {
+ nd->count=nd->length;
+ return NULL;
+ }
+ d.type=rescode;
+ d.value=resid&0xFFFFFF;
+ d.mask=nd->mask;
+ return &d;
+}
+
+/*
+ * MAC video handling irritations
+ */
+
+static unsigned char nubus_vid_byte[16];
+static unsigned long nubus_vid_offset[16];
+
+static void nubus_irqsplat(int slot, void *dev_id, struct pt_regs *regs)
+{
+ unsigned char *p=((unsigned char *)nubus_slot_addr(slot))+
+ nubus_vid_offset[slot];
+ *p=nubus_vid_byte[slot];
+}
+
+static int nubus_add_irqsplatter(int slot, unsigned long ptr, unsigned char v)
+{
+ nubus_vid_byte[slot]=v;
+ nubus_vid_offset[slot]=ptr;
+ nubus_request_irq(slot, NULL, nubus_irqsplat);
+ return 0;
+}
+
+void nubus_video_shutup(int slot, struct nubus_type *nt)
+{
+ if(nt->category!=3 /* Display */ || nt->type!=1 /* Video */
+ || nt->DrSW!=1 /* Quickdraw device */)
+ return;
+ switch(nt->DrHW)
+ {
+ /*
+ * Toby and MacII Hires cards. These behave in a MacII
+ * anyway but not on an RBV box
+ */
+ case 0x0001:
+ case 0x0013:
+ nubus_add_irqsplatter(slot, 0xA0000, 0);
+ break;
+ /*
+ * Apple workstation video card.
+ */
+ case 0x0006:
+ nubus_add_irqsplatter(slot, 0xA00000, 0);
+ break;
+ /*
+ * Futura cards
+ */
+ case 0x0417:
+ case 0x042F:
+ nubus_add_irqsplatter(slot, 0xF05000, 0x80);
+ break;
+
+ /*
+ * Fingers crossed 8)
+ *
+ * If you have another card and an RBV based mac you'll
+ * almost certainly have to add it here to make it work.
+ */
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Device list
+ */
+
+static struct nubus_device_specifier *nubus_device_list=NULL;
+
+void register_nubus_device(struct nubus_device_specifier *d)
+{
+ d->next=nubus_device_list;
+ nubus_device_list=d;
+}
+
+void unregister_nubus_device(struct nubus_device_specifier *nb)
+{
+ struct nubus_device_specifier **t=&nubus_device_list;
+ while(*t!=nb && *t)
+ t=&((*t)->next);
+ *t=nb->next;
+}
+
+static struct nubus_device_specifier *find_nubus_device(int slot, struct nubus_type *nt)
+{
+ struct nubus_device_specifier *t=nubus_device_list;
+ while(t!=NULL)
+ {
+ if(t->setup(t,slot, nt)==0)
+ return t;
+ t=t->next;
+ }
+ printk("No driver for device [%d %d %d %d]\n",
+ nt->category, nt->type, nt->DrHW, nt->DrSW);
+ return NULL;
+}
+
+/*
+ * Probe a nubus slot
+ */
+
+void nubus_probe_slot(int slot, int mode)
+{
+ unsigned char *rp;
+ unsigned char dp;
+ int lanes;
+ int i;
+ unsigned long dpat;
+ struct nubus_dir *dir;
+ struct nubus_dirent *nd;
+ struct nubus_type type_info;
+
+ /*
+ * Ok see whats cooking in the bytelanes
+ */
+
+ rp=nubus_rom_addr(slot);
+
+ for(i=4;i;i--)
+ {
+ rp--;
+
+ if(!nubus_hwreg_present(rp))
+ continue;
+
+ dp=*rp;
+
+ if(dp==0)
+ continue;
+
+ /*
+ * Valid ?
+ */
+
+ if((((dp>>4)^dp)&0x0F)!=0x0F)
+ continue;
+
+ if((dp&0x0F) >= 1<<i)
+ continue;
+
+ /*
+ * Looks promising
+ */
+
+ nubus_slots[slot].slot_flags|=NUBUS_DEVICE_PRESENT;
+ lanes=dp;
+
+ if (mode==0)
+ printk("nubus%c: ",
+ "0123456789abcdef"[slot]);
+
+
+ /*
+ * Time to dig deeper. Find the ROM base
+ * and read it
+ */
+
+ rp=nubus_rom_addr(slot);
+
+ /*
+ * Now to make this more fun the ROM is only visible
+ * on its bytelanes - that is smeared across the address
+ * space.
+ */
+
+ nubus_rewind(&rp,20,lanes);
+
+ nubus_slots[slot].slot_directory= nubus_get_rom(&rp,4,lanes);
+ nubus_slots[slot].slot_dlength = nubus_get_rom(&rp,4,lanes);
+ nubus_slots[slot].slot_crc = nubus_get_rom(&rp,4,lanes);
+ nubus_slots[slot].slot_rev = nubus_get_rom(&rp,1,lanes);
+ nubus_slots[slot].slot_format = nubus_get_rom(&rp,1,lanes);
+ nubus_slots[slot].slot_lanes = lanes;
+
+ dpat=nubus_get_rom(&rp,4,lanes);
+
+ /*
+ * Ok now check what we got
+ */
+
+ if(!(nubus_slots[slot].slot_directory&0x00FF0000))
+ printk("Dodgy doffset ??\n");
+ if(dpat!=0x5A932BC7)
+ printk("Wrong test pattern %lx\n",dpat);
+
+ /*
+ * I wonder how the CRC is meant to work -
+ * any takers ?
+ */
+
+
+ /*
+ * Now parse the directories on the card
+ */
+
+
+ dir=nubus_openrootdir(slot);
+
+ /*
+ * Find the board resource
+ */
+
+ while((nd=nubus_readdir(dir))!=NULL)
+ {
+ /*
+ * This ought to be 1. 1 doesn't work, 0x80
+ * does. Seems the Apple docs are wrong.
+ */
+ if(nd->type==0x80/*RES_ID_BOARD_DIR*/)
+ break;
+ }
+
+ nubus_closedir(dir);
+
+ if(nd==NULL)
+ {
+ printk("board resource not found!\n");
+ return;
+ }
+
+ dir=nubus_opensubdir(nd);
+
+ /*
+ * Walk the board resource
+ */
+
+ while((nd=nubus_readdir(dir))!=NULL)
+ {
+ switch(nd->type)
+ {
+ case RES_ID_TYPE:
+ {
+ unsigned short nbtdata[4];
+ nubus_memcpy(slot, nbtdata, nubus_dirptr(nd), 8);
+ type_info.category=nbtdata[0];
+ type_info.type=nbtdata[1];
+ type_info.DrHW=nbtdata[2];
+ type_info.DrSW=nbtdata[3];
+ break;
+ }
+ case RES_ID_NAME:
+ nubus_strncpy(slot, nubus_slots[slot].slot_cardname,nubus_dirptr(nd),64);
+ break;
+ default:
+ ;
+ }
+ }
+
+ nubus_closedir(dir);
+
+ /*
+ * Attempt to bind a driver to this slot
+ */
+
+ if (mode==0) {
+ printk("%s\n",
+ nubus_slots[slot].slot_cardname);
+ find_nubus_device(slot,&type_info);
+ }
+ if (mode==1)
+ nubus_video_shutup(slot, &type_info);
+
+ return;
+ }
+}
+
+
+void nubus_probe_bus(void)
+{
+ int i;
+ for(i=9;i<15;i++)
+ {
+ /* printk("nubus: probing slot %d !\n", i); */
+ nubus_probe_slot(i, 0);
+ }
+}
+
+/*
+ * RBV machines have level triggered video interrupts, and a VIA
+ * emulation that doesn't always seem to include being able to disable
+ * an interrupt. Totally lusing hardware. Before we can init irq's we
+ * have to install a handler to shut the bloody things up.
+ */
+
+void nubus_sweep_video(void)
+{
+ int i;
+ return; /* XXX why ?? */
+ for(i=9;i<15;i++)
+ {
+ nubus_probe_slot(i,1);
+ }
+}
+
+/*
+ * Support functions
+ */
+
+int nubus_ethernet_addr(int slot, unsigned char *addr)
+{
+ struct nubus_dir *nb;
+ struct nubus_dirent *d;
+ int ng=-ENOENT;
+
+ nb=nubus_openrootdir(slot);
+
+ if(nb==NULL)
+ return -ENOENT;
+
+ while((d=nubus_readdir(nb))!=NULL)
+ {
+ if(d->type==0x80) /* First private resource */
+ break;
+ }
+ if(d==NULL)
+ return -ENOENT;
+
+ nb=nubus_opensubdir(d);
+
+ while((d=nubus_readdir(nb))!=NULL)
+ {
+ if(d->type==0x80) /* First private field is the mac */
+ {
+ int i;
+ nubus_memcpy(slot, addr, nubus_dirptr(d), 6);
+/* printk("d.base=%lX, d.value=%lX\n",
+ d->base,d->value);
+ memcpy(addr,"\xC0\xC1\xC2\xC3\xC4\xC5",6);*/
+ printk("MAC address: ");
+ for(i=0;i<6;i++)
+ {
+ printk("%s%02X", i?":":"", addr[i]);
+ }
+ ng=0;
+ break;
+ }
+ else
+ printk("ID=%d val=%x\n",
+ d->type, d->value);
+ }
+ return ng;
+}
+
+void nubus_init(void)
+{
+ /*
+ * Register cards
+ */
+#ifdef CONFIG_DAYNAPORT
+ extern struct nubus_device_specifier nubus_8390;
+#endif
+
+ if (!MACH_IS_MAC)
+ return;
+
+#ifdef LCIII_WEIRDNESS
+ if (macintosh_config->ident == MAC_MODEL_LCIII) {
+ printk("nubus init: LCIII has no nubus!\n");
+ return;
+ }
+#endif
+
+#ifdef CONFIG_DAYNAPORT
+ register_nubus_device(&nubus_8390);
+#endif
+
+ /*
+ * And probe
+ */
+
+ nubus_init_via();
+ printk("Scanning nubus slots.\n");
+ nubus_probe_bus();
+}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b12b2a454..de7b85cdc 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -71,7 +71,7 @@ const char *pcibios_strerror(int error)
unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
{
unsigned int devfn, l, max, class;
- unsigned char cmd, irq, tmp, hdr_type = 0;
+ unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
struct pci_dev *dev;
struct pci_bus *child;
int reg;
@@ -82,12 +82,13 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
max = bus->secondary;
for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) == 0) {
- pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
- } else if (!(hdr_type & 0x80)) {
+ if (PCI_FUNC(devfn) && !is_multi) {
/* not a multi-function device */
continue;
}
+ pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
+ if (!PCI_FUNC(devfn))
+ is_multi = hdr_type & 0x80;
pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l);
/* some broken boards return 0 if a slot is empty: */
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 95400fe68..93a30f3e9 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -2,7 +2,7 @@
* 53c710 driver. Modified from Drew Eckhardts driver
* for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
* Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
- * relevant machine specific file (eg. mvme166.[ch], amiga7xx.[ch]).
+ * relevant machine specific file (eg. mvme16x.[ch], amiga7xx.[ch]).
* There are also currently some defines at the top of 53c7xx.scr.
* The chip type is #defined in script_asm.pl, as well as the Makefile.
* Host scsi ID expected to be 7 - see NCR53c7x0_init().
@@ -10,9 +10,9 @@
* I have removed the PCI code and some of the 53c8xx specific code -
* simply to make this file smaller and easier to manage.
*
- * MVME166 issues:
+ * MVME16x issues:
* Problems trying to read any chip registers in NCR53c7x0_init(), as they
- * may never have been set by 166Bug (eg. If kernel has come in over tftp).
+ * may never have been set by 16xBug (eg. If kernel has come in over tftp).
*/
/*
@@ -45,6 +45,9 @@
* validids:0x?? - Bitmask field that disallows certain ID's.
* - e.g. 0x03 allows ID 0,1
* - 0x1F allows ID 0,1,2,3,4
+ * opthi:n - replace top word of options with 'n'
+ * optlo:n - replace bottom word of options with 'n'
+ * - ALWAYS SPECIFY opthi THEN optlo <<<<<<<<<<
*/
/*
@@ -60,7 +63,7 @@
* out brain damaged main boards.
*
* Other PERM_OPTIONS settings are listed below. Note the actual options
- * required are set in the relevant file (mvme166.c, amiga7xx.c, etc):
+ * required are set in the relevant file (mvme16x.c, amiga7xx.c, etc):
*
* OPTION_NO_ASYNC
* Don't negotiate for asynchronous transfers on the first command
@@ -231,6 +234,9 @@
#endif
#include <linux/config.h>
+
+#include <linux/types.h>
+#include <asm/setup.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -259,11 +265,13 @@
#define NO_IO_SPACE
#endif
-#ifdef CONFIG_MVME166
-#include <asm/mvme166hw.h>
+#ifdef CONFIG_MVME16x
+#include <asm/pgtable.h>
+#include <asm/mvme16xhw.h>
#define BIG_ENDIAN
#define NO_IO_SPACE
+#define VALID_IDS
#endif
#include "scsi.h"
@@ -636,6 +644,7 @@ static const unsigned char wdtr_message[] = {
EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
};
+#if 0
/*
* Function : struct Scsi_Host *find_host (int host)
*
@@ -734,6 +743,7 @@ request_disconnect (int host, int on_or_off) {
hostdata->options &= ~OPTION_DISCONNECT;
return 0;
}
+#endif
/*
* Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
@@ -751,10 +761,6 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
int i, j;
u32 *ncrcurrent;
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
for (i = 0; i < 16; ++i) {
hostdata->request_sense[i] = 0;
for (j = 0; j < 8; ++j)
@@ -783,9 +789,9 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
hostdata->initiate_sdtr = 0;
hostdata->talked_to = 0;
hostdata->idle = 1;
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (!MACH_IS_MVME16x)
+ cache_push(virt_to_bus(hostdata->script), flushsize);
}
/*
@@ -877,18 +883,22 @@ NCR53c7x0_init (struct Scsi_Host *host) {
setup_used[--i] = 1;
}
+ if (check_setup_strings("opthi",&flags,&val,buf))
+ hostdata->options = (long long)val << 32;
+ if (check_setup_strings("optlo",&flags,&val,buf))
+ hostdata->options |= val;
NCR53c7x0_local_setup(host);
-
switch (hostdata->chip) {
case 710:
+ case 770:
hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
hostdata->init_save_regs = NULL;
hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
hostdata->init_fixup = NCR53c7x0_init_fixup;
hostdata->soft_reset = NCR53c7x0_soft_reset;
hostdata->run_tests = NCR53c7xx_run_tests;
- expected_clock = hostdata->scsi_clock = 50000000;
+ expected_clock = hostdata->scsi_clock;
expected_id = 7;
break;
default:
@@ -904,7 +914,6 @@ NCR53c7x0_init (struct Scsi_Host *host) {
hostdata->NCR53c7xx_msg_abort = ABORT;
hostdata->NCR53c7xx_msg_nop = NOP;
hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
-
if (expected_mapping == -1 ||
(hostdata->options & (OPTION_MEMORY_MAPPED)) !=
(expected_mapping & OPTION_MEMORY_MAPPED))
@@ -917,6 +926,12 @@ NCR53c7x0_init (struct Scsi_Host *host) {
hostdata->istat = ((hostdata->chip / 100) == 8) ?
ISTAT_REG_800 : ISTAT_REG_700;
+/* We have to assume that this may be the first access to the chip, so
+ * we must set EA in DCNTL. */
+
+ NCR53c7x0_write8 (DCNTL_REG, DCNTL_10_EA|DCNTL_10_COM);
+
+
/* Only the ISTAT register is readable when the NCR is running, so make
sure it's halted. */
ncr_halt(host);
@@ -990,7 +1005,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
* On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
* on 800 series chips, it allows for a totem-pole IRQ driver.
* NOTE saved_dcntl currently overwritten in init function.
- * The value read here may be garbage anyway, MVME166 board at least
+ * The value read here may be garbage anyway, MVME16x board at least
* does not initialise chip if kernel arrived via tftp.
*/
@@ -999,7 +1014,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
/*
* DMODE controls DMA burst length, and on 700 series chips,
* 286 mode and bus width
- * NOTE: On MVME166, chip may have been reset, so this could be a
+ * NOTE: On MVME16x, chip may have been reset, so this could be a
* power-on/reset default value.
*/
hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
@@ -1053,11 +1068,11 @@ NCR53c7x0_init (struct Scsi_Host *host) {
* with another board.
*/
-#ifdef CONFIG_MVME166
- if (request_irq(IRQ_MVME166_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+#ifdef CONFIG_MVME16x
+ if (request_irq(IRQ_MVME16x_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
panic ("Couldn't get SCSI IRQ");
-#ifdef MVME166_INTFLY
- else if (request_irq(IRQ_MVME166_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+#ifdef MVME16x_INTFLY
+ else if (request_irq(IRQ_MVME16x_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
panic ("Couldn't get INT_FLY IRQ");
#endif
#else
@@ -1105,10 +1120,9 @@ NCR53c7x0_init (struct Scsi_Host *host) {
}
/*
- * Function : static int normal_init(Scsi_Host_Template *tpnt, int board,
- * int chip, u32 base, int io_port, int irq, int dma, int pcivalid,
- * unsigned char pci_bus, unsigned char pci_device_fn,
- * long long options);
+ * Function : static int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board,
+ * int chip, u32 base, int io_port, int irq, int dma,
+ * long long options, int clock);
*
* Purpose : initializes a NCR53c7,8x0 based on base addresses,
* IRQ, and DMA channel.
@@ -1137,6 +1151,7 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
switch (chip) {
case 710:
+ case 770:
schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
script_len = NCR53c7xx_script_len;
dsa_len = NCR53c7xx_dsa_len;
@@ -1214,7 +1229,7 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
/* FIXME : if we ever support an ISA NCR53c7xx based board, we
need to check if the chip is running in a 16 bit mode, and if so
unregister it if it is past the 16M (0x1000000) mark */
-
+
hostdata = (struct NCR53c7x0_hostdata *)
instance->hostdata;
hostdata->size = size;
@@ -1269,6 +1284,7 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
hostdata->dsa_len = dsa_len;
hostdata->max_cmd_size = max_cmd_size;
hostdata->num_cmds = 1;
+ hostdata->scsi_clock = clock;
/* Initialize single command */
tmp = (hostdata->script + hostdata->script_count);
#ifdef FORCE_DSA_ALIGNMENT
@@ -1393,8 +1409,8 @@ NCR53c7x0_init_fixup (struct Scsi_Host *host) {
* register. Make sure SCRIPTS start automagically.
*/
-#if defined(CONFIG_MVME166)
- /* We know better what we want than 166Bug does! */
+#if defined(CONFIG_MVME16x)
+ /* We know better what we want than 16xBug does! */
tmp = DMODE_10_BL_8 | DMODE_10_FC2;
#else
tmp = NCR53c7x0_read8(DMODE_REG_10);
@@ -1543,9 +1559,9 @@ NCR53c7x0_init_fixup (struct Scsi_Host *host) {
printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(hostdata->script), hostdata->script);
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (!MACH_IS_MVME16x)
+ cache_push(virt_to_bus(hostdata->script), flushsize);
}
/*
@@ -1599,9 +1615,8 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
hostdata->state = STATE_RUNNING;
printk ("scsi%d : test 1", host->host_no);
- flush_cache_all();
- cache_push(virt_to_bus(hostdata->script), flushsize);
- cache_clear(virt_to_bus(hostdata->script), flushsize);
+ if (!MACH_IS_MVME16x)
+ cache_push(virt_to_bus(hostdata->script), flushsize);
NCR53c7x0_write32 (DSP_REG, start);
if (hostdata->options & OPTION_DEBUG_TRACE)
NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
@@ -1695,8 +1710,8 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
hostdata->test_completed = -1;
start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
hostdata->state = STATE_RUNNING;
- flush_cache_all();
- cache_clear(virt_to_bus(hostdata->script), flushsize);
+ if(!MACH_IS_MVME16x)
+ cache_clear(virt_to_bus(hostdata->script), flushsize);
NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
NCR53c7x0_write32 (DSP_REG, start);
if (hostdata->options & OPTION_DEBUG_TRACE)
@@ -1803,9 +1818,10 @@ NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
+ if (!MACH_IS_MVME16x) {
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+ cache_push(virt_to_bus(cmd->dsa), flushsize);
+ }
}
/*
@@ -1988,8 +2004,6 @@ intr_break (struct Scsi_Host *host, struct
*/
save_flags(flags);
cli();
- flush_cache_all();
- cache_push(virt_to_bus(hostdata->script), flushsize);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
for (bp = hostdata->breakpoints; bp && bp->address != dsp;
bp = bp->next);
@@ -2258,14 +2272,20 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
host->hostdata;
u32 dsps,*dsp; /* Argument of the INT instruction */
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
NCR53c7x0_local_setup(host);
dsps = NCR53c7x0_read32(DSPS_REG);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ /* RGH 150597: Frig. Commands which fail with Check Condition are
+ * Flagged as successful - hack dsps to indicate check condition */
+#if 0
+ /* RGH 200597: Need to disable for BVME6000, as it gets Check Conditions
+ * and then dies. Seems to handle Check Condition at startup, but
+ * not mid kernel build. */
+ if (dsps == A_int_norm_emulateintfly && c && c->result == 2)
+ dsps = A_int_err_check_condition;
+#endif
+
if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
@@ -2870,9 +2890,9 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
host->host_no, (unsigned) dsps);
return SPECIFIC_INT_PANIC;
}
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (!MACH_IS_MVME16x)
+ flush_cache_all();
}
/*
@@ -2910,7 +2930,7 @@ static void
NCR53c7x0_soft_reset (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
unsigned long flags;
-#ifdef CONFIG_MVME166
+#ifdef CONFIG_MVME16x
volatile unsigned long v;
#endif
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
@@ -2922,7 +2942,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) {
/* Disable scsi chip and s/w level 7 ints */
-#ifdef CONFIG_MVME166
+#ifdef CONFIG_MVME16x
v = *(volatile unsigned long *)0xfff4006c;
v &= ~0x8000;
*(volatile unsigned long *)0xfff4006c = v;
@@ -2997,7 +3017,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) {
SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
SIEN_SGE | SIEN_MA);
-#ifdef CONFIG_MVME166
+#ifdef CONFIG_MVME16x
/* Enable scsi chip and s/w level 7 ints */
v = *(volatile unsigned long *)0xfff40080;
@@ -3285,10 +3305,6 @@ create_cmd (Scsi_Cmnd *cmd) {
patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
exp_select_indirect = ((1 << cmd->target) << 16) |
@@ -3306,11 +3322,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
patch_dsa_32(tmp->dsa, dsa_select, 0,
hostdata->sync[cmd->target].select_indirect);
-
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
/*
* Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
* different commands; although it should be trivial to do them
@@ -3339,10 +3350,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
else if (!(hostdata->talked_to & (1 << cmd->target)) &&
!(hostdata->options & OPTION_NO_ASYNC)) {
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
memcpy ((void *) (tmp->select + 1), (void *) async_message,
sizeof(async_message));
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
@@ -3352,10 +3359,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
else
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
hostdata->talked_to |= (1 << cmd->target);
tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
@@ -3429,11 +3432,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
* Not bad, not good. We'll see.
*/
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
-
for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
cmd_dataout += 4, ++i) {
u32 buf = cmd->use_sg ?
@@ -3476,11 +3474,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
}
}
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
-
/*
* Install JUMP instructions after the data transfer routines to return
* control to the do_other_transfer routines.
@@ -3515,10 +3508,6 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
cmd_dataout += 2;
}
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
return tmp;
}
@@ -3693,11 +3682,6 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
i > 0 && ncrcurrent[0] != hostdata->NOP_insn;
--i, ncrcurrent += 2 /* JUMP instructions are two words */);
-
-flush_cache_all();
-cache_push(virt_to_bus(hostdata->script), flushsize);
-cache_clear(virt_to_bus(hostdata->script), flushsize);
-
if (i > 0) {
++hostdata->busy[tmp->target][tmp->lun];
cmd->next = hostdata->running_list;
@@ -3724,15 +3708,15 @@ cache_clear(virt_to_bus(hostdata->script), flushsize);
return;
}
- cache_push(virt_to_bus(cmd->dsa), hostdata->dsa_len);
- cache_push(virt_to_bus(ncrcurrent), sizeof(ncrcurrent));
-
/*
* If the NCR chip is in an idle state, start it running the scheduler
* immediately. Otherwise, signal the chip to jump to schedule as
* soon as it is idle.
*/
+ if (!MACH_IS_MVME16x)
+ flush_cache_all();
+
if (hostdata->idle) {
hostdata->idle = 0;
hostdata->state = STATE_RUNNING;
@@ -4133,7 +4117,7 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
done = 1;
for (host = first_host; host; host = host->next)
if (host->hostt == the_template
-#if defined(MVME166_INTFLY)
+#if defined(MVME16x_INTFLY)
/* We have two different interrupts pointing
* at this routine, so remove this check */
#else
@@ -4157,7 +4141,7 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
istat = NCR53c7x0_read8(hostdata->istat);
if ((hostdata->options & OPTION_INTFLY) &&
-#ifdef MVME166_INTFLY
+#ifdef MVME16x_INTFLY
/* the bit is set which indicates an on-the-fly int */
(*(volatile unsigned long *)0xfff40068 & 0x8000))
#else
@@ -4168,7 +4152,7 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
done = 0;
interrupted = 1;
-#ifdef MVME166_INTFLY
+#ifdef MVME16x_INTFLY
/* clear the INTFLY bit */
*(volatile unsigned long *)0xfff40074 = 0x8000;
#endif
@@ -4345,6 +4329,8 @@ restart:
#endif
hostdata->state = STATE_RUNNING;
+ if (!MACH_IS_MVME16x)
+ flush_cache_all();
NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
if (hostdata->options & OPTION_DEBUG_TRACE) {
#ifdef CYCLIC_TRACE
@@ -4669,7 +4655,9 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
where = "non-BMI dynamic DSA code";
action = ACTION_ABORT_PRINT;
}
- } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4)) {
+ } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4 + 2)) {
+ /* RGH 290697: Added +2 above, to compensate for the script
+ * instruction which disables the selection timer. */
/* Release ATN */
NCR53c7x0_write8 (SOCL_REG, 0);
switch (sbcl) {
@@ -4751,8 +4739,9 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
print_insn (host, hostdata->dsp, "", 1);
}
#endif
-
- cache_push(virt_to_bus(hostdata->script), flushsize);
+
+ if (!MACH_IS_MVME16x)
+ cache_push(virt_to_bus(hostdata->script), flushsize);
}
/*
@@ -4826,7 +4815,7 @@ intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
*/
if (retry == NEVER) {
- printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
+ printk(KERN_ALERT " mail ricahrd@sleepie.demon.co.uk\n");
FATAL (host);
}
}
@@ -5097,7 +5086,7 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
* FIXME : (void *) cast in virt_to_bus should be unnecessary, because
* it should take const void * as argument.
*/
-#ifndef CONFIG_MVME166
+#ifndef CONFIG_MVME16x
sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
(prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
insn[0], insn[1], bus_to_virt (insn[1]));
@@ -5110,7 +5099,7 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
#endif
tmp = buf + strlen(buf);
if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
-#ifndef CONFIG_MVME166
+#ifndef CONFIG_MVME16x
sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
bus_to_virt(insn[2]));
#else
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
index 56271a104..a2a53f107 100644
--- a/drivers/scsi/53c7xx.h
+++ b/drivers/scsi/53c7xx.h
@@ -893,7 +893,7 @@ extern inline void * phys_to_virt(unsigned long address)
* NCR53c710, this bit moved to CTEST8
*/
#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
-#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME166 */
+#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME16x */
#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
index 2fc9db2dd..5f26cde9f 100644
--- a/drivers/scsi/53c7xx.scr
+++ b/drivers/scsi/53c7xx.scr
@@ -315,7 +315,7 @@ dsa_code_check_reselect:
MOVE MEMORY 1, reselected_identify, addr_scratch
DMODE_MEMORY_TO_MEMORY
#ifdef BIG_ENDIAN
- ; BIG ENDIAN ON MVME166
+ ; BIG ENDIAN ON MVME16x
MOVE SCRATCH3 TO SFBR
#else
MOVE SCRATCH0 TO SFBR
@@ -1134,8 +1134,8 @@ command_complete_msgin:
JUMP command_failed, IF 0x02
#endif
#if (CHIP == 710)
-#if defined(MVME166_INTFLY)
-; For MVME166 (ie CHIP=710) we will force an INTFLY by triggering a software
+#if defined(MVME16x_INTFLY)
+; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
; interupt (SW7). We can use SCRATCH, as we are about to jump to
; schedule, which corrupts it anyway. Will probably remove this later,
; but want to check performance effects first.
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
new file mode 100644
index 000000000..81a3fab54
--- /dev/null
+++ b/drivers/scsi/NCR53C9x.c
@@ -0,0 +1,3733 @@
+/* NCR53C9x.c: Generic SCSI driver code for NCR53C9x chips.
+ *
+ * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Most DMA dependencies put in driver specific files by
+ * Jesper Skov (jskov@cygnus.co.uk)
+ */
+
+/* TODO:
+ *
+ * 1) Maybe disable parity checking in config register one for SCSI1
+ * targets. (Gilmore says parity error on the SBus can lock up
+ * old sun4c's)
+ * 2) Add support for DMA2 pipelining.
+ * 3) Add tagged queueing.
+ * 4) Maybe change use of "esp" to something more "NCR"'ish.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "NCR53C9x.h"
+
+#ifdef CONFIG_SCSI_SUNESP
+#include "sparc_esp.h"
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/machines.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#endif
+
+#if defined(CONFIG_BLZ1230_SCSI)||defined(CONFIG_BLZ2060_SCSI)||defined(CONFIG_CYBERSTORMII_SCSI)
+#define SYMBIOS_HACK
+#else
+#undef SYMBIOS_HACK
+#endif
+
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* Command phase enumeration. */
+enum {
+ not_issued = 0x00, /* Still in the issue_SC queue. */
+
+ /* Various forms of selecting a target. */
+#define in_slct_mask 0x10
+ in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */
+ in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */
+ in_slct_msg = 0x12, /* select, then send a message */
+ in_slct_tag = 0x13, /* select and send tagged queue msg */
+ in_slct_sneg = 0x14, /* select and acquire sync capabilities */
+
+ /* Any post selection activity. */
+#define in_phases_mask 0x20
+ in_datain = 0x20, /* Data is transferring from the bus */
+ in_dataout = 0x21, /* Data is transferring to the bus */
+ in_data_done = 0x22, /* Last DMA data operation done (maybe) */
+ in_msgin = 0x23, /* Eating message from target */
+ in_msgincont = 0x24, /* Eating more msg bytes from target */
+ in_msgindone = 0x25, /* Decide what to do with what we got */
+ in_msgout = 0x26, /* Sending message to target */
+ in_msgoutdone = 0x27, /* Done sending msg out */
+ in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */
+ in_cmdend = 0x29, /* Done sending slow cmd */
+ in_status = 0x2a, /* Was in status phase, finishing cmd */
+ in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */
+ in_the_dark = 0x2c, /* Don't know what bus phase we are in */
+
+ /* Special states, ie. not normal bus transitions... */
+#define in_spec_mask 0x80
+ in_abortone = 0x80, /* Aborting one command currently */
+ in_abortall = 0x81, /* Blowing away all commands we have */
+ in_resetdev = 0x82, /* SCSI target reset in progress */
+ in_resetbus = 0x83, /* SCSI bus reset in progress */
+ in_tgterror = 0x84, /* Target did something stupid */
+};
+
+struct proc_dir_entry proc_scsi_esp = {
+ PROC_SCSI_ESP, 3, "esp",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/* The master ring of all esp hosts we are managing in this driver. */
+struct NCR_ESP *espchain = 0;
+int nesps = 0, esps_in_use = 0, esps_running = 0;
+
+void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+
+/* Debugging routines */
+struct esp_cmdstrings {
+ unchar cmdchar;
+ char *text;
+} esp_cmd_strings[] = {
+ /* Miscellaneous */
+ { ESP_CMD_NULL, "ESP_NOP", },
+ { ESP_CMD_FLUSH, "FIFO_FLUSH", },
+ { ESP_CMD_RC, "RSTESP", },
+ { ESP_CMD_RS, "RSTSCSI", },
+ /* Disconnected State Group */
+ { ESP_CMD_RSEL, "RESLCTSEQ", },
+ { ESP_CMD_SEL, "SLCTNATN", },
+ { ESP_CMD_SELA, "SLCTATN", },
+ { ESP_CMD_SELAS, "SLCTATNSTOP", },
+ { ESP_CMD_ESEL, "ENSLCTRESEL", },
+ { ESP_CMD_DSEL, "DISSELRESEL", },
+ { ESP_CMD_SA3, "SLCTATN3", },
+ { ESP_CMD_RSEL3, "RESLCTSEQ", },
+ /* Target State Group */
+ { ESP_CMD_SMSG, "SNDMSG", },
+ { ESP_CMD_SSTAT, "SNDSTATUS", },
+ { ESP_CMD_SDATA, "SNDDATA", },
+ { ESP_CMD_DSEQ, "DISCSEQ", },
+ { ESP_CMD_TSEQ, "TERMSEQ", },
+ { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
+ { ESP_CMD_DCNCT, "DISC", },
+ { ESP_CMD_RMSG, "RCVMSG", },
+ { ESP_CMD_RCMD, "RCVCMD", },
+ { ESP_CMD_RDATA, "RCVDATA", },
+ { ESP_CMD_RCSEQ, "RCVCMDSEQ", },
+ /* Initiator State Group */
+ { ESP_CMD_TI, "TRANSINFO", },
+ { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
+ { ESP_CMD_MOK, "MSGACCEPTED", },
+ { ESP_CMD_TPAD, "TPAD", },
+ { ESP_CMD_SATN, "SATN", },
+ { ESP_CMD_RATN, "RATN", },
+};
+#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
+
+/* Print textual representation of an ESP command */
+static inline void esp_print_cmd(unchar espcmd)
+{
+ unchar dma_bit = espcmd & ESP_CMD_DMA;
+ int i;
+
+ espcmd &= ~dma_bit;
+ for(i=0; i<NUM_ESP_COMMANDS; i++)
+ if(esp_cmd_strings[i].cmdchar == espcmd)
+ break;
+ if(i==NUM_ESP_COMMANDS)
+ printk("ESP_Unknown");
+ else
+ printk("%s%s", esp_cmd_strings[i].text,
+ ((dma_bit) ? "+DMA" : ""));
+}
+
+/* Print the status register's value */
+static inline void esp_print_statreg(unchar statreg)
+{
+ unchar phase;
+
+ printk("STATUS<");
+ phase = statreg & ESP_STAT_PMASK;
+ printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
+ (phase == ESP_DIP ? "DATA-IN" :
+ (phase == ESP_CMDP ? "COMMAND" :
+ (phase == ESP_STATP ? "STATUS" :
+ (phase == ESP_MOP ? "MSG-OUT" :
+ (phase == ESP_MIP ? "MSG_IN" :
+ "unknown")))))));
+ if(statreg & ESP_STAT_TDONE)
+ printk("TRANS_DONE,");
+ if(statreg & ESP_STAT_TCNT)
+ printk("TCOUNT_ZERO,");
+ if(statreg & ESP_STAT_PERR)
+ printk("P_ERROR,");
+ if(statreg & ESP_STAT_SPAM)
+ printk("SPAM,");
+ if(statreg & ESP_STAT_INTR)
+ printk("IRQ,");
+ printk(">");
+}
+
+/* Print the interrupt register's value */
+static inline void esp_print_ireg(unchar intreg)
+{
+ printk("INTREG< ");
+ if(intreg & ESP_INTR_S)
+ printk("SLCT_NATN ");
+ if(intreg & ESP_INTR_SATN)
+ printk("SLCT_ATN ");
+ if(intreg & ESP_INTR_RSEL)
+ printk("RSLCT ");
+ if(intreg & ESP_INTR_FDONE)
+ printk("FDONE ");
+ if(intreg & ESP_INTR_BSERV)
+ printk("BSERV ");
+ if(intreg & ESP_INTR_DC)
+ printk("DISCNCT ");
+ if(intreg & ESP_INTR_IC)
+ printk("ILL_CMD ");
+ if(intreg & ESP_INTR_SR)
+ printk("SCSI_BUS_RESET ");
+ printk(">");
+}
+
+/* Print the sequence step registers contents */
+static inline void esp_print_seqreg(unchar stepreg)
+{
+ stepreg &= ESP_STEP_VBITS;
+ printk("STEP<%s>",
+ (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
+ (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
+ (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
+ (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
+ (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
+ "UNKNOWN"))))));
+}
+
+#if defined(DEBUG_STATE_MACHINE) || defined(DEBUG_ESP)
+static char *phase_string(int phase)
+{
+ switch(phase) {
+ case not_issued:
+ return "UNISSUED";
+ case in_slct_norm:
+ return "SLCTNORM";
+ case in_slct_stop:
+ return "SLCTSTOP";
+ case in_slct_msg:
+ return "SLCTMSG";
+ case in_slct_tag:
+ return "SLCTTAG";
+ case in_slct_sneg:
+ return "SLCTSNEG";
+ case in_datain:
+ return "DATAIN";
+ case in_dataout:
+ return "DATAOUT";
+ case in_data_done:
+ return "DATADONE";
+ case in_msgin:
+ return "MSGIN";
+ case in_msgincont:
+ return "MSGINCONT";
+ case in_msgindone:
+ return "MSGINDONE";
+ case in_msgout:
+ return "MSGOUT";
+ case in_msgoutdone:
+ return "MSGOUTDONE";
+ case in_cmdbegin:
+ return "CMDBEGIN";
+ case in_cmdend:
+ return "CMDEND";
+ case in_status:
+ return "STATUS";
+ case in_freeing:
+ return "FREEING";
+ case in_the_dark:
+ return "CLUELESS";
+ case in_abortone:
+ return "ABORTONE";
+ case in_abortall:
+ return "ABORTALL";
+ case in_resetdev:
+ return "RESETDEV";
+ case in_resetbus:
+ return "RESETBUS";
+ case in_tgterror:
+ return "TGTERROR";
+ default:
+ return "UNKNOWN";
+ };
+}
+#endif
+
+static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
+{
+#ifdef DEBUG_STATE_MACHINE
+ ESPLOG(("<%s>", phase_string(newphase)));
+#endif
+ s->SCp.sent_command = s->SCp.phase;
+ s->SCp.phase = newphase;
+}
+
+extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ unchar cmd)
+{
+#ifdef DEBUG_ESP_CMDS
+ esp->espcmdlog[esp->espcmdent] = cmd;
+ esp->espcmdent = (esp->espcmdent + 1) & 31;
+#endif
+ eregs->esp_cmd = cmd;
+}
+
+/* How we use the various Linux SCSI data structures for operation.
+ *
+ * struct scsi_cmnd:
+ *
+ * We keep track of the syncronous capabilities of a target
+ * in the device member, using sync_min_period and
+ * sync_max_offset. These are the values we directly write
+ * into the ESP registers while running a command. If offset
+ * is zero the ESP will use asynchronous transfers.
+ * If the borken flag is set we assume we shouldn't even bother
+ * trying to negotiate for synchronous transfer as this target
+ * is really stupid. If we notice the target is dropping the
+ * bus, and we have been allowing it to disconnect, we clear
+ * the disconnect flag.
+ */
+
+
+/* Manipulation of the ESP command queues. Thanks to the aha152x driver
+ * and its author, Juergen E. Fischer, for the methods used here.
+ * Note that these are per-ESP queues, not global queues like
+ * the aha152x driver uses.
+ */
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+ Scsi_Cmnd *end;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ new_SC->host_scribble = (unsigned char *) NULL;
+ if(!*SC)
+ *SC = new_SC;
+ else {
+ for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble)
+ ;
+ end->host_scribble = (unsigned char *) new_SC;
+ }
+ restore_flags(flags);
+}
+
+static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ new_SC->host_scribble = (unsigned char *) *SC;
+ *SC = new_SC;
+ restore_flags(flags);
+}
+
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
+{
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ ptr = *SC;
+ if(ptr)
+ *SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+ restore_flags(flags);
+ return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
+{
+ Scsi_Cmnd *ptr, *prev;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ for(ptr = *SC, prev = NULL;
+ ptr && ((ptr->target != target) || (ptr->lun != lun));
+ prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ ;
+ if(ptr) {
+ if(prev)
+ prev->host_scribble=ptr->host_scribble;
+ else
+ *SC=(Scsi_Cmnd *)ptr->host_scribble;
+ }
+ restore_flags(flags);
+ return ptr;
+}
+
+/* Resetting various pieces of the ESP scsi driver chipset */
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int family_code, version, i;
+ volatile int trash;
+
+ /* Now reset the ESP chip */
+ esp_cmd(esp, eregs, ESP_CMD_RC);
+ esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+ esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+
+ /* Reload the configuration registers */
+ eregs->esp_cfact = esp->cfact;
+ eregs->esp_stp = 0;
+ eregs->esp_soff = 0;
+ eregs->esp_timeo = esp->neg_defp;
+
+ /* This is the only point at which it is reliable to read
+ * the ID-code for a fast ESP chip variant.
+ */
+ esp->max_period = ((35 * esp->ccycle) / 1000);
+ if(esp->erev == fast) {
+ version = eregs->esp_uid;
+ family_code = (version & 0xf8) >> 3;
+#ifdef SYMBIOS_HACK
+ if (version == 0 && family_code == 0)
+ {
+ printk ("Detected SymBIOS chip with no family code.\n");
+ version = 3;
+ family_code = 2;
+ }
+#endif
+ if(family_code == 0x02)
+ esp->erev = fas236;
+ else if(family_code == 0x0a)
+ esp->erev = fashme; /* Version is usually '5'. */
+ else
+ esp->erev = fas100a;
+ printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+ esp->esp_id,
+ (esp->erev == fas236) ? "fas236" :
+ ((esp->erev == fas100a) ? "fas100a" :
+ "fasHME"), family_code, (version & 7));
+
+ esp->min_period = ((4 * esp->ccycle) / 1000);
+ } else {
+ esp->min_period = ((5 * esp->ccycle) / 1000);
+ }
+ esp->max_period = (esp->max_period + 3)>>2;
+ esp->min_period = (esp->min_period + 3)>>2;
+
+ eregs->esp_cfg1 = esp->config1;
+ switch(esp->erev) {
+ case esp100:
+ /* nothing to do */
+ break;
+ case esp100a:
+ eregs->esp_cfg2 = esp->config2;
+ break;
+ case esp236:
+ /* Slow 236 */
+ eregs->esp_cfg2 = esp->config2;
+ eregs->esp_cfg3 = esp->config3[0];
+ break;
+ case fashme:
+ esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+ /* fallthrough... */
+ case fas236:
+ /* Fast 236 or HME */
+ eregs->esp_cfg2 = esp->config2;
+ for(i=0; i<8; i++) {
+ if(esp->erev == fashme)
+ esp->config3[i] |=
+ (ESP_CONFIG3_FCLOCK | ESP_CONFIG3_BIGID | ESP_CONFIG3_OBPUSH);
+ else
+ esp->config3[i] |= ESP_CONFIG3_FCLK;
+ }
+ eregs->esp_cfg3 = esp->config3[0];
+ if(esp->erev == fashme) {
+ esp->radelay = 80;
+ } else {
+ if(esp->diff)
+ esp->radelay = 0;
+ else
+ esp->radelay = 96;
+ }
+ break;
+ case fas100a:
+ /* Fast 100a */
+ eregs->esp_cfg2 = esp->config2;
+ for(i=0; i<8; i++)
+ esp->config3[i] |= ESP_CONFIG3_FCLOCK;
+ eregs->esp_cfg3 = esp->config3[0];
+ esp->radelay = 32;
+ break;
+ default:
+ panic("esp: what could it be... I wonder...");
+ break;
+ };
+
+ /* Eat any bitrot in the chip */
+ trash = eregs->esp_intrpt;
+ udelay(100);
+}
+
+/* This places the ESP into a known state at boot time. */
+inline void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ volatile unchar trash;
+
+ /* Reset the DMA */
+ if(esp->dma_reset)
+ esp->dma_reset(esp);
+
+ /* Reset the ESP */
+ esp_reset_esp(esp, eregs);
+
+ /* Reset the SCSI bus, but tell ESP not to generate an irq */
+ eregs->esp_cfg1 |= ESP_CONFIG1_SRRDISAB;
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+ udelay(400);
+ eregs->esp_cfg1 = esp->config1;
+
+ /* Eat any bitrot in the chip and we are done... */
+ trash = eregs->esp_intrpt;
+}
+
+/* Allocate structure and insert basic data such as SCSI chip frequency
+ * data and a pointer to the device
+ */
+struct NCR_ESP* esp_allocate(Scsi_Host_Template *tpnt, void *esp_dev)
+{
+ struct NCR_ESP *esp, *elink;
+ struct Scsi_Host *esp_host;
+
+ esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+ if(!esp_host)
+ panic("Cannot register ESP SCSI host");
+ esp = (struct NCR_ESP *) esp_host->hostdata;
+ if(!esp)
+ panic("No esp in hostdata");
+ esp->ehost = esp_host;
+ esp->edev = esp_dev;
+ esp->esp_id = nesps++;
+
+ /* Put into the chain of esp chips detected */
+ if(espchain) {
+ elink = espchain;
+ while(elink->next) elink = elink->next;
+ elink->next = esp;
+ } else {
+ espchain = esp;
+ }
+ esp->next = 0;
+
+ return esp;
+}
+
+/* Complete initialization of ESP structure and device
+ * Caller must have initialized appropriate parts of the ESP structure
+ * between the call to esp_allocate and this function.
+ */
+void esp_initialize(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs = esp->eregs;
+ unsigned int fmhz;
+ unchar ccf;
+ int i;
+
+ /* Check out the clock properties of the chip. */
+
+ /* This is getting messy but it has to be done
+ * correctly or else you get weird behavior all
+ * over the place. We are trying to basically
+ * figure out three pieces of information.
+ *
+ * a) Clock Conversion Factor
+ *
+ * This is a representation of the input
+ * crystal clock frequency going into the
+ * ESP on this machine. Any operation whose
+ * timing is longer than 400ns depends on this
+ * value being correct. For example, you'll
+ * get blips for arbitration/selection during
+ * high load or with multiple targets if this
+ * is not set correctly.
+ *
+ * b) Selection Time-Out
+ *
+ * The ESP isn't very bright and will arbitrate
+ * for the bus and try to select a target
+ * forever if you let it. This value tells
+ * the ESP when it has taken too long to
+ * negotiate and that it should interrupt
+ * the CPU so we can see what happened.
+ * The value is computed as follows (from
+ * NCR/Symbios chip docs).
+ *
+ * (Time Out Period) * (Input Clock)
+ * STO = ----------------------------------
+ * (8192) * (Clock Conversion Factor)
+ *
+ * You usually want the time out period to be
+ * around 250ms, I think we'll set it a little
+ * bit higher to account for fully loaded SCSI
+ * bus's and slow devices that don't respond so
+ * quickly to selection attempts. (yeah, I know
+ * this is out of spec. but there is a lot of
+ * buggy pieces of firmware out there so bite me)
+ *
+ * c) Imperical constants for synchronous offset
+ * and transfer period register values
+ *
+ * This entails the smallest and largest sync
+ * period we could ever handle on this ESP.
+ */
+
+ fmhz = esp->cfreq;
+
+ if(fmhz <= (5000000))
+ ccf = 0;
+ else
+ ccf = (((5000000 - 1) + (fmhz))/(5000000));
+ if(!ccf || ccf > 8) {
+ /* If we can't find anything reasonable,
+ * just assume 20MHZ. This is the clock
+ * frequency of the older sun4c's where I've
+ * been unable to find the clock-frequency
+ * PROM property. All other machines provide
+ * useful values it seems.
+ */
+ ccf = ESP_CCF_F4;
+ fmhz = (20000000);
+ }
+ if(ccf==(ESP_CCF_F7+1))
+ esp->cfact = ESP_CCF_F0;
+ else if(ccf == ESP_CCF_NEVER)
+ esp->cfact = ESP_CCF_F2;
+ else
+ esp->cfact = ccf;
+ esp->cfreq = fmhz;
+ esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+ esp->ctick = ESP_TICK(ccf, esp->ccycle);
+ esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+ esp->sync_defp = SYNC_DEFP_SLOW;
+
+
+ /* Fill in ehost data */
+ esp->ehost->base = (unsigned char *) eregs;
+ esp->ehost->this_id = esp->scsi_id;
+ esp->ehost->irq = esp->irq;
+
+ /* SCSI id mask */
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+
+ /* Probe the revision of this esp */
+ esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+ esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ eregs->esp_cfg2 = esp->config2;
+#ifndef SYMBIOS_HACK
+ if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) !=
+ (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+ printk("NCR53C90(esp100) detected\n");
+ esp->erev = esp100;
+ } else {
+#endif
+ eregs->esp_cfg2 = esp->config2 = 0;
+ eregs->esp_cfg3 = 0;
+ eregs->esp_cfg3 = esp->config3[0] = 5;
+#ifndef SYMBIOS_HACK
+ if(eregs->esp_cfg3 != 5) {
+ printk("NCR53C90A(esp100a) detected\n");
+ esp->erev = esp100a;
+ } else {
+#else
+ {
+#endif
+ int target;
+
+ for(target=0; target<8; target++)
+ esp->config3[target] = 0;
+ eregs->esp_cfg3 = 0;
+#ifndef SYMBIOS_HACK
+ if(ccf > ESP_CCF_F5) {
+#endif
+ printk("NCR53C9XF(espfast) detected\n");
+ esp->erev = fast;
+ eregs->esp_cfg2 = esp->config2 = 0;
+ esp->sync_defp = SYNC_DEFP_FAST;
+#ifndef SYMBIOS_HACK
+ } else {
+ printk("NCR53C9x(esp236) detected\n");
+ esp->erev = esp236;
+ eregs->esp_cfg2 = esp->config2 = 0;
+ }
+ }
+#endif
+ }
+
+ /* Initialize the command queues */
+ esp->current_SC = 0;
+ esp->disconnected_SC = 0;
+ esp->issue_SC = 0;
+
+ /* Clear the state machines. */
+ esp->targets_present = 0;
+ esp->resetting_bus = 0;
+ esp->snip = 0;
+ esp->targets_present = 0;
+ for(i = 0; i < 32; i++)
+ esp->espcmdlog[i] = 0;
+ esp->espcmdent = 0;
+ for(i = 0; i < 16; i++) {
+ esp->cur_msgout[i] = 0;
+ esp->cur_msgin[i] = 0;
+ }
+ esp->prevmsgout = esp->prevmsgin = 0;
+ esp->msgout_len = esp->msgin_len = 0;
+
+ /* Reset the thing before we try anything... */
+ esp_bootup_reset(esp, eregs);
+
+ esps_in_use++;
+
+ printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ",
+ esp->scsi_id, (esp->cfreq / 1000000),
+ esp->ccf, (int) esp->neg_defp);
+}
+
+/* The info function will return whatever useful
+ * information the developer sees fit. If not provided, then
+ * the name field will be used instead.
+ */
+const char *esp_info(struct Scsi_Host *host)
+{
+ struct NCR_ESP *esp;
+
+ esp = (struct NCR_ESP *) host->hostdata;
+ switch(esp->erev) {
+ case esp100:
+ return "Sparc ESP100 (NCR53C90)";
+ case esp100a:
+ return "Sparc ESP100A (NCR53C90A)";
+ case esp236:
+ return "Sparc ESP236";
+ case fas236:
+ return "Sparc ESP236-FAST";
+ case fashme:
+ return "Sparc ESP366-HME";
+ case fas100a:
+ return "Sparc ESP100A-FAST";
+ default:
+ panic("Bogon ESP revision");
+ };
+}
+
+/* From Wolfgang Stanglmeier's NCR scsi driver. */
+struct info_str
+{
+ char *buffer;
+ int length;
+ int offset;
+ int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+ if (info->pos + len > info->length)
+ len = info->length - info->pos;
+
+ if (info->pos + len < info->offset) {
+ info->pos += len;
+ return;
+ }
+ if (info->pos < info->offset) {
+ data += (info->offset - info->pos);
+ len -= (info->offset - info->pos);
+ }
+
+ if (len > 0) {
+ memcpy(info->buffer + info->pos, data, len);
+ info->pos += len;
+ }
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+ va_list args;
+ char buf[81];
+ int len;
+
+ va_start(args, fmt);
+ len = vsprintf(buf, fmt, args);
+ va_end(args);
+
+ copy_mem_info(info, buf, len);
+ return len;
+}
+
+static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
+{
+ struct info_str info;
+ int i;
+
+ info.buffer = ptr;
+ info.length = len;
+ info.offset = offset;
+ info.pos = 0;
+
+ copy_info(&info, "Sparc ESP Host Adapter:\n");
+ copy_info(&info, "\tPROM node\t\t%08lx\n", (unsigned long) esp->prom_node);
+ copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
+ copy_info(&info, "\tESP Model\t\t");
+ switch(esp->erev) {
+ case esp100:
+ copy_info(&info, "ESP100\n");
+ break;
+ case esp100a:
+ copy_info(&info, "ESP100A\n");
+ break;
+ case esp236:
+ copy_info(&info, "ESP236\n");
+ break;
+ case fas236:
+ copy_info(&info, "FAS236\n");
+ break;
+ case fas100a:
+ copy_info(&info, "FAS100A\n");
+ break;
+ case fast:
+ copy_info(&info, "FAST\n");
+ break;
+ case fashme:
+ copy_info(&info, "Happy Meal FAS\n");
+ break;
+ case espunknown:
+ default:
+ copy_info(&info, "Unknown!\n");
+ break;
+ };
+#ifdef CONFIG_SCSI_SUNESP
+ copy_info(&info, "\tDMA Revision\t\t");
+ switch(((struct Linux_SBus_DMA*) (esp->dma))->revision) {
+ case dvmarev0:
+ copy_info(&info, "Rev 0\n");
+ break;
+ case dvmaesc1:
+ copy_info(&info, "ESC Rev 1\n");
+ break;
+ case dvmarev1:
+ copy_info(&info, "Rev 1\n");
+ break;
+ case dvmarev2:
+ copy_info(&info, "Rev 2\n");
+ break;
+ case dvmarev3:
+ copy_info(&info, "Rev 3\n");
+ break;
+ case dvmarevplus:
+ copy_info(&info, "Rev 1+\n");
+ break;
+ case dvmahme:
+ copy_info(&info, "Rev HME/FAS\n");
+ break;
+ default:
+ copy_info(&info, "Unknown!\n");
+ break;
+ };
+#endif
+ copy_info(&info, "\tLive Targets\t\t[ ");
+ for(i = 0; i < 15; i++) {
+ if(esp->targets_present & (1 << i))
+ copy_info(&info, "%d ", i);
+ }
+ copy_info(&info, "]\n\n");
+
+ /* Now describe the state of each existing target. */
+ copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
+ for(i = 0; i < 15; i++) {
+ if(esp->targets_present & (1 << i)) {
+ Scsi_Device *SDptr = esp->ehost->host_queue;
+
+ while((SDptr->host != esp->ehost) &&
+ (SDptr->id != i) &&
+ (SDptr->next))
+ SDptr = SDptr->next;
+
+ copy_info(&info, "%d\t\t", i);
+ copy_info(&info, "%08lx\t", esp->config3[i]);
+ copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset,
+ SDptr->sync_min_period);
+ copy_info(&info, "%s\t\t", SDptr->disconnect ? "yes" : "no");
+ copy_info(&info, "%s\n",
+ (esp->config3[i] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
+ }
+ }
+
+ return info.pos > info.offset? info.pos - info.offset : 0;
+}
+
+/* ESP proc filesystem code. */
+int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
+{
+ struct NCR_ESP *esp;
+
+ if(inout)
+ return -EINVAL; /* not yet */
+
+ for_each_esp(esp) {
+ if(esp->ehost->host_no == hostno)
+ break;
+ }
+ if(!esp)
+ return -EINVAL;
+
+ if(start)
+ *start = buffer;
+
+ return esp_host_info(esp, buffer, offset, length);
+}
+
+/* Some rules:
+ *
+ * 1) Never ever panic while something is live on the bus.
+ * If there is to be any chance of syncing the disks this
+ * rule is to be obeyed.
+ *
+ * 2) Any target that causes a foul condition will no longer
+ * have synchronous transfers done to it, no questions
+ * asked.
+ *
+ * 3) Keep register accesses to a minimum. Think about some
+ * day when we have Xbus machines this is running on and
+ * the ESP chip is on the other end of the machine on a
+ * different board from the cpu where this is running.
+ */
+
+/* Fire off a command. We assume the bus is free and that the only
+ * case where we could see an interrupt is where we have disconnected
+ * commands active and they are trying to reselect us.
+ */
+static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ switch(sp->cmd_len) {
+ case 6:
+ case 10:
+ case 12:
+ esp->esp_slowcmd = 0;
+ break;
+
+ default:
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdleft = sp->cmd_len;
+ esp->esp_scmdp = &sp->cmnd[0];
+ break;
+ };
+}
+
+static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset)
+{
+ esp->cur_msgout[0] = EXTENDED_MESSAGE;
+ esp->cur_msgout[1] = 3;
+ esp->cur_msgout[2] = EXTENDED_SDTR;
+ esp->cur_msgout[3] = period;
+ esp->cur_msgout[4] = offset;
+ esp->msgout_len = 5;
+}
+
+/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
+static inline void build_wide_nego_msg(struct NCR_ESP *esp, int size)
+{
+ esp->cur_msgout[0] = EXTENDED_MESSAGE;
+ esp->cur_msgout[1] = 2;
+ esp->cur_msgout[2] = EXTENDED_WDTR;
+ switch(size) {
+ case 32:
+ esp->cur_msgout[3] = 2;
+ break;
+ case 16:
+ esp->cur_msgout[3] = 1;
+ break;
+ case 8:
+ default:
+ esp->cur_msgout[3] = 0;
+ break;
+ };
+
+ esp->msgout_len = 4;
+}
+
+static inline void esp_exec_cmd(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs = esp->eregs;
+ Scsi_Cmnd *SCptr;
+ Scsi_Device *SDptr;
+ volatile unchar *cmdp = esp->esp_command;
+ unsigned char the_esp_command;
+ int lun, target;
+ int i;
+
+ /* Hold off if we've been reselected or an IRQ is showing... */
+ if(esp->disconnected_SC || esp->dma_irq_p(esp))
+ return;
+
+ /* Grab first member of the issue queue. */
+ SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
+
+ /* Safe to panic here because current_SC is null. */
+ if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL");
+
+ SDptr = SCptr->device;
+ lun = SCptr->lun;
+ target = SCptr->target;
+
+ esp->snip = 0;
+ esp->msgout_len = 0;
+
+ /* Send it out whole, or piece by piece? The ESP
+ * only knows how to automatically send out 6, 10,
+ * and 12 byte commands. I used to think that the
+ * Linux SCSI code would never throw anything other
+ * than that to us, but then again there is the
+ * SCSI generic driver which can send us anything.
+ */
+ esp_check_cmd(esp, SCptr);
+
+ /* If arbitration/selection is successful, the ESP will leave
+ * ATN asserted, causing the target to go into message out
+ * phase. The ESP will feed the target the identify and then
+ * the target can only legally go to one of command,
+ * datain/out, status, or message in phase, or stay in message
+ * out phase (should we be trying to send a sync negotiation
+ * message after the identify). It is not allowed to drop
+ * BSY, but some buggy targets do and we check for this
+ * condition in the selection complete code. Most of the time
+ * we'll make the command bytes available to the ESP and it
+ * will not interrupt us until it finishes command phase, we
+ * cannot do this for command sizes the ESP does not
+ * understand and in this case we'll get interrupted right
+ * when the target goes into command phase.
+ *
+ * It is absolutely _illegal_ in the presence of SCSI-2 devices
+ * to use the ESP select w/o ATN command. When SCSI-2 devices are
+ * present on the bus we _must_ always go straight to message out
+ * phase with an identify message for the target. Being that
+ * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
+ * selections should not confuse SCSI-1 we hope.
+ */
+
+ if(SDptr->sync) {
+ /* this targets sync is known */
+#ifdef CONFIG_SCSI_SUNESP
+do_sync_known:
+#endif
+ if(SDptr->disconnect)
+ *cmdp++ = IDENTIFY(1, lun);
+ else
+ *cmdp++ = IDENTIFY(0, lun);
+
+ if(esp->esp_slowcmd) {
+ the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_stop);
+ } else {
+ the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_norm);
+ }
+ } else if(!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) {
+ /* After the bootup SCSI code sends both the
+ * TEST_UNIT_READY and INQUIRY commands we want
+ * to at least attempt allowing the device to
+ * disconnect.
+ */
+ ESPMISC(("esp: Selecting device for first time. target=%d "
+ "lun=%d\n", target, SCptr->lun));
+ if(!SDptr->borken && !SDptr->disconnect)
+ SDptr->disconnect = 1;
+
+ *cmdp++ = IDENTIFY(0, lun);
+ esp->prevmsgout = NOP;
+ esp_advance_phase(SCptr, in_slct_norm);
+ the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+
+ /* Take no chances... */
+ SDptr->sync_max_offset = 0;
+ SDptr->sync_min_period = 0;
+ } else {
+ int toshiba_cdrom_hwbug_wkaround = 0;
+
+#ifdef CONFIG_SCSI_SUNESP
+ /* Never allow disconnects or synchronous transfers on
+ * SparcStation1 and SparcStation1+. Allowing those
+ * to be enabled seems to lockup the machine completely.
+ */
+ if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ /* But we are nice and allow tapes to disconnect. */
+ if(SDptr->type == TYPE_TAPE)
+ SDptr->disconnect = 1;
+ else
+ SDptr->disconnect = 0;
+ SDptr->sync_max_offset = 0;
+ SDptr->sync_min_period = 0;
+ SDptr->sync = 1;
+ esp->snip = 0;
+ goto do_sync_known;
+ }
+#endif
+ /* We've talked to this guy before,
+ * but never negotiated.. lets try,
+ * need to attempt WIDE first, before
+ * sync nego, as per SCSI 2 standard.
+ */
+ if(esp->erev == fashme && !SDptr->wide) {
+ if(!SDptr->borken &&
+ (SDptr->type != TYPE_ROM ||
+ strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+ build_wide_nego_msg(esp, 16);
+ esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
+ SDptr->wide = 1;
+ esp->wnip = 1;
+ goto after_nego_msg_built;
+ } else {
+ SDptr->wide = 1;
+ /* Fall through and try sync. */
+ }
+ }
+
+ if(!SDptr->borken) {
+ if((SDptr->type == TYPE_ROM) &&
+ (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+ /* Nice try sucker... */
+ printk(KERN_INFO "esp%d: Disabling sync for buggy "
+ "Toshiba CDROM.\n", esp->esp_id);
+ toshiba_cdrom_hwbug_wkaround = 1;
+ build_sync_nego_msg(esp, 0, 0);
+ } else {
+ build_sync_nego_msg(esp, esp->sync_defp, 15);
+ }
+ } else {
+ build_sync_nego_msg(esp, 0, 0);
+ }
+ SDptr->sync = 1;
+ esp->snip = 1;
+
+after_nego_msg_built:
+ /* A fix for broken SCSI1 targets, when they disconnect
+ * they lock up the bus and confuse ESP. So disallow
+ * disconnects for SCSI1 targets for now until we
+ * find a better fix.
+ *
+ * Addendum: This is funny, I figured out what was going
+ * on. The blotzed SCSI1 target would disconnect,
+ * one of the other SCSI2 targets or both would be
+ * disconnected as well. The SCSI1 target would
+ * stay disconnected long enough that we start
+ * up a command on one of the SCSI2 targets. As
+ * the ESP is arbitrating for the bus the SCSI1
+ * target begins to arbitrate as well to reselect
+ * the ESP. The SCSI1 target refuses to drop it's
+ * ID bit on the data bus even though the ESP is
+ * at ID 7 and is the obvious winner for any
+ * arbitration. The ESP is a poor sport and refuses
+ * to lose arbitration, it will continue indefinately
+ * trying to arbitrate for the bus and can only be
+ * stopped via a chip reset or SCSI bus reset.
+ * Therefore _no_ disconnects for SCSI1 targets
+ * thank you very much. ;-)
+ */
+ if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+#if 1 /* Until I find out why HME barfs with disconnects enabled... */
+ toshiba_cdrom_hwbug_wkaround || SDptr->borken || esp->erev == fashme) {
+#else
+ toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
+#endif
+ printk(KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+ "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun);
+ SDptr->disconnect = 0;
+ *cmdp++ = IDENTIFY(0, lun);
+ } else {
+ *cmdp++ = IDENTIFY(1, lun);
+ }
+
+ /* ESP fifo is only so big...
+ * Make this look like a slow command.
+ */
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdleft = SCptr->cmd_len;
+ esp->esp_scmdp = &SCptr->cmnd[0];
+
+ the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+ esp_advance_phase(SCptr, in_slct_msg);
+ }
+
+ if(!esp->esp_slowcmd)
+ for(i = 0; i < SCptr->cmd_len; i++)
+ *cmdp++ = SCptr->cmnd[i];
+
+ /* HME sucks... */
+ if(esp->erev == fashme)
+ eregs->esp_busid = (target & 0xf) |
+ (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+ else
+ eregs->esp_busid = (target & 7);
+ eregs->esp_soff = SDptr->sync_max_offset;
+ eregs->esp_stp = SDptr->sync_min_period;
+ if(esp->erev > esp100a)
+ eregs->esp_cfg3 = esp->config3[target];
+
+ i = (cmdp - esp->esp_command);
+
+ /* Set up the DMA and ESP counters */
+ if(esp->do_pio_cmds){
+ int j = 0;
+
+ for(;j<i;j++)
+ eregs->esp_fdata = esp->esp_command[j];
+ the_esp_command &= ~ESP_CMD_DMA;
+
+ /* Tell ESP to "go". */
+ esp_cmd(esp, eregs, the_esp_command);
+ } else {
+ if(esp->erev == fashme) {
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */
+
+ /* Set up the HME counters */
+ eregs->esp_tclow = i;
+ eregs->esp_tcmed = 0;
+ eregs->fas_rlo = 0;
+ eregs->fas_rhi = 0;
+ esp_cmd(esp, eregs, the_esp_command);
+ esp->dma_init_write(esp, esp->esp_command_dvma, 16);
+ } else {
+ /* Set up the ESP counters */
+ eregs->esp_tclow = i;
+ eregs->esp_tcmed = 0;
+ esp->dma_init_write(esp, esp->esp_command_dvma, i);
+
+ /* Tell ESP to "go". */
+ esp_cmd(esp, eregs, the_esp_command);
+ }
+ }
+}
+
+/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
+int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ struct NCR_ESP *esp;
+ unsigned long flags;
+
+ /* Set up func ptr and initial driver cmd-phase. */
+ SCpnt->scsi_done = done;
+ SCpnt->SCp.phase = not_issued;
+
+ esp = (struct NCR_ESP *) SCpnt->host->hostdata;
+
+ if(esp->dma_led_on)
+ esp->dma_led_on(esp);
+
+ /* We use the scratch area. */
+ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
+ ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
+ if(!SCpnt->use_sg) {
+ ESPQUEUE(("!use_sg\n"));
+ SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.buffer =
+ (struct scatterlist *) SCpnt->request_buffer;
+ SCpnt->SCp.buffers_residual = 0;
+#ifdef CONFIG_SCSI_SUNESP
+ /* Sneaky. */
+ SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
+ SCpnt->SCp.this_residual,
+ ((struct linux_sbus_device*) (esp->edev))->my_bus);
+ /* XXX The casts are extremely gross, but with 64-bit kernel
+ * XXX and 32-bit SBUS what am I to do? -DaveM
+ */
+ SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
+#else
+ SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
+ (char *) VTOP((unsigned long) SCpnt->request_buffer);
+#endif
+
+ } else {
+ ESPQUEUE(("use_sg "));
+#ifdef DEBUG_ESP_SG
+ printk("esp%d: sglist at %p with %d buffers\n",
+ esp->esp_id, SCpnt->buffer, SCpnt->use_sg);
+#endif
+ SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
+ SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+ SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+#ifdef CONFIG_SCSI_SUNESP
+ mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
+ SCpnt->SCp.buffers_residual,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+ /* XXX Again these casts are sick... -DaveM */
+ SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
+#else
+ SCpnt->SCp.ptr =
+ (char *) VTOP((unsigned long) SCpnt->SCp.buffer->address);
+#endif
+ }
+ SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Message = 0xff;
+ SCpnt->SCp.sent_command = 0;
+
+ /* Place into our queue. */
+ if(SCpnt->cmnd[0] == REQUEST_SENSE) {
+ ESPQUEUE(("RQSENSE\n"));
+ prepend_SC(&esp->issue_SC, SCpnt);
+ } else {
+ ESPQUEUE(("\n"));
+ append_SC(&esp->issue_SC, SCpnt);
+ }
+
+ save_and_cli(flags);
+
+ /* Run it now if we can. */
+ if(!esp->current_SC && !esp->resetting_bus)
+ esp_exec_cmd(esp);
+
+ restore_flags(flags);
+ return 0;
+}
+
+/* Only queuing supported in this ESP driver. */
+int esp_command(Scsi_Cmnd *SCpnt)
+{
+#ifdef DEBUG_ESP
+ struct NCR_ESP *esp = (struct NCR_ESP *) SCpnt->host->hostdata;
+#endif
+
+ ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id));
+ return -1;
+}
+
+/* Dump driver state. */
+static inline void esp_dump_cmd(Scsi_Cmnd *SCptr)
+{
+ ESPLOG(("[tgt<%02x> lun<%02x> "
+ "pphase<%s> cphase<%s>]",
+ SCptr->target, SCptr->lun,
+ phase_string(SCptr->SCp.sent_command),
+ phase_string(SCptr->SCp.phase)));
+}
+
+static inline void esp_dump_state(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+#ifdef DEBUG_ESP_CMDS
+ int i;
+#endif
+
+ ESPLOG(("esp%d: dumping state\n", esp->esp_id));
+
+ /* Print DMA status */
+ esp->dma_dump_state(esp);
+
+ ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+ esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
+ ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+ esp->esp_id, eregs->esp_status, eregs->esp_sstep, eregs->esp_intrpt));
+#ifdef DEBUG_ESP_CMDS
+ printk("esp%d: last ESP cmds [", esp->esp_id);
+ i = (esp->espcmdent - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ i = (i - 1) & 31;
+ printk("<");
+ esp_print_cmd(esp->espcmdlog[i]);
+ printk(">");
+ printk("]\n");
+#endif /* (DEBUG_ESP_CMDS) */
+
+ if(SCptr) {
+ ESPLOG(("esp%d: current command ", esp->esp_id));
+ esp_dump_cmd(SCptr);
+ }
+ ESPLOG(("\n"));
+ SCptr = esp->disconnected_SC;
+ ESPLOG(("esp%d: disconnected ", esp->esp_id));
+ while(SCptr) {
+ esp_dump_cmd(SCptr);
+ SCptr = (Scsi_Cmnd *) SCptr->host_scribble;
+ }
+ ESPLOG(("\n"));
+}
+
+/* Abort a command. */
+int esp_abort(Scsi_Cmnd *SCptr)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
+ struct ESP_regs *eregs = esp->eregs;
+ int don;
+ unsigned long flags;
+
+ ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
+ esp_dump_state(esp, eregs);
+
+ /* Wheee, if this is the current command on the bus, the
+ * best we can do is assert ATN and wait for msgout phase.
+ * This should even fix a hung SCSI bus when we lose state
+ * in the driver and timeout because the eventual phase change
+ * will cause the ESP to (eventually) give an interrupt.
+ */
+ save_and_cli(flags);
+ if(esp->current_SC == SCptr) {
+ esp->cur_msgout[0] = ABORT;
+ esp->msgout_len = 1;
+ esp->msgout_ctr = 0;
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ restore_flags(flags);
+ return SCSI_ABORT_PENDING;
+ }
+ restore_flags(flags);
+
+ /* If it is still in the issue queue then we can safely
+ * call the completion routine and report abort success.
+ */
+ don = esp->dma_ports_p(esp);
+ if(don) {
+ esp->dma_ints_off(esp);
+ synchronize_irq();
+ }
+ if(esp->issue_SC) {
+ Scsi_Cmnd **prev, *this;
+ for(prev = (&esp->issue_SC), this = esp->issue_SC;
+ this;
+ prev = (Scsi_Cmnd **) &(this->host_scribble),
+ this = (Scsi_Cmnd *) this->host_scribble) {
+ if(this == SCptr) {
+ *prev = (Scsi_Cmnd *) this->host_scribble;
+ this->host_scribble = NULL;
+ this->result = DID_ABORT << 16;
+ this->done(this);
+ if(don)
+ esp->dma_ints_on(esp);
+ return SCSI_ABORT_SUCCESS;
+ }
+ }
+ }
+
+ /* Yuck, the command to abort is disconnected, it is not
+ * worth trying to abort it now if something else is live
+ * on the bus at this time. So, we let the SCSI code wait
+ * a little bit and try again later.
+ */
+ if(esp->current_SC)
+ return SCSI_ABORT_BUSY;
+
+ /* It's disconnected, we have to reconnect to re-establish
+ * the nexus and tell the device to abort. However, we really
+ * cannot 'reconnect' per se, therefore we tell the upper layer
+ * the safest thing we can. This is, wait a bit, if nothing
+ * happens, we are really hung so reset the bus.
+ */
+
+ return SCSI_ABORT_SNOOZE;
+}
+
+/* Reset ESP chip, reset hanging bus, then kill active and
+ * disconnected commands for targets without soft reset.
+ */
+int esp_reset(Scsi_Cmnd *SCptr, unsigned int how)
+{
+ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
+ struct ESP_regs *eregs = esp->eregs;
+
+ ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+ esp->resetting_bus = 1;
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+ return SCSI_RESET_PENDING;
+}
+
+/* Internal ESP done function. */
+static void esp_done(struct NCR_ESP *esp, int error)
+{
+ Scsi_Cmnd *done_SC;
+
+ if(esp->current_SC) {
+ unsigned long flags;
+
+ done_SC = esp->current_SC;
+ esp->current_SC = NULL;
+
+ /* Free dvma entry. */
+ if(!done_SC->use_sg) {
+#ifdef CONFIG_SCSI_SUNESP
+ /* Sneaky. */
+ mmu_release_scsi_one(done_SC->SCp.have_data_in,
+ done_SC->request_bufflen,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+#endif
+ } else {
+#ifdef DEBUG_ESP_SG
+ printk("esp%d: unmapping sg ", esp->esp_id);
+#endif
+#ifdef CONFIG_SCSI_SUNESP
+ mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
+ done_SC->use_sg - 1,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+#endif
+#ifdef DEBUG_ESP_SG
+ printk("done.\n");
+#endif
+ }
+
+ done_SC->result = error;
+ done_SC->scsi_done(done_SC);
+
+ save_and_cli(flags);
+
+ /* Bus is free, issue any commands in the queue. */
+ if(esp->issue_SC && !esp->current_SC)
+ esp_exec_cmd(esp);
+
+ restore_flags(flags);
+ } else {
+ /* Panic is safe as current_SC is null so we may still
+ * be able to accept more commands to sync disk buffers.
+ */
+ ESPLOG(("panicing\n"));
+ panic("esp: done() called with NULL esp->current_SC");
+ }
+}
+
+/* Wheee, ESP interrupt engine. */
+
+enum {
+ do_phase_determine, do_reset_bus, do_reset_complete,
+ do_work_bus, do_intr_end,
+};
+
+/* Forward declarations. */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+ struct ESP_regs *eregs);
+static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+
+static inline int sreg_datainp(unchar sreg)
+{
+ return (sreg & ESP_STAT_PMASK) == ESP_DIP;
+}
+
+static inline int sreg_dataoutp(unchar sreg)
+{
+ return (sreg & ESP_STAT_PMASK) == ESP_DOP;
+}
+
+/* Did they drop these fabs on the floor or what?!?!! */
+static inline void hme_fifo_hwbug_workaround(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ unchar status = esp->sreg;
+
+ /* Cannot safely frob the fifo for these following cases. */
+ if(sreg_datainp(status) || sreg_dataoutp(status) ||
+ (esp->current_SC && esp->current_SC->SCp.phase == in_data_done)) {
+ ESPHME(("<wkaround_skipped>"));
+ return;
+ } else {
+ unsigned long count = 0;
+ unsigned long fcnt = eregs->esp_fflags & ESP_FF_FBYTES;
+
+ /* The HME stores bytes in multiples of 2 in the fifo. */
+ ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
+ while(fcnt) {
+ esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+ esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+ ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
+ fcnt--;
+ }
+ if(eregs->esp_status2 & ESP_STAT2_F1BYTE) {
+ ESPHME(("<poke_byte>"));
+ eregs->esp_fdata = 0;
+ esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+ ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
+ ESPHME(("CMD_FLUSH"));
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else {
+ ESPHME(("no_xtra_byte"));
+ }
+ esp->hme_fifo_workaround_count = count;
+ ESPHME(("wkarnd_cnt=%d]", (int)count));
+ }
+}
+
+static inline void hme_fifo_push(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ unchar *bytes, unchar count)
+{
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ while(count) {
+ eregs->esp_fdata = *bytes++;
+ eregs->esp_fdata = 0;
+ count--;
+ }
+}
+
+/* We try to avoid some interrupts by jumping ahead and see if the ESP
+ * has gotten far enough yet. Hence the following.
+ */
+static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *scp, int prev_phase, int new_phase)
+{
+ if(scp->SCp.sent_command != prev_phase)
+ return 0;
+
+ if(esp->dma_irq_p(esp)) {
+ /* Yes, we are able to save an interrupt. */
+ esp->sreg = eregs->esp_status;
+ if(esp->erev == fashme) {
+ /* This chip is really losing. */
+ ESPHME(("HME["));
+ /* Must latch fifo before reading the interrupt
+ * register else garbage ends up in the FIFO
+ * which confuses the driver utterly.
+ * Happy Meal indeed....
+ */
+ ESPHME(("fifo_workaround]"));
+ hme_fifo_hwbug_workaround(esp, eregs);
+ }
+ esp->ireg = eregs->esp_intrpt;
+ esp->sreg &= ~(ESP_STAT_INTR);
+ if(!(esp->ireg & ESP_INTR_SR))
+ return 0;
+ else
+ return do_reset_complete;
+ }
+ /* Ho hum, target is taking forever... */
+ scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+ return do_intr_end;
+}
+
+static inline int skipahead2(struct NCR_ESP *esp,
+ struct ESP_regs *eregs,
+ Scsi_Cmnd *scp, int prev_phase1, int prev_phase2,
+ int new_phase)
+{
+ if(scp->SCp.sent_command != prev_phase1 &&
+ scp->SCp.sent_command != prev_phase2)
+ return 0;
+ if(esp->dma_irq_p(esp)) {
+ /* Yes, we are able to save an interrupt. */
+ esp->sreg = eregs->esp_status;
+ if(esp->erev == fashme) {
+ /* This chip is really losing. */
+ ESPHME(("HME["));
+
+ /* Must latch fifo before reading the interrupt
+ * register else garbage ends up in the FIFO
+ * which confuses the driver utterly.
+ * Happy Meal indeed....
+ */
+ ESPHME(("fifo_workaround]"));
+ hme_fifo_hwbug_workaround(esp, eregs);
+ }
+ esp->ireg = eregs->esp_intrpt;
+ esp->sreg &= ~(ESP_STAT_INTR);
+ if(!(esp->ireg & ESP_INTR_SR))
+ return 0;
+ else
+ return do_reset_complete;
+ }
+ /* Ho hum, target is taking forever... */
+ scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+ return do_intr_end;
+}
+
+/* Misc. esp helper routines. */
+static inline void esp_setcount(struct ESP_regs *eregs, int cnt, int hme)
+{
+ eregs->esp_tclow = (cnt & 0xff);
+ eregs->esp_tcmed = ((cnt >> 8) & 0xff);
+ if(hme) {
+ eregs->fas_rlo = 0;
+ eregs->fas_rhi = 0;
+ }
+}
+
+static inline int esp_getcount(struct ESP_regs *eregs)
+{
+ return (((eregs->esp_tclow)&0xff) |
+ (((eregs->esp_tcmed)&0xff) << 8));
+}
+
+static inline int fcount(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->erev == fashme)
+ return esp->hme_fifo_workaround_count;
+ else
+ return eregs->esp_fflags & ESP_FF_FBYTES;
+}
+
+static inline int fnzero(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->erev == fashme)
+ return 0;
+ else
+ return eregs->esp_fflags & ESP_FF_ONOTZERO;
+}
+
+/* XXX speculative nops unnecessary when continuing amidst a data phase
+ * XXX even on esp100!!! another case of flooding the bus with I/O reg
+ * XXX writes...
+ */
+static inline void esp_maybe_nop(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->erev == esp100)
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+}
+
+static inline int sreg_to_dataphase(unchar sreg)
+{
+ if((sreg & ESP_STAT_PMASK) == ESP_DOP)
+ return in_dataout;
+ else
+ return in_datain;
+}
+
+/* The ESP100 when in synchronous data phase, can mistake a long final
+ * REQ pulse from the target as an extra byte, it places whatever is on
+ * the data lines into the fifo. For now, we will assume when this
+ * happens that the target is a bit quirky and we don't want to
+ * be talking synchronously to it anyways. Regardless, we need to
+ * tell the ESP to eat the extraneous byte so that we can proceed
+ * to the next phase.
+ */
+static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *sp, int fifocnt)
+{
+ /* Do not touch this piece of code. */
+ if((!(esp->erev == esp100)) ||
+ (!(sreg_datainp((esp->sreg = eregs->esp_status)) && !fifocnt) &&
+ !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+ if(sp->SCp.phase == in_dataout)
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ return 0;
+ } else {
+ /* Async mode for this guy. */
+ build_sync_nego_msg(esp, 0, 0);
+
+ /* Ack the bogus byte, but set ATN first. */
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+ return 1;
+ }
+}
+
+/* This closes the window during a selection with a reselect pending, because
+ * we use DMA for the selection process the FIFO should hold the correct
+ * contents if we get reselected during this process. So we just need to
+ * ack the possible illegal cmd interrupt pending on the esp100.
+ */
+static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ volatile unchar junk;
+
+ if(esp->erev != esp100)
+ return 0;
+ junk = eregs->esp_intrpt;
+
+ if(junk & ESP_INTR_SR)
+ return 1;
+ return 0;
+}
+
+/* This verifies the BUSID bits during a reselection so that we know which
+ * target is talking to us.
+ */
+static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int it, me = esp->scsi_id_mask, targ = 0;
+
+ if(2 != fcount(esp, eregs))
+ return -1;
+ if(esp->erev == fashme) {
+ /* HME does not latch it's own BUS ID bits during
+ * a reselection. Also the target number is given
+ * as an unsigned char, not as a sole bit number
+ * like the other ESP's do.
+ * Happy Meal indeed....
+ */
+ targ = esp->hme_fifo_workaround_buffer[0];
+ } else {
+ it = eregs->esp_fdata;
+ if(!(it & me))
+ return -1;
+ it &= ~me;
+ if(it & (it - 1))
+ return -1;
+ while(!(it & 1))
+ targ++, it >>= 1;
+ }
+ return targ;
+}
+
+/* This verifies the identify from the target so that we know which lun is
+ * being reconnected.
+ */
+static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ int lun;
+
+ if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
+ return -1;
+ if(esp->erev == fashme)
+ lun = esp->hme_fifo_workaround_buffer[1];
+ else
+ lun = eregs->esp_fdata;
+ if(esp->sreg & ESP_STAT_PERR)
+ return 0;
+ if((lun & 0x40) || !(lun & 0x80))
+ return -1;
+ return lun & 7;
+}
+
+/* This puts the driver in a state where it can revitalize a command that
+ * is being continued due to reselection.
+ */
+static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ Scsi_Cmnd *sp)
+{
+ Scsi_Device *dp = sp->device;
+ eregs->esp_soff = dp->sync_max_offset;
+ eregs->esp_stp = dp->sync_min_period;
+ if(esp->erev > esp100a)
+ eregs->esp_cfg3 = esp->config3[sp->target];
+ if(esp->erev == fashme)
+ eregs->esp_busid = (sp->target & 0xf) |
+ (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+ esp->current_SC = sp;
+}
+
+/* This will place the current working command back into the issue queue
+ * if we are to receive a reselection amidst a selection attempt.
+ */
+static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(!esp->disconnected_SC)
+ printk("esp%d: Weird, being reselected but disconnected "
+ "command queue is empty.\n", esp->esp_id);
+ esp->snip = 0;
+ esp->current_SC = 0;
+ sp->SCp.phase = not_issued;
+ append_SC(&esp->issue_SC, sp);
+}
+
+/* Begin message in phase. */
+static inline int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ /* Must be very careful with the fifo on the HME */
+ if((esp->erev != fashme) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY))
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ esp_maybe_nop(esp, eregs);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ esp->msgin_len = 1;
+ esp->msgin_ctr = 0;
+ esp_advance_phase(esp->current_SC, in_msgindone);
+ return do_work_bus;
+}
+
+static inline void advance_sg(Scsi_Cmnd *sp)
+{
+ ++sp->SCp.buffer;
+ --sp->SCp.buffers_residual;
+ sp->SCp.this_residual = sp->SCp.buffer->length;
+#ifdef CONFIG_SCSI_SUNESP
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+#else
+ sp->SCp.ptr = (char *)VTOP((unsigned long) sp->SCp.buffer->address);
+#endif
+}
+
+/* Please note that the way I've coded these routines is that I _always_
+ * check for a disconnect during any and all information transfer
+ * phases. The SCSI standard states that the target _can_ cause a BUS
+ * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note
+ * that during information transfer phases the target controls every
+ * change in phase, the only thing the initiator can do is "ask" for
+ * a message out phase by driving ATN true. The target can, and sometimes
+ * will, completely ignore this request so we cannot assume anything when
+ * we try to force a message out phase to abort/reset a target. Most of
+ * the time the target will eventually be nice and go to message out, so
+ * we may have to hold on to our state about what we want to tell the target
+ * for some period of time.
+ */
+
+/* I think I have things working here correctly. Even partial transfers
+ * within a buffer or sub-buffer should not upset us at all no matter
+ * how bad the target and/or ESP fucks things up.
+ */
+
+static inline int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int thisphase, hmuch;
+
+ ESPDATA(("esp_do_data: "));
+ esp_maybe_nop(esp, eregs);
+ thisphase = sreg_to_dataphase(esp->sreg);
+ esp_advance_phase(SCptr, thisphase);
+ ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
+ hmuch = esp->dma_can_transfer(esp, SCptr);
+ ESPDATA(("hmuch<%d> ", hmuch));
+ esp->current_transfer_size = hmuch;
+ if(esp->erev == fashme) {
+ /* Touchy chip, this stupid HME scsi adapter... */
+ esp_setcount(eregs, hmuch, 1);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+
+ if(thisphase == in_datain)
+ esp->dma_init_read(esp, (__u32)((unsigned long)SCptr->SCp.ptr), hmuch);
+ else
+ esp->dma_init_write(esp, (__u32)((unsigned long)SCptr->SCp.ptr), hmuch);
+ } else {
+ esp_setcount(eregs, hmuch, 0);
+ esp->dma_setup(esp,
+ (__u32)((unsigned long)SCptr->SCp.ptr),
+ hmuch, (thisphase == in_datain));
+ ESPDATA(("DMA|TI --> do_intr_end\n"));
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ return do_intr_end;
+}
+
+/* See how successful the data transfer was. */
+static inline int esp_do_data_finale(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
+
+ if(esp->dma_led_off)
+ esp->dma_led_off(esp);
+
+ ESPDATA(("esp_do_data_finale: "));
+
+ if(SCptr->SCp.phase == in_datain) {
+ if(esp->sreg & ESP_STAT_PERR) {
+ /* Yuck, parity error. The ESP asserts ATN
+ * so that we can go to message out phase
+ * immediately and inform the target that
+ * something bad happened.
+ */
+ ESPLOG(("esp%d: data bad parity detected.\n",
+ esp->esp_id));
+ esp->cur_msgout[0] = INITIATOR_ERROR;
+ esp->msgout_len = 1;
+ }
+ if(esp->dma_drain)
+ esp->dma_drain(esp);
+ }
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+
+ /* This could happen for the above parity error case. */
+ if(!(esp->ireg == ESP_INTR_BSERV)) {
+ /* Please go to msgout phase, please please please... */
+ ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
+ esp->esp_id));
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ /* Check for partial transfers and other horrible events.
+ * Note, here we read the real fifo flags register even
+ * on HME broken adapters because we skip the HME fifo
+ * workaround code in esp_handle() if we are doing data
+ * phase things. We don't want to fuck directly with
+ * the fifo like that, especially if doing syncronous
+ * transfers! Also, will need to double the count on
+ * HME if we are doing wide transfers, as the HME fifo
+ * will move and count 16-bit quantities during wide data.
+ * SMCC _and_ Qlogic can both bite me.
+ */
+ fifocnt = eregs->esp_fflags & ESP_FF_FBYTES;
+ if(esp->erev != fashme)
+ ecount = esp_getcount(eregs);
+ bytes_sent = esp->current_transfer_size;
+
+ /* Uhhh, might not want both of these conditionals to run
+ * at once on HME due to the fifo problems it has. Consider
+ * changing it to:
+ *
+ * if(!(esp->sreg & ESP_STAT_TCNT)) {
+ * bytes_sent -= ecount;
+ * } else if(SCptr->SCp.phase == in_dataout) {
+ * bytes_sent -= fifocnt;
+ * }
+ *
+ * But only for the HME case, leave the current code alone
+ * for all other ESP revisions as we know the existing code
+ * works just fine for them.
+ */
+ ESPDATA(("trans_sz=%d, ", bytes_sent));
+ if(esp->erev == fashme) {
+ if(!(esp->sreg & ESP_STAT_TCNT)) {
+ bytes_sent -= esp_getcount(eregs);
+ } else if(SCptr->SCp.phase == in_dataout) {
+ bytes_sent -= fifocnt;
+ }
+ } else {
+ if(!(esp->sreg & ESP_STAT_TCNT))
+ bytes_sent -= ecount;
+ if(SCptr->SCp.phase == in_dataout)
+ bytes_sent -= fifocnt;
+ }
+
+ ESPDATA(("bytes_sent=%d, ", bytes_sent));
+
+ /* If we were in synchronous mode, check for peculiarities. */
+ if(esp->erev == fashme) {
+ if(SCptr->device->sync_max_offset) {
+ if(SCptr->SCp.phase == in_dataout)
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else {
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ }
+ } else {
+ if(SCptr->device->sync_max_offset)
+ bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
+ else
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ }
+
+ /* Until we are sure of what has happened, we are certainly
+ * in the dark.
+ */
+ esp_advance_phase(SCptr, in_the_dark);
+
+ if(bytes_sent < 0) {
+ /* I've seen this happen due to lost state in this
+ * driver. No idea why it happened, but allowing
+ * this value to be negative caused things to
+ * lock up. This allows greater chance of recovery.
+ */
+ ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
+ ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
+ esp->esp_id,
+ esp->current_transfer_size, fifocnt, ecount));
+ ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
+ esp->esp_id,
+ SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+ bytes_sent = 0;
+ }
+
+ /* Update the state of our transfer. */
+ SCptr->SCp.ptr += bytes_sent;
+ SCptr->SCp.this_residual -= bytes_sent;
+ if(SCptr->SCp.this_residual < 0) {
+ /* shit */
+ printk("esp%d: Data transfer overrun.\n", esp->esp_id);
+ SCptr->SCp.this_residual = 0;
+ }
+
+ /* Maybe continue. */
+ if(!bogus_data) {
+ ESPDATA(("!bogus_data, "));
+ /* NO MATTER WHAT, we advance the scatterlist,
+ * if the target should decide to disconnect
+ * in between scatter chunks (which is common)
+ * we could die horribly! I used to have the sg
+ * advance occur only if we are going back into
+ * (or are staying in) a data phase, you can
+ * imagine the hell I went through trying to
+ * figure this out.
+ */
+ if(SCptr->use_sg && !SCptr->SCp.this_residual)
+ advance_sg(SCptr);
+ if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
+ ESPDATA(("to more data\n"));
+ return esp_do_data(esp, eregs);
+ }
+ ESPDATA(("to new phase\n"));
+ return esp_do_phase_determine(esp, eregs);
+ }
+ /* Bogus data, just wait for next interrupt. */
+ ESPLOG(("esp%d: bogus_data during end of data phase\n",
+ esp->esp_id));
+ return do_intr_end;
+}
+
+/* Either a command is completing or a target is dropping off the bus
+ * to continue the command in the background so we can do other work.
+ */
+static inline int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int rval;
+
+ rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing);
+ if(rval)
+ return rval;
+
+ if(esp->ireg != ESP_INTR_DC) {
+ ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
+ return do_reset_bus; /* target will not drop BSY... */
+ }
+ esp->msgout_len = 0;
+ esp->prevmsgout = NOP;
+ if(esp->prevmsgin == COMMAND_COMPLETE) {
+ /* Normal end of nexus. */
+ if(esp->disconnected_SC || (esp->erev == fashme))
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ if(SCptr->SCp.Status != GOOD && SCptr->SCp.Status != CONDITION_GOOD &&
+ ((1<<SCptr->target) & esp->targets_present) &&
+ SCptr->device->sync && SCptr->device->sync_max_offset) {
+ /* SCSI standard says that the synchronous capabilities
+ * should be renegotiated at this point. Most likely
+ * we are about to request sense from this target
+ * in which case we want to avoid using sync
+ * transfers until we are sure of the current target
+ * state.
+ */
+ ESPMISC(("esp: Status <%d> for target %d lun %d\n",
+ SCptr->SCp.Status, SCptr->target, SCptr->lun));
+
+ /* But don't do this when spinning up a disk at
+ * boot time while we poll for completion as it
+ * fills up the console with messages. Also, tapes
+ * can report not ready many times right after
+ * loading up a tape.
+ */
+ if(SCptr->cmnd[0] != START_STOP &&
+ SCptr->data_cmnd[0] != START_STOP &&
+ SCptr->cmnd[0] != TEST_UNIT_READY &&
+ SCptr->data_cmnd[0] != TEST_UNIT_READY &&
+ !(SCptr->device->type == TYPE_TAPE &&
+ (SCptr->cmnd[0] == TEST_UNIT_READY ||
+ SCptr->data_cmnd[0] == TEST_UNIT_READY ||
+ SCptr->cmnd[0] == MODE_SENSE ||
+ SCptr->data_cmnd[0] == MODE_SENSE)))
+ SCptr->device->sync = 0;
+ }
+ ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
+ esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+ ((SCptr->SCp.Message & 0xff)<<8) |
+ (DID_OK << 16)));
+ } else if(esp->prevmsgin == DISCONNECT) {
+ /* Normal disconnect. */
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+ ESPDISC(("D<%02x,%02x>", SCptr->target, SCptr->lun));
+ append_SC(&esp->disconnected_SC, SCptr);
+ esp->current_SC = NULL;
+ if(esp->issue_SC)
+ esp_exec_cmd(esp);
+ } else {
+ /* Driver bug, we do not expect a disconnect here
+ * and should not have advanced the state engine
+ * to in_freeing.
+ */
+ ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
+ esp->esp_id));
+ return do_reset_bus;
+ }
+ return do_intr_end;
+}
+
+/* Do the needy when a target tries to reconnect to us. */
+static inline int esp_do_reconnect(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ int lun, target;
+ Scsi_Cmnd *SCptr;
+
+ /* Check for all bogus conditions first. */
+ target = reconnect_target(esp, eregs);
+ if(target < 0) {
+ ESPDISC(("bad bus bits\n"));
+ return do_reset_bus;
+ }
+ lun = reconnect_lun(esp, eregs);
+ if(lun < 0) {
+ ESPDISC(("target=%2x, bad identify msg\n", target));
+ return do_reset_bus;
+ }
+
+ /* Things look ok... */
+ ESPDISC(("R<%02x,%02x>", target, lun));
+
+ /* Must flush both FIFO and the DVMA on HME. */
+ if(esp->erev == fashme) {
+ /* XXX this still doesn't fix the problem... */
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+ } else {
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ if(esp100_reconnect_hwbug(esp, eregs))
+ return do_reset_bus;
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ }
+
+ SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
+ if(!SCptr) {
+ Scsi_Cmnd *sp;
+
+ ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+ esp->esp_id));
+ ESPLOG(("QUEUE DUMP\n"));
+ sp = esp->issue_SC;
+ ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->current_SC;
+ ESPLOG(("esp%d: current_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->disconnected_SC;
+ ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ return do_reset_bus;
+ }
+ esp_connect(esp, eregs, SCptr);
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+ /* No need for explicit restore pointers operation. */
+ esp->snip = 0;
+ esp_advance_phase(SCptr, in_the_dark);
+ return do_intr_end;
+}
+
+/* End of NEXUS (hopefully), pick up status + message byte then leave if
+ * all goes well.
+ */
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int intr, rval;
+
+ rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status);
+ if(rval)
+ return rval;
+
+ intr = esp->ireg;
+ ESPSTAT(("esp_do_status: "));
+ if(intr != ESP_INTR_DC) {
+ int message_out = 0; /* for parity problems */
+
+ /* Ack the message. */
+ ESPSTAT(("ack msg, "));
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+ if(esp->dma_poll)
+ esp->dma_poll(esp, (unsigned char *) esp->esp_command);
+
+ ESPSTAT(("got something, "));
+ /* ESP chimes in with one of
+ *
+ * 1) function done interrupt:
+ * both status and message in bytes
+ * are available
+ *
+ * 2) bus service interrupt:
+ * only status byte was acquired
+ *
+ * 3) Anything else:
+ * can't happen, but we test for it
+ * anyways
+ *
+ * ALSO: If bad parity was detected on either
+ * the status _or_ the message byte then
+ * the ESP has asserted ATN on the bus
+ * and we must therefore wait for the
+ * next phase change.
+ */
+ if(intr & ESP_INTR_FDONE) {
+ /* We got it all, hallejulia. */
+ ESPSTAT(("got both, "));
+ SCptr->SCp.Status = esp->esp_command[0];
+ SCptr->SCp.Message = esp->esp_command[1];
+ esp->prevmsgin = SCptr->SCp.Message;
+ esp->cur_msgin[0] = SCptr->SCp.Message;
+ if(esp->sreg & ESP_STAT_PERR) {
+ /* There was bad parity for the
+ * message byte, the status byte
+ * was ok.
+ */
+ message_out = MSG_PARITY_ERROR;
+ }
+ } else if(intr == ESP_INTR_BSERV) {
+ /* Only got status byte. */
+ ESPLOG(("esp%d: got status only, ", esp->esp_id));
+ if(!(esp->sreg & ESP_STAT_PERR)) {
+ SCptr->SCp.Status = esp->esp_command[0];
+ SCptr->SCp.Message = 0xff;
+ } else {
+ /* The status byte had bad parity.
+ * we leave the scsi_pointer Status
+ * field alone as we set it to a default
+ * of CHECK_CONDITION in esp_queue.
+ */
+ message_out = INITIATOR_ERROR;
+ }
+ } else {
+ /* This shouldn't happen ever. */
+ ESPSTAT(("got bolixed\n"));
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ if(!message_out) {
+ ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
+ SCptr->SCp.Message));
+ if(SCptr->SCp.Message == COMMAND_COMPLETE) {
+ ESPSTAT(("and was COMMAND_COMPLETE\n"));
+ esp_advance_phase(SCptr, in_freeing);
+ return esp_do_freebus(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
+ esp->esp_id));
+ esp->msgin_len = esp->msgin_ctr = 1;
+ esp_advance_phase(SCptr, in_msgindone);
+ return esp_do_msgindone(esp, eregs);
+ }
+ } else {
+ /* With luck we'll be able to let the target
+ * know that bad parity happened, it will know
+ * which byte caused the problems and send it
+ * again. For the case where the status byte
+ * receives bad parity, I do not believe most
+ * targets recover very well. We'll see.
+ */
+ ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
+ esp->esp_id, message_out));
+ esp->cur_msgout[0] = message_out;
+ esp->msgout_len = esp->msgout_ctr = 1;
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+ } else {
+ /* If we disconnect now, all hell breaks loose. */
+ ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+}
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+
+ ESPPHASE(("esp_do_phase_determine: "));
+ if(!(esp->ireg & ESP_INTR_DC)) {
+ switch(esp->sreg & ESP_STAT_PMASK) {
+ case ESP_DOP:
+ case ESP_DIP:
+ ESPPHASE(("to data phase\n"));
+ return esp_do_data(esp, eregs);
+
+ case ESP_STATP:
+ /* Whee, status phase, finish up the command. */
+ ESPPHASE(("to status phase\n"));
+
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+ if(esp->do_pio_cmds){
+ esp_advance_phase(SCptr, in_status);
+ esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
+ while(!(esp->eregs->esp_status & ESP_STAT_INTR));
+ esp->esp_command[0] = eregs->esp_fdata;
+ while(!(esp->eregs->esp_status & ESP_STAT_INTR));
+ esp->esp_command[1] = eregs->esp_fdata;
+ } else {
+ if(esp->erev != fashme) {
+ esp->esp_command[0] = 0xff;
+ esp->esp_command[1] = 0xff;
+ eregs->esp_tclow = 2;
+ eregs->esp_tcmed = 0;
+ esp->dma_init_read(esp, esp->esp_command_dvma, 2);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
+ } else {
+ /* Using DVMA for status/message bytes is
+ * unreliable on HME, nice job QLogic.
+ * Happy Meal indeed....
+ */
+ esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
+ }
+ esp_advance_phase(SCptr, in_status);
+ }
+ return esp_do_status(esp, eregs);
+
+ case ESP_MOP:
+ ESPPHASE(("to msgout phase\n"));
+ esp_advance_phase(SCptr, in_msgout);
+ return esp_do_msgout(esp, eregs);
+
+ case ESP_MIP:
+ ESPPHASE(("to msgin phase\n"));
+ esp_advance_phase(SCptr, in_msgin);
+ return esp_do_msgin(esp, eregs);
+
+ case ESP_CMDP:
+ /* Ugh, we're running a non-standard command the
+ * ESP doesn't understand, one byte at a time.
+ */
+ ESPPHASE(("to cmd phase\n"));
+ esp_advance_phase(SCptr, in_cmdbegin);
+ return esp_do_cmdbegin(esp, eregs);
+ };
+ } else {
+ Scsi_Device *dp = SCptr->device;
+
+ /* This means real problems if we see this
+ * here. Unless we were actually trying
+ * to force the device to abort/reset.
+ */
+ ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
+ ESPLOG(("pphase<%s> cphase<%s>, ",
+ phase_string(SCptr->SCp.phase),
+ phase_string(SCptr->SCp.sent_command)));
+ if(esp->disconnected_SC || (esp->erev == fashme))
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ switch(esp->cur_msgout[0]) {
+ default:
+ /* We didn't expect this to happen at all. */
+ ESPLOG(("device is bolixed\n"));
+ esp_advance_phase(SCptr, in_tgterror);
+ esp_done(esp, (DID_ERROR << 16));
+ break;
+
+ case BUS_DEVICE_RESET:
+ ESPLOG(("device reset successful\n"));
+ dp->sync_max_offset = 0;
+ dp->sync_min_period = 0;
+ dp->sync = 0;
+ esp_advance_phase(SCptr, in_resetdev);
+ esp_done(esp, (DID_RESET << 16));
+ break;
+
+ case ABORT:
+ ESPLOG(("device abort successful\n"));
+ esp_advance_phase(SCptr, in_abortone);
+ esp_done(esp, (DID_ABORT << 16));
+ break;
+
+ };
+ return do_intr_end;
+ }
+
+ ESPLOG(("esp%d: to unknown phase\n", esp->esp_id));
+ printk("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+ esp->sreg & ESP_STAT_PMASK);
+ return do_reset_bus;
+}
+
+/* First interrupt after exec'ing a cmd comes here. */
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ Scsi_Device *SDptr = SCptr->device;
+ int cmd_bytes_sent, fcnt;
+
+ if(esp->erev != fashme)
+ esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+ if(esp->erev == fashme)
+ fcnt = esp->hme_fifo_workaround_count;
+ else
+ fcnt = (eregs->esp_fflags & ESP_FF_FBYTES);
+ cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+
+ /* Let's check to see if a reselect happened
+ * while we we're trying to select. This must
+ * be checked first.
+ */
+ if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+ esp_reconnect(esp, SCptr);
+ return esp_do_reconnect(esp, eregs);
+ }
+
+ /* Looks like things worked, we should see a bus service &
+ * a function complete interrupt at this point. Note we
+ * are doing a direct comparison because we don't want to
+ * be fooled into thinking selection was successful if
+ * ESP_INTR_DC is set, see below.
+ */
+ if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+ /* target speaks... */
+ esp->targets_present |= (1<<SCptr->target);
+
+ /* What if the target ignores the sdtr? */
+ if(esp->snip)
+ SDptr->sync = 1;
+
+ /* See how far, if at all, we got in getting
+ * the information out to the target.
+ */
+ switch(esp->seqreg) {
+ default:
+
+ case ESP_STEP_ASEL:
+ /* Arbitration won, target selected, but
+ * we are in some phase which is not command
+ * phase nor is it message out phase.
+ *
+ * XXX We've confused the target, obviously.
+ * XXX So clear it's state, but we also end
+ * XXX up clearing everyone elses. That isn't
+ * XXX so nice. I'd like to just reset this
+ * XXX target, but if I cannot even get it's
+ * XXX attention and finish selection to talk
+ * XXX to it, there is not much more I can do.
+ * XXX If we have a loaded bus we're going to
+ * XXX spend the next second or so renegotiating
+ * XXX for synchronous transfers.
+ */
+ ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
+ esp->esp_id, SCptr->target));
+
+ case ESP_STEP_SID:
+ /* Arbitration won, target selected, went
+ * to message out phase, sent one message
+ * byte, then we stopped. ATN is asserted
+ * on the SCSI bus and the target is still
+ * there hanging on. This is a legal
+ * sequence step if we gave the ESP a select
+ * and stop command.
+ *
+ * XXX See above, I could set the borken flag
+ * XXX in the device struct and retry the
+ * XXX command. But would that help for
+ * XXX tagged capable targets?
+ */
+
+ case ESP_STEP_NCMD:
+ /* Arbitration won, target selected, maybe
+ * sent the one message byte in message out
+ * phase, but we did not go to command phase
+ * in the end. Actually, we could have sent
+ * only some of the message bytes if we tried
+ * to send out the entire identify and tag
+ * message using ESP_CMD_SA3.
+ */
+ cmd_bytes_sent = 0;
+ break;
+
+ case ESP_STEP_PPC:
+ /* No, not the powerPC pinhead. Arbitration
+ * won, all message bytes sent if we went to
+ * message out phase, went to command phase
+ * but only part of the command was sent.
+ *
+ * XXX I've seen this, but usually in conjunction
+ * XXX with a gross error which appears to have
+ * XXX occurred between the time I told the
+ * XXX ESP to arbitrate and when I got the
+ * XXX interrupt. Could I have misloaded the
+ * XXX command bytes into the fifo? Actually,
+ * XXX I most likely missed a phase, and therefore
+ * XXX went into never never land and didn't even
+ * XXX know it. That was the old driver though.
+ * XXX What is even more peculiar is that the ESP
+ * XXX showed the proper function complete and
+ * XXX bus service bits in the interrupt register.
+ */
+
+ case ESP_STEP_FINI4:
+ case ESP_STEP_FINI5:
+ case ESP_STEP_FINI6:
+ case ESP_STEP_FINI7:
+ /* Account for the identify message */
+ if(SCptr->SCp.phase == in_slct_norm)
+ cmd_bytes_sent -= 1;
+ };
+ if(esp->erev != fashme)
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+ /* Be careful, we could really get fucked during synchronous
+ * data transfers if we try to flush the fifo now.
+ */
+ if((esp->erev != fashme) && /* not a Happy Meal and... */
+ !fcnt && /* Fifo is empty and... */
+ /* either we are not doing synchronous transfers or... */
+ (!SDptr->sync_max_offset ||
+ /* We are not going into data in phase. */
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */
+
+ /* See how far we got if this is not a slow command. */
+ if(!esp->esp_slowcmd) {
+ if(cmd_bytes_sent < 0)
+ cmd_bytes_sent = 0;
+ if(cmd_bytes_sent != SCptr->cmd_len) {
+ /* Crapola, mark it as a slowcmd
+ * so that we have some chance of
+ * keeping the command alive with
+ * good luck.
+ *
+ * XXX Actually, if we didn't send it all
+ * XXX this means either we didn't set things
+ * XXX up properly (driver bug) or the target
+ * XXX or the ESP detected parity on one of
+ * XXX the command bytes. This makes much
+ * XXX more sense, and therefore this code
+ * XXX should be changed to send out a
+ * XXX parity error message or if the status
+ * XXX register shows no parity error then
+ * XXX just expect the target to bring the
+ * XXX bus into message in phase so that it
+ * XXX can send us the parity error message.
+ * XXX SCSI sucks...
+ */
+ esp->esp_slowcmd = 1;
+ esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
+ esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
+ }
+ }
+
+ /* Now figure out where we went. */
+ esp_advance_phase(SCptr, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+
+ /* Did the target even make it? */
+ if(esp->ireg == ESP_INTR_DC) {
+ /* wheee... nobody there or they didn't like
+ * what we told it to do, clean up.
+ */
+
+ /* If anyone is off the bus, but working on
+ * a command in the background for us, tell
+ * the ESP to listen for them.
+ */
+ if(esp->disconnected_SC)
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+ if(((1<<SCptr->target) & esp->targets_present) &&
+ esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE &&
+ (SCptr->SCp.phase == in_slct_msg ||
+ SCptr->SCp.phase == in_slct_stop)) {
+ /* shit */
+ esp->snip = 0;
+ printk("esp%d: Failed synchronous negotiation for target %d "
+ "lun %d\n",
+ esp->esp_id, SCptr->target, SCptr->lun);
+ SDptr->sync_max_offset = 0;
+ SDptr->sync_min_period = 0;
+ SDptr->sync = 1; /* so we don't negotiate again */
+
+ /* Run the command again, this time though we
+ * won't try to negotiate for synchronous transfers.
+ *
+ * XXX I'd like to do something like send an
+ * XXX INITIATOR_ERROR or ABORT message to the
+ * XXX target to tell it, "Sorry I confused you,
+ * XXX please come back and I will be nicer next
+ * XXX time". But that requires having the target
+ * XXX on the bus, and it has dropped BSY on us.
+ */
+ esp->current_SC = NULL;
+ esp_advance_phase(SCptr, not_issued);
+ prepend_SC(&esp->issue_SC, SCptr);
+ esp_exec_cmd(esp);
+ return do_intr_end;
+ }
+
+ /* Ok, this is normal, this is what we see during boot
+ * or whenever when we are scanning the bus for targets.
+ * But first make sure that is really what is happening.
+ */
+ if(((1<<SCptr->target) & esp->targets_present)) {
+ printk("esp%d: Warning, live target %d not responding to "
+ "selection.\n", esp->esp_id, SCptr->target);
+
+ /* This _CAN_ happen. The SCSI standard states that
+ * the target is to _not_ respond to selection if
+ * _it_ detects bad parity on the bus for any reason.
+ * Therefore, we assume that if we've talked successfully
+ * to this target before, bad parity is the problem.
+ */
+ esp_done(esp, (DID_PARITY << 16));
+ } else {
+ /* Else, there really isn't anyone there. */
+ ESPMISC(("esp: selection failure, maybe nobody there?\n"));
+ ESPMISC(("esp: target %d lun %d\n",
+ SCptr->target, SCptr->lun));
+ esp_done(esp, (DID_BAD_TARGET << 16));
+ }
+ return do_intr_end;
+ }
+
+
+ ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
+ printk("esp%d: Currently -- ", esp->esp_id);
+ esp_print_ireg(esp->ireg);
+ printk(" ");
+ esp_print_statreg(esp->sreg);
+ printk(" ");
+ esp_print_seqreg(esp->seqreg);
+ printk("\n");
+ printk("esp%d: New -- ", esp->esp_id);
+ esp->sreg = eregs->esp_status;
+ esp->seqreg = eregs->esp_sstep;
+ esp->ireg = eregs->esp_intrpt;
+ esp_print_ireg(esp->ireg);
+ printk(" ");
+ esp_print_statreg(esp->sreg);
+ printk(" ");
+ esp_print_seqreg(esp->seqreg);
+ printk("\n");
+ ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
+ return do_reset_bus; /* ugh... */
+}
+
+/* Continue reading bytes for msgin phase. */
+static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->ireg & ESP_INTR_BSERV) {
+ /* in the right phase too? */
+ if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
+ /* phew... */
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ esp_advance_phase(esp->current_SC, in_msgindone);
+ return do_intr_end;
+ }
+
+ /* We changed phase but ESP shows bus service,
+ * in this case it is most likely that we, the
+ * hacker who has been up for 20hrs straight
+ * staring at the screen, drowned in coffee
+ * smelling like retched cigarette ashes
+ * have miscoded something..... so, try to
+ * recover as best we can.
+ */
+ printk("esp%d: message in mis-carriage.\n", esp->esp_id);
+ }
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return do_phase_determine;
+}
+
+static inline int check_singlebyte_msg(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ esp->prevmsgin = esp->cur_msgin[0];
+ if(esp->cur_msgin[0] & 0x80) {
+ /* wheee... */
+ ESPLOG(("esp%d: target sends identify amidst phases\n",
+ esp->esp_id));
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return 0;
+ } else if(((esp->cur_msgin[0] & 0xf0) == 0x20) ||
+ (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
+ esp->msgin_len = 2;
+ esp_advance_phase(esp->current_SC, in_msgincont);
+ return 0;
+ }
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ switch(esp->cur_msgin[0]) {
+ default:
+ /* We don't want to hear about it. */
+ ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
+ esp->cur_msgin[0]));
+ return MESSAGE_REJECT;
+
+ case NOP:
+ ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
+ esp->current_SC->target));
+ return 0;
+
+ case RESTORE_POINTERS:
+ case SAVE_POINTERS:
+ /* We handle this all automatically. */
+ return 0;
+
+ case COMMAND_COMPLETE:
+ case DISCONNECT:
+ /* Freeing the bus, let it go. */
+ esp->current_SC->SCp.phase = in_freeing;
+ return 0;
+
+ case MESSAGE_REJECT:
+ ESPMISC(("msg reject, "));
+ if(esp->prevmsgout == EXTENDED_MESSAGE) {
+ Scsi_Device *SDptr = esp->current_SC->device;
+
+ /* Doesn't look like this target can
+ * do synchronous or WIDE transfers.
+ */
+ ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
+ SDptr->sync = 1;
+ SDptr->wide = 1;
+ SDptr->sync_min_period = 0;
+ SDptr->sync_max_offset = 0;
+ return 0;
+ } else {
+ ESPMISC(("not sync nego, sending ABORT\n"));
+ return ABORT;
+ }
+ };
+}
+
+/* Target negotiates for synchronous transfers before we do, this
+ * is legal although very strange. What is even funnier is that
+ * the SCSI2 standard specifically recommends against targets doing
+ * this because so many initiators cannot cope with this occuring.
+ */
+static inline int target_with_ants_in_pants(struct NCR_ESP *esp,
+ Scsi_Cmnd *SCptr,
+ Scsi_Device *SDptr)
+{
+ if(SDptr->sync || SDptr->borken) {
+ /* sorry, no can do */
+ ESPSDTR(("forcing to async, "));
+ build_sync_nego_msg(esp, 0, 0);
+ SDptr->sync = 1;
+ esp->snip = 1;
+ ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
+ esp_advance_phase(SCptr, in_the_dark);
+ return EXTENDED_MESSAGE;
+ }
+
+ /* Ok, we'll check them out... */
+ return 0;
+}
+
+static inline void sync_report(struct NCR_ESP *esp)
+{
+ int msg3, msg4;
+ char *type;
+
+ msg3 = esp->cur_msgin[3];
+ msg4 = esp->cur_msgin[4];
+ if(msg4) {
+ int hz = 1000000000 / (msg3 * 4);
+ int integer = hz / 1000000;
+ int fraction = (hz - (integer * 1000000)) / 10000;
+ if((esp->erev == fashme) &&
+ (esp->config3[esp->current_SC->target] & ESP_CONFIG3_EWIDE)) {
+ type = "FAST-WIDE";
+ integer <<= 1;
+ fraction <<= 1;
+ } else if((msg3 * 4) < 200) {
+ type = "FAST";
+ } else {
+ type = "synchronous";
+ }
+ printk(KERN_INFO "esp%d: target %d [period %dns offset %d %d.%02dMHz %s SCSI%s]\n",
+ esp->esp_id, esp->current_SC->target,
+ (int) msg3 * 4,
+ (int) msg4,
+ integer, fraction, type,
+ (((msg3 * 4) < 200) ? "-II" : ""));
+ } else {
+ printk(KERN_INFO "esp%d: target %d asynchronous\n",
+ esp->esp_id, esp->current_SC->target);
+ }
+}
+
+static inline int check_multibyte_msg(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ Scsi_Device *SDptr = SCptr->device;
+ unchar regval = 0;
+ int message_out = 0;
+
+ ESPSDTR(("chk multibyte msg: "));
+ if(esp->cur_msgin[2] == EXTENDED_SDTR) {
+ int period = esp->cur_msgin[3];
+ int offset = esp->cur_msgin[4];
+
+ ESPSDTR(("is sync nego response, "));
+ if(!esp->snip) {
+ int rval;
+
+ /* Target negotiates first! */
+ ESPSDTR(("target jumps the gun, "));
+ message_out = EXTENDED_MESSAGE; /* we must respond */
+ rval = target_with_ants_in_pants(esp, SCptr, SDptr);
+ if(rval)
+ return rval;
+ }
+
+ ESPSDTR(("examining sdtr, "));
+
+ /* Offset cannot be larger than ESP fifo size. */
+ if(offset > 15) {
+ ESPSDTR(("offset too big %2x, ", offset));
+ offset = 15;
+ ESPSDTR(("sending back new offset\n"));
+ build_sync_nego_msg(esp, period, offset);
+ return EXTENDED_MESSAGE;
+ }
+
+ if(offset && period > esp->max_period) {
+ /* Yeee, async for this slow device. */
+ ESPSDTR(("period too long %2x, ", period));
+ build_sync_nego_msg(esp, 0, 0);
+ ESPSDTR(("hoping for msgout\n"));
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return EXTENDED_MESSAGE;
+ } else if (offset && period < esp->min_period) {
+ ESPSDTR(("period too short %2x, ", period));
+ period = esp->min_period;
+ if(esp->erev > esp236)
+ regval = 4;
+ else
+ regval = 5;
+ } else if(offset) {
+ int tmp;
+
+ ESPSDTR(("period is ok, "));
+ tmp = esp->ccycle / 1000;
+ regval = (((period << 2) + tmp - 1) / tmp);
+ if(regval && ((esp->erev == fas100a ||
+ esp->erev == fas236 ||
+ esp->erev == fashme))) {
+ if(period >= 50)
+ regval--;
+ }
+ }
+
+ if(offset) {
+ unchar bit;
+
+ SDptr->sync_min_period = (regval & 0x1f);
+ SDptr->sync_max_offset = (offset | esp->radelay);
+ if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+ if((esp->erev == fas100a) || (esp->erev == fashme))
+ bit = ESP_CONFIG3_FAST;
+ else
+ bit = ESP_CONFIG3_FSCSI;
+ if(period < 50)
+ esp->config3[SCptr->target] |= bit;
+ else
+ esp->config3[SCptr->target] &= ~bit;
+ eregs->esp_cfg3 = esp->config3[SCptr->target];
+ }
+ eregs->esp_soff = SDptr->sync_min_period;
+ eregs->esp_stp = SDptr->sync_max_offset;
+
+ ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
+ SDptr->sync_max_offset,
+ SDptr->sync_min_period,
+ esp->config3[SCptr->target]));
+
+ esp->snip = 0;
+ } else if(SDptr->sync_max_offset) {
+ unchar bit;
+
+ /* back to async mode */
+ ESPSDTR(("unaccaptable sync nego, forcing async\n"));
+ SDptr->sync_max_offset = 0;
+ SDptr->sync_min_period = 0;
+ eregs->esp_soff = 0;
+ eregs->esp_stp = 0;
+ if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+ if((esp->erev == fas100a) || (esp->erev == fashme))
+ bit = ESP_CONFIG3_FAST;
+ else
+ bit = ESP_CONFIG3_FSCSI;
+ esp->config3[SCptr->target] &= ~bit;
+ eregs->esp_cfg3 = esp->config3[SCptr->target];
+ }
+ }
+
+ sync_report(esp);
+
+ ESPSDTR(("chk multibyte msg: sync is known, "));
+ SDptr->sync = 1;
+
+ if(message_out) {
+ ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
+ esp->esp_id));
+ build_sync_nego_msg(esp, period, offset);
+ esp_advance_phase(SCptr, in_the_dark);
+ return EXTENDED_MESSAGE;
+ }
+
+ ESPSDTR(("returning zero\n"));
+ esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
+ return 0;
+ } else if(esp->cur_msgin[2] == EXTENDED_WDTR) {
+ int size = 8 << esp->cur_msgin[3];
+
+ esp->wnip = 0;
+ if(esp->erev != fashme) {
+ printk("esp%d: AIEEE wide msg received and not HME.\n",
+ esp->esp_id);
+ message_out = MESSAGE_REJECT;
+ } else if(size > 16) {
+ printk("esp%d: AIEEE wide transfer for %d size not supported.\n",
+ esp->esp_id, size);
+ message_out = MESSAGE_REJECT;
+ } else {
+ /* Things look good, lets see what we got. */
+ if(size == 16) {
+ /* Set config 3 register for this target. */
+ printk("esp%d: 16 byte WIDE transfers enabled for target %d.\n",
+ esp->esp_id, SCptr->target);
+ esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
+ } else {
+ /* Just make sure it was one byte sized. */
+ if(size != 8) {
+ printk("esp%d: Aieee, wide nego of %d size.\n",
+ esp->esp_id, size);
+ message_out = MESSAGE_REJECT;
+ goto finish;
+ }
+ /* Pure paranoia. */
+ esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE);
+ }
+ eregs->esp_cfg3 = esp->config3[SCptr->target];
+
+ /* Regardless, next try for sync transfers. */
+ build_sync_nego_msg(esp, esp->sync_defp, 15);
+ SDptr->sync = 1;
+ esp->snip = 1;
+ message_out = EXTENDED_MESSAGE;
+ }
+ } else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
+ ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
+ message_out = MESSAGE_REJECT;
+ }
+finish:
+ esp_advance_phase(SCptr, in_the_dark);
+ return message_out;
+}
+
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+ int message_out = 0, it = 0, rval;
+
+ rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone);
+ if(rval)
+ return rval;
+ if(SCptr->SCp.sent_command != in_status) {
+ if(!(esp->ireg & ESP_INTR_DC)) {
+ if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
+ message_out = MSG_PARITY_ERROR;
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else if(esp->erev != fashme &&
+ (it = (eregs->esp_fflags & ESP_FF_FBYTES))!=1) {
+ /* We certainly dropped the ball somewhere. */
+ message_out = INITIATOR_ERROR;
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ } else if(!esp->msgin_len) {
+ if(esp->erev == fashme)
+ it = esp->hme_fifo_workaround_buffer[0];
+ else
+ it = eregs->esp_fdata;
+ esp_advance_phase(SCptr, in_msgincont);
+ } else {
+ /* it is ok and we want it */
+ if(esp->erev == fashme)
+ it = esp->cur_msgin[esp->msgin_ctr] =
+ esp->hme_fifo_workaround_buffer[0];
+ else
+ it = esp->cur_msgin[esp->msgin_ctr] =
+ eregs->esp_fdata;
+ esp->msgin_ctr++;
+ }
+ } else {
+ esp_advance_phase(SCptr, in_the_dark);
+ return do_work_bus;
+ }
+ } else {
+ it = esp->cur_msgin[0];
+ }
+ if(!message_out && esp->msgin_len) {
+ if(esp->msgin_ctr < esp->msgin_len) {
+ esp_advance_phase(SCptr, in_msgincont);
+ } else if(esp->msgin_len == 1) {
+ message_out = check_singlebyte_msg(esp, eregs);
+ } else if(esp->msgin_len == 2) {
+ if(esp->cur_msgin[0] == EXTENDED_MESSAGE) {
+ if((it+2) >= 15) {
+ message_out = MESSAGE_REJECT;
+ } else {
+ esp->msgin_len = (it + 2);
+ esp_advance_phase(SCptr, in_msgincont);
+ }
+ } else {
+ message_out = MESSAGE_REJECT; /* foo on you */
+ }
+ } else {
+ message_out = check_multibyte_msg(esp, eregs);
+ }
+ }
+ if(message_out < 0) {
+ return -message_out;
+ } else if(message_out) {
+ if(((message_out != 1) &&
+ ((message_out < 0x20) || (message_out & 0x80))))
+ esp->msgout_len = 1;
+ esp->cur_msgout[0] = message_out;
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_advance_phase(SCptr, in_the_dark);
+ esp->msgin_len = 0;
+ }
+ esp->sreg = eregs->esp_status;
+ esp->sreg &= ~(ESP_STAT_INTR);
+ if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
+ esp_cmd(esp, eregs, ESP_CMD_MOK);
+ if((SCptr->SCp.sent_command == in_msgindone) &&
+ (SCptr->SCp.phase == in_freeing))
+ return esp_do_freebus(esp, eregs);
+ return do_intr_end;
+}
+
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+
+ esp_advance_phase(SCptr, in_cmdend);
+ if(esp->erev == fashme) {
+ int i;
+
+ for(i = 0; i < esp->esp_scmdleft; i++)
+ esp->esp_command[i] = *esp->esp_scmdp++;
+ esp->esp_scmdleft = 0;
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ esp_setcount(eregs, i, 1);
+ esp_cmd(esp, eregs, (ESP_CMD_DMA | ESP_CMD_TI));
+ esp->dma_init_write(esp, esp->esp_command_dvma, i);
+ } else {
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ eregs->esp_fdata = *esp->esp_scmdp++;
+ esp->esp_scmdleft--;
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ }
+ return do_intr_end;
+}
+
+static inline int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ if(esp->erev == fashme){
+ if(esp->dma_invalidate)
+ esp->dma_invalidate(esp);
+ } else
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ if(esp->ireg & ESP_INTR_BSERV) {
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+ }
+ ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
+ esp->esp_id));
+ return do_reset_bus;
+}
+
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ switch(esp->msgout_len) {
+ case 1:
+ if(esp->erev == fashme)
+ hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
+ else
+ eregs->esp_fdata = esp->cur_msgout[0];
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ break;
+
+ case 2:
+ if(esp->do_pio_cmds){
+ eregs->esp_fdata = esp->cur_msgout[0];
+ eregs->esp_fdata = esp->cur_msgout[1];
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ if(esp->erev == fashme) {
+ hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 2);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->dma_setup(esp, esp->esp_command_dvma, 2, 0);
+ esp_setcount(eregs, 2, 0);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ }
+ break;
+
+ case 4:
+ esp->snip = 1;
+ if(esp->do_pio_cmds){
+ eregs->esp_fdata = esp->cur_msgout[0];
+ eregs->esp_fdata = esp->cur_msgout[1];
+ eregs->esp_fdata = esp->cur_msgout[2];
+ eregs->esp_fdata = esp->cur_msgout[3];
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ esp->esp_command[2] = esp->cur_msgout[2];
+ esp->esp_command[3] = esp->cur_msgout[3];
+ if(esp->erev == fashme) {
+ hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 4);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->dma_setup(esp, esp->esp_command_dvma, 4, 0);
+ esp_setcount(eregs, 4, 0);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ }
+ break;
+
+ case 5:
+ esp->snip = 1;
+ if(esp->do_pio_cmds){
+ eregs->esp_fdata = esp->cur_msgout[0];
+ eregs->esp_fdata = esp->cur_msgout[1];
+ eregs->esp_fdata = esp->cur_msgout[2];
+ eregs->esp_fdata = esp->cur_msgout[3];
+ eregs->esp_fdata = esp->cur_msgout[4];
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->esp_command[0] = esp->cur_msgout[0];
+ esp->esp_command[1] = esp->cur_msgout[1];
+ esp->esp_command[2] = esp->cur_msgout[2];
+ esp->esp_command[3] = esp->cur_msgout[3];
+ esp->esp_command[4] = esp->cur_msgout[4];
+ if(esp->erev == fashme) {
+ hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 5);
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ } else {
+ esp->dma_setup(esp, esp->esp_command_dvma, 5, 0);
+ esp_setcount(eregs, 5, 0);
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ }
+ }
+ break;
+
+ default:
+ /* whoops */
+ ESPMISC(("bogus msgout sending NOP\n"));
+ esp->cur_msgout[0] = NOP;
+ if(esp->erev == fashme) {
+ hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
+ } else {
+ eregs->esp_fdata = esp->cur_msgout[0];
+ }
+ esp->msgout_len = 1;
+ esp_cmd(esp, eregs, ESP_CMD_TI);
+ break;
+ }
+ esp_advance_phase(esp->current_SC, in_msgoutdone);
+ return do_intr_end;
+}
+
+static inline int esp_do_msgoutdone(struct NCR_ESP *esp,
+ struct ESP_regs *eregs)
+{
+ if((esp->msgout_len > 1) && esp->dma_barrier)
+ esp->dma_barrier(esp);
+
+ if(!(esp->ireg & ESP_INTR_DC)) {
+ if(esp->erev != fashme)
+ esp_cmd(esp, eregs, ESP_CMD_NULL);
+ switch(esp->sreg & ESP_STAT_PMASK) {
+ case ESP_MOP:
+ /* whoops, parity error */
+ ESPLOG(("esp%d: still in msgout, parity error assumed\n",
+ esp->esp_id));
+ if(esp->msgout_len > 1)
+ esp_cmd(esp, eregs, ESP_CMD_SATN);
+ esp_advance_phase(esp->current_SC, in_msgout);
+ return do_work_bus;
+
+ case ESP_DIP:
+ break;
+
+ default:
+ /* Happy Meal fifo is touchy... */
+ if((esp->erev != fashme) &&
+ !fcount(esp, eregs) &&
+ !(esp->current_SC->device->sync_max_offset))
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ break;
+
+ };
+ } else {
+ ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
+ return do_reset_bus;
+ }
+
+ /* If we sent out a synchronous negotiation message, update
+ * our state.
+ */
+ if(esp->cur_msgout[2] == EXTENDED_MESSAGE &&
+ esp->cur_msgout[4] == EXTENDED_SDTR) {
+ esp->snip = 1; /* anal retentiveness... */
+ }
+
+ esp->prevmsgout = esp->cur_msgout[0];
+ esp->msgout_len = 0;
+ esp_advance_phase(esp->current_SC, in_the_dark);
+ return esp_do_phase_determine(esp, eregs);
+}
+
+/* This is the second tier in our dual-level SCSI state machine. */
+static inline int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+ Scsi_Cmnd *SCptr = esp->current_SC;
+
+ ESPBUS(("esp_work_bus: "));
+ if(!SCptr) {
+ ESPBUS(("reconnect\n"));
+ return esp_do_reconnect(esp, eregs);
+ }
+
+ switch(SCptr->SCp.phase) {
+ case in_the_dark:
+ ESPBUS(("in the dark\n"));
+ return esp_do_phase_determine(esp, eregs);
+
+ case in_slct_norm:
+ case in_slct_stop:
+ case in_slct_msg:
+ case in_slct_tag:
+ case in_slct_sneg:
+ ESPBUS(("finish selection\n"));
+ return esp_select_complete(esp, eregs);
+
+ case in_datain:
+ case in_dataout:
+ ESPBUS(("finish data\n"));
+ return esp_do_data_finale(esp, eregs);
+
+ case in_msgout:
+ ESPBUS(("message out "));
+ return esp_do_msgout(esp, eregs);
+
+ case in_msgoutdone:
+ ESPBUS(("finish message out "));
+ return esp_do_msgoutdone(esp, eregs);
+
+ case in_msgin:
+ ESPBUS(("message in "));
+ return esp_do_msgin(esp, eregs);
+
+ case in_msgincont:
+ ESPBUS(("continue message in "));
+ return esp_do_msgincont(esp, eregs);
+
+ case in_msgindone:
+ ESPBUS(("finish message in "));
+ return esp_do_msgindone(esp, eregs);
+
+ case in_status:
+ ESPBUS(("status phase "));
+ return esp_do_status(esp, eregs);
+
+ case in_freeing:
+ ESPBUS(("freeing the bus "));
+ return esp_do_freebus(esp, eregs);
+
+ case in_cmdbegin:
+ ESPBUS(("begin slow cmd "));
+ return esp_do_cmdbegin(esp, eregs);
+
+ case in_cmdend:
+ ESPBUS(("end slow cmd "));
+ return esp_do_cmddone(esp, eregs);
+
+ default:
+ printk("esp%d: command in weird state %2x\n",
+ esp->esp_id, esp->current_SC->SCp.phase);
+ return do_reset_bus;
+ };
+}
+
+/* Main interrupt handler for an esp adapter. */
+inline void esp_handle(struct NCR_ESP *esp)
+{
+ struct ESP_regs *eregs;
+ Scsi_Cmnd *SCptr;
+ int what_next = do_intr_end;
+#ifdef CONFIG_SCSI_SUNESP
+ struct sparc_dma_registers *dregs =
+ (struct sparc_dma_registers*) esp->dregs;
+#endif
+ eregs = esp->eregs;
+ SCptr = esp->current_SC;
+
+ if(esp->dma_irq_entry)
+ esp->dma_irq_entry(esp);
+
+ /* Check for errors. */
+ esp->sreg = eregs->esp_status;
+ esp->sreg &= (~ESP_STAT_INTR);
+ if(esp->erev == fashme) {
+ esp->sreg2 = eregs->esp_status2;
+ esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+ }
+ if(esp->sreg & (ESP_STAT_SPAM)) {
+ /* Gross error, could be due to one of:
+ *
+ * - top of fifo overwritten, could be because
+ * we tried to do a synchronous transfer with
+ * an offset greater than ESP fifo size
+ *
+ * - top of command register overwritten
+ *
+ * - DMA setup to go in one direction, SCSI
+ * bus points in the other, whoops
+ *
+ * - weird phase change during asynchronous
+ * data phase while we are initiator
+ */
+ ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
+
+ /* If a command is live on the bus we cannot safely
+ * reset the bus, so we'll just let the pieces fall
+ * where they may. Here we are hoping that the
+ * target will be able to cleanly go away soon
+ * so we can safely reset things.
+ */
+ if(!SCptr) {
+ ESPLOG(("esp%d: No current cmd during gross error, "
+ "resetting bus\n", esp->esp_id));
+ what_next = do_reset_bus;
+ goto again;
+ }
+ }
+
+#ifdef CONFIG_SCSI_SUNESP
+ if(dregs->cond_reg & DMA_HNDL_ERROR) {
+ /* A DMA gate array error. Here we must
+ * be seeing one of two things. Either the
+ * virtual to physical address translation
+ * on the SBUS could not occur, else the
+ * translation it did get pointed to a bogus
+ * page. Ho hum...
+ */
+ ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
+ dregs->cond_reg));
+
+ /* DMA gate array itself must be reset to clear the
+ * error condition.
+ */
+ if(esp->dma_reset)
+ esp->dma_reset(esp);
+
+ what_next = do_reset_bus;
+ goto again;
+ }
+#endif /* CONFIG_SCSI_SUNESP */
+
+ if(esp->erev == fashme) {
+ /* This chip is really losing. */
+ ESPHME(("HME["));
+
+ ESPHME(("sreg2=%02x,", esp->sreg2));
+ /* Must latch fifo before reading the interrupt
+ * register else garbage ends up in the FIFO
+ * which confuses the driver utterly.
+ */
+ if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+ (esp->sreg2 & ESP_STAT2_F1BYTE)) {
+ ESPHME(("fifo_workaround]"));
+ hme_fifo_hwbug_workaround(esp, eregs);
+ } else {
+ ESPHME(("no_fifo_workaround]"));
+ }
+ }
+
+ esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */
+
+ /* This cannot be done until this very moment. -DaveM */
+ synchronize_irq();
+
+ /* No current cmd is only valid at this point when there are
+ * commands off the bus or we are trying a reset.
+ */
+ if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
+ /* Panic is safe, since current_SC is null. */
+ ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
+ panic("esp_handle: current_SC == penguin within interrupt!");
+ }
+
+ if(esp->ireg & (ESP_INTR_IC)) {
+ /* Illegal command fed to ESP. Outside of obvious
+ * software bugs that could cause this, there is
+ * a condition with esp100 where we can confuse the
+ * ESP into an erroneous illegal command interrupt
+ * because it does not scrape the FIFO properly
+ * for reselection. See esp100_reconnect_hwbug()
+ * to see how we try very hard to avoid this.
+ */
+ ESPLOG(("esp%d: illegal command\n", esp->esp_id));
+
+ esp_dump_state(esp, eregs);
+
+ if(SCptr) {
+ /* Devices with very buggy firmware can drop BSY
+ * during a scatter list interrupt when using sync
+ * mode transfers. We continue the transfer as
+ * expected, the target drops the bus, the ESP
+ * gets confused, and we get a illegal command
+ * interrupt because the bus is in the disconnected
+ * state now and ESP_CMD_TI is only allowed when
+ * a nexus is alive on the bus.
+ */
+ ESPLOG(("esp%d: Forcing async and disabling disconnect for "
+ "target %d\n", esp->esp_id, SCptr->target));
+ SCptr->device->borken = 1; /* foo on you */
+ }
+
+ what_next = do_reset_bus;
+ goto again;
+ }
+
+ if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+ int phase;
+
+ if(SCptr) {
+ phase = SCptr->SCp.phase;
+ if(phase & in_phases_mask) {
+ what_next = esp_work_bus(esp, eregs);
+ } else if(phase & in_slct_mask) {
+ what_next = esp_select_complete(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: interrupt for no good reason...\n",
+ esp->esp_id));
+ goto esp_handle_done;
+ }
+ } else {
+ ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ goto again;
+ }
+ } else if(esp->ireg & ESP_INTR_SR) {
+ ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
+ what_next = do_reset_complete;
+ } else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
+ ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ goto again;
+ } else if(esp->ireg & ESP_INTR_RSEL) {
+ if(!SCptr) {
+ /* This is ok. */
+ what_next = esp_do_reconnect(esp, eregs);
+ } else if(SCptr->SCp.phase & in_slct_mask) {
+ /* Only selection code knows how to clean
+ * up properly.
+ */
+ ESPDISC(("Reselected during selection attempt\n"));
+ what_next = esp_select_complete(esp, eregs);
+ } else {
+ ESPLOG(("esp%d: Reselected while bus is busy\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ goto again;
+ }
+ }
+
+ /* We're trying to fight stack problems, and inline as much as
+ * possible without making this driver a mess. hate hate hate
+ * This is tier-one in our dual level SCSI state machine.
+ */
+again:
+ switch(what_next) {
+ case do_intr_end:
+ goto esp_handle_done;
+
+ case do_work_bus:
+ what_next = esp_work_bus(esp, eregs);
+ break;
+
+ case do_phase_determine:
+ what_next = esp_do_phase_determine(esp, eregs);
+ break;
+
+ case do_reset_bus:
+ ESPLOG(("esp%d: resetting bus...\n", esp->esp_id));
+ esp->resetting_bus = 1;
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+ goto esp_handle_done;
+
+ case do_reset_complete:
+ /* Tricky, we don't want to cause any more commands to
+ * go out until we clear all the live cmds by hand.
+ */
+ if(esp->current_SC) {
+ Scsi_Cmnd *SCptr = esp->current_SC;
+
+#ifdef CONFIG_SCSI_SUNESP
+ if(!SCptr->use_sg)
+ mmu_release_scsi_one(SCptr->SCp.have_data_in,
+ SCptr->request_bufflen,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+ else
+ mmu_release_scsi_sgl((struct mmu_sglist *)
+ SCptr->buffer,
+ SCptr->use_sg - 1,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+#endif
+ SCptr->result = (DID_RESET << 16);
+
+ SCptr->scsi_done(SCptr);
+ }
+ esp->current_SC = NULL;
+ if(esp->disconnected_SC) {
+ Scsi_Cmnd *SCptr;
+ while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
+ if(!SCptr->use_sg)
+#ifdef CONFIG_SCSI_SUNESP
+ mmu_release_scsi_one(SCptr->SCp.have_data_in,
+ SCptr->request_bufflen,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+ else
+ mmu_release_scsi_sgl((struct mmu_sglist *)
+ SCptr->buffer,
+ SCptr->use_sg - 1,
+ ((struct linux_sbus_device *) (esp->edev))->my_bus);
+#endif
+ SCptr->result = (DID_RESET << 16);
+
+ SCptr->scsi_done(SCptr);
+ }
+ }
+ esp->resetting_bus = 0;
+
+ if(esp->current_SC) {
+ printk("esp%d: weird weird weird, current_SC not NULL after "
+ "SCSI bus reset.\n", esp->esp_id);
+ goto esp_handle_done;
+ }
+
+ /* Now it is safe to execute more things. */
+ if(esp->issue_SC)
+ esp_exec_cmd(esp);
+ goto esp_handle_done;
+
+ default:
+ /* state is completely lost ;-( */
+ ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
+ break;
+
+ };
+ goto again;
+
+esp_handle_done:
+ if(esp->dma_irq_exit)
+ esp->dma_irq_exit(esp);
+ return;
+}
+
+#ifndef __sparc_v9__
+
+#ifndef __SMP__
+void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+ struct NCR_ESP *esp;
+ int again;
+
+ /* Handle all ESP interrupts showing at this IRQ level. */
+repeat:
+ again = 0;
+ for_each_esp(esp) {
+ if(((esp)->irq & 0xf) == irq) {
+ if(esp->dma_irq_p(esp)) {
+ again = 1;
+
+ esp->dma_ints_off(esp);
+
+ ESPIRQ(("I%d(", esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ }
+ }
+ }
+ if(again)
+ goto repeat;
+}
+#else
+/* For SMP we only service one ESP on the list list at our IRQ level! */
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+ struct NCR_ESP *esp;
+
+ /* Handle all ESP interrupts showing at this IRQ level. */
+ for_each_esp(esp) {
+ if(((esp)->irq & 0xf) == irq) {
+ if(esp->dma_irq_p(esp)) {
+ esp->dma_ints_off(esp);
+
+ ESPIRQ(("I[%d:%d](",
+ smp_processor_id(), esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ return;
+ }
+ }
+ }
+}
+#endif
+
+#else /* __sparc_v9__ */
+
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+ struct NCR_ESP *esp = dev_id;
+
+ if(esp->dma_irq_p(esp)) {
+ esp->dma_ints_off(dregs);
+
+ ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ esp->dma_ints_on(esp);
+ }
+}
+
+#endif
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
new file mode 100644
index 000000000..a7431ca87
--- /dev/null
+++ b/drivers/scsi/NCR53C9x.h
@@ -0,0 +1,529 @@
+/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver.
+ *
+ * Originaly esp.h: Defines and structures for the Sparc ESP
+ * (Enhanced SCSI Processor) driver under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Generalization by Jesper Skov (jskov@cygnus.co.uk)
+ */
+
+#ifndef NCR53C9X_H
+#define NCR53C9X_H
+
+/* Macros for debugging messages */
+
+/* #define DEBUG_ESP */
+/* #define DEBUG_ESP_HME */
+/* #define DEBUG_ESP_DATA */
+/* #define DEBUG_ESP_QUEUE */
+/* #define DEBUG_ESP_DISCONNECT */
+/* #define DEBUG_ESP_STATUS */
+/* #define DEBUG_ESP_PHASES */
+/* #define DEBUG_ESP_WORKBUS */
+/* #define DEBUG_STATE_MACHINE */
+/* #define DEBUG_ESP_CMDS */
+/* #define DEBUG_ESP_IRQS */
+/* #define DEBUG_SDTR */
+/* #define DEBUG_ESP_SG */
+
+/* Use the following to sprinkle debugging messages in a way which
+ * suits you if combinations of the above become too verbose when
+ * trying to track down a specific problem.
+ */
+/* #define DEBUG_ESP_MISC */
+
+#if defined(DEBUG_ESP)
+#define ESPLOG(foo) printk foo
+#else
+#define ESPLOG(foo)
+#endif /* (DEBUG_ESP) */
+
+#if defined(DEBUG_ESP_HME)
+#define ESPHME(foo) printk foo
+#else
+#define ESPHME(foo)
+#endif
+
+#if defined(DEBUG_ESP_DATA)
+#define ESPDATA(foo) printk foo
+#else
+#define ESPDATA(foo)
+#endif
+
+#if defined(DEBUG_ESP_QUEUE)
+#define ESPQUEUE(foo) printk foo
+#else
+#define ESPQUEUE(foo)
+#endif
+
+#if defined(DEBUG_ESP_DISCONNECT)
+#define ESPDISC(foo) printk foo
+#else
+#define ESPDISC(foo)
+#endif
+
+#if defined(DEBUG_ESP_STATUS)
+#define ESPSTAT(foo) printk foo
+#else
+#define ESPSTAT(foo)
+#endif
+
+#if defined(DEBUG_ESP_PHASES)
+#define ESPPHASE(foo) printk foo
+#else
+#define ESPPHASE(foo)
+#endif
+
+#if defined(DEBUG_ESP_WORKBUS)
+#define ESPBUS(foo) printk foo
+#else
+#define ESPBUS(foo)
+#endif
+
+#if defined(DEBUG_ESP_IRQS)
+#define ESPIRQ(foo) printk foo
+#else
+#define ESPIRQ(foo)
+#endif
+
+#if defined(DEBUG_SDTR)
+#define ESPSDTR(foo) printk foo
+#else
+#define ESPSDTR(foo)
+#endif
+
+#if defined(DEBUG_ESP_MISC)
+#define ESPMISC(foo) printk foo
+#else
+#define ESPMISC(foo)
+#endif
+
+#define INTERNAL_ESP_ERROR \
+ (panic ("Internal ESP driver error in file %s, line %d\n", \
+ __FILE__, __LINE__))
+
+#define INTERNAL_ESP_ERROR_NOPANIC \
+ (printk ("Internal ESP driver error in file %s, line %d\n", \
+ __FILE__, __LINE__))
+
+/* The ESP SCSI controllers have their register sets in three
+ * "classes":
+ *
+ * 1) Registers which are both read and write.
+ * 2) Registers which are read only.
+ * 3) Registers which are write only.
+ *
+ * Yet, they all live within the same IO space.
+ */
+
+/* All the ESP registers are one byte each and are accessed longwords
+ * apart with a big-endian ordering to the bytes.
+ */
+
+struct ESP_regs {
+ /* Access Description Offset */
+ volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */
+ unchar tlpad1[3];
+ volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */
+ unchar fdpad[3];
+ volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */
+ unchar cbpad[3];
+ volatile unchar esp_cmd; /* rw SCSI command bits 0x0c */
+ unchar stpad[3];
+ volatile unchar esp_status; /* ro ESP status register 0x10 */
+#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */
+ unchar irqpd[3];
+ volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */
+#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */
+ unchar sspad[3];
+ volatile unchar esp_sstep; /* ro Sequence step register 0x18 */
+#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */
+ unchar ffpad[3];
+ volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */
+#define esp_soff esp_fflags /* wo Sync offset 0x1c */
+ unchar cf1pd[3];
+ volatile unchar esp_cfg1; /* rw First configuration register 0x20 */
+ unchar cfpad[3];
+ volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */
+#define esp_status2 esp_cfact /* ro HME status2 register 0x24 */
+ unchar ctpad[3];
+ volatile unchar esp_ctest; /* wo Chip test register 0x28 */
+ unchar cf2pd[3];
+ volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */
+ unchar cf3pd[3];
+
+ /* The following is only found on the 53C9X series SCSI chips */
+ volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */
+ unchar thpd[7];
+
+ /* The following is found on all chips except the NCR53C90 (ESP100) */
+ volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */
+#define esp_uid esp_tchi /* ro Unique ID code 0x38 */
+#define fas_rlo esp_tchi /* rw HME extended counter 0x38 */
+ unchar fgpad[3];
+ volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */
+#define fas_rhi esp_fgrnd /* rw HME extended counter 0x3c */
+};
+
+/* Various revisions of the ESP board. */
+enum esp_rev {
+ esp100 = 0x00, /* NCR53C90 - very broken */
+ esp100a = 0x01, /* NCR53C90A */
+ esp236 = 0x02,
+ fas236 = 0x03,
+ fas100a = 0x04,
+ fast = 0x05,
+ fashme = 0x06,
+ espunknown = 0x07
+};
+
+/* We get one of these for each ESP probed. */
+struct NCR_ESP {
+ struct NCR_ESP *next; /* Next ESP on probed or NULL */
+ struct ESP_regs *eregs; /* All esp registers */
+ struct Linux_DMA *dma; /* Who I do transfers with. */
+ void *dregs; /* And his registers. */
+ struct Scsi_Host *ehost; /* Backpointer to SCSI Host */
+
+ void *edev; /* Pointer to controller base/SBus */
+ char prom_name[64]; /* Name of ESP device from prom */
+ int prom_node; /* Prom node where ESP found */
+ int esp_id; /* Unique per-ESP ID number */
+
+ /* ESP Configuration Registers */
+ unsigned char config1; /* Copy of the 1st config register */
+ unsigned char config2; /* Copy of the 2nd config register */
+ unsigned char config3[16]; /* Copy of the 3rd config register */
+
+ /* The current command we are sending to the ESP chip. This esp_command
+ * ptr needs to be mapped in DVMA area so we can send commands and read
+ * from the ESP fifo without burning precious CPU cycles. Programmed I/O
+ * sucks when we have the DVMA to do it for us. The ESP is stupid and will
+ * only send out 6, 10, and 12 byte SCSI commands, others we need to send
+ * one byte at a time. esp_slowcmd being set says that we are doing one
+ * of the command types ESP doesn't understand, esp_scmdp keeps track of
+ * which byte we are sending, esp_scmdleft says how many bytes to go.
+ */
+ volatile unchar *esp_command; /* Location of command (CPU view) */
+ __u32 esp_command_dvma; /* Location of command (DVMA view) */
+ unsigned char esp_clen; /* Length of this command */
+ unsigned char esp_slowcmd;
+ unsigned char *esp_scmdp;
+ unsigned char esp_scmdleft;
+
+ /* The following are used to determine the cause of an IRQ. Upon every
+ * IRQ entry we synchronize these with the hardware registers.
+ */
+ unchar ireg; /* Copy of ESP interrupt register */
+ unchar sreg; /* Same for ESP status register */
+ unchar seqreg; /* The ESP sequence register */
+ unchar sreg2; /* Copy of HME status2 register */
+
+ /* The HME is the biggest piece of shit I have ever seen. */
+ unchar hme_fifo_workaround_buffer[16 * 2]; /* 16-bit/entry fifo for wide scsi */
+ unchar hme_fifo_workaround_count;
+
+ /* Clock periods, frequencies, synchronization, etc. */
+ unsigned int cfreq; /* Clock frequency in HZ */
+ unsigned int cfact; /* Clock conversion factor */
+ unsigned int ccycle; /* One ESP clock cycle */
+ unsigned int ctick; /* One ESP clock time */
+ unsigned int radelay; /* FAST chip req/ack delay */
+ unsigned int neg_defp; /* Default negotiation period */
+ unsigned int sync_defp; /* Default sync transfer period */
+ unsigned int max_period; /* longest our period can be */
+ unsigned int min_period; /* shortest period we can withstand */
+ unsigned char ccf; /* Clock conversion factor */
+ /* For slow to medium speed input clock rates we shoot for 5mb/s,
+ * but for high input clock rates we try to do 10mb/s although I
+ * don't think a transfer can even run that fast with an ESP even
+ * with DMA2 scatter gather pipelining.
+ */
+#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
+#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
+
+ unsigned int snip; /* Sync. negotiation in progress */
+ unsigned int wnip; /* WIDE negotiation in progress */
+ unsigned int targets_present; /* targets spoken to before */
+
+ int current_transfer_size; /* Set at beginning of data dma */
+
+ unchar espcmdlog[32]; /* Log of current esp cmds sent. */
+ unchar espcmdent; /* Current entry in esp cmd log. */
+
+ /* Misc. info about this ESP */
+ enum esp_rev erev; /* ESP revision */
+ int irq; /* SBus IRQ for this ESP */
+ int scsi_id; /* Who am I as initiator? */
+ int scsi_id_mask; /* Bitmask of 'me'. */
+ int diff; /* Differential SCSI bus? */
+ int bursts; /* Burst sizes our DVMA supports */
+
+ /* Our command queues, only one cmd lives in the current_SC queue. */
+ Scsi_Cmnd *issue_SC; /* Commands to be issued */
+ Scsi_Cmnd *current_SC; /* Who is currently working the bus */
+ Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */
+
+ /* Message goo */
+ unchar cur_msgout[16];
+ unchar cur_msgin[16];
+ unchar prevmsgout, prevmsgin;
+ unchar msgout_len, msgin_len;
+ unchar msgout_ctr, msgin_ctr;
+
+ /* States that we cannot keep in the per cmd structure because they
+ * cannot be assosciated with any specific command.
+ */
+ unchar resetting_bus;
+
+ unchar do_pio_cmds; /* Do command transfer with pio */
+
+ /* Functions handling DMA
+ */
+ /* Required functions */
+ int (*dma_bytes_sent)(struct NCR_ESP *, int);
+ int (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_dump_state)(struct NCR_ESP *);
+ void (*dma_init_read)(struct NCR_ESP *, __u32, int);
+ void (*dma_init_write)(struct NCR_ESP *, __u32, int);
+ void (*dma_ints_off)(struct NCR_ESP *);
+ void (*dma_ints_on)(struct NCR_ESP *);
+ int (*dma_irq_p)(struct NCR_ESP *);
+ int (*dma_ports_p)(struct NCR_ESP *);
+ void (*dma_setup)(struct NCR_ESP *, __u32, int, int);
+
+ /* Optional functions (i.e. may be initialized to 0) */
+ void (*dma_barrier)(struct NCR_ESP *);
+ void (*dma_drain)(struct NCR_ESP *);
+ void (*dma_invalidate)(struct NCR_ESP *);
+ void (*dma_irq_entry)(struct NCR_ESP *);
+ void (*dma_irq_exit)(struct NCR_ESP *);
+ void (*dma_led_off)(struct NCR_ESP *);
+ void (*dma_led_on)(struct NCR_ESP *);
+ void (*dma_poll)(struct NCR_ESP *, unsigned char *);
+ void (*dma_reset)(struct NCR_ESP *);
+};
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
+#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */
+#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
+#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */
+#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
+#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
+#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */
+#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */
+#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */
+#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */
+#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */
+#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */
+#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */
+#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */
+#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */
+#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */
+#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */
+#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */
+#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */
+#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */
+#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */
+#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */
+#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */
+#define ESP_CONFIG3_BIGID 0x20 /* SCSI-ID's are 4bits (hme) */
+#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */
+#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */
+#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
+#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
+
+/* ESP command register read-write */
+/* Group 1 commands: These may be sent at any point in time to the ESP
+ * chip. None of them can generate interrupts 'cept
+ * the "SCSI bus reset" command if you have not disabled
+ * SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
+#define ESP_CMD_RC 0x02 /* Chip reset */
+#define ESP_CMD_RS 0x03 /* SCSI bus reset */
+
+/* Group 2 commands: ESP must be an initiator and connected to a target
+ * for these commands to work.
+ */
+#define ESP_CMD_TI 0x10 /* Transfer Information */
+#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
+#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
+#define ESP_CMD_SATN 0x1a /* Set ATN */
+#define ESP_CMD_RATN 0x1b /* De-assert ATN */
+
+/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
+ * to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG 0x20 /* Send message */
+#define ESP_CMD_SSTAT 0x21 /* Send status */
+#define ESP_CMD_SDATA 0x22 /* Send data */
+#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
+#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT 0x27 /* Disconnect */
+#define ESP_CMD_RMSG 0x28 /* Receive Message */
+#define ESP_CMD_RCMD 0x29 /* Receive Command */
+#define ESP_CMD_RDATA 0x2a /* Receive Data */
+#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
+
+/* Group 4 commands: The ESP must be in the disconnected state and must
+ * not be connected to any targets as initiator for
+ * these commands to work.
+ */
+#define ESP_CMD_RSEL 0x40 /* Reselect */
+#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
+#define ESP_CMD_SELA 0x42 /* Select w/ATN */
+#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL 0x44 /* Enable selection */
+#define ESP_CMD_DSEL 0x45 /* Disable selections */
+#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
+#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
+
+/* This bit enables the ESP's DMA on the SBus */
+#define ESP_CMD_DMA 0x80 /* Do DMA? */
+
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO 0x01 /* IO phase bit */
+#define ESP_STAT_PCD 0x02 /* CD phase bit */
+#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
+#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
+#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
+#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR 0x20 /* Parity error */
+#define ESP_STAT_SPAM 0x40 /* Real bad error */
+/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
+ * bit on other revs of the ESP.
+ */
+#define ESP_STAT_INTR 0x80 /* Interrupt */
+
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in. For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP (0) /* Data Out */
+#define ESP_DIP (ESP_STAT_PIO) /* Data In */
+#define ESP_CMDP (ESP_STAT_PCD) /* Command */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
+#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
+#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S 0x01 /* Select w/o ATN */
+#define ESP_INTR_SATN 0x02 /* Select w/ATN */
+#define ESP_INTR_RSEL 0x04 /* Reselected */
+#define ESP_INTR_FDONE 0x08 /* Function done */
+#define ESP_INTR_BSERV 0x10 /* Bus service */
+#define ESP_INTR_DC 0x20 /* Disconnect */
+#define ESP_INTR_IC 0x40 /* Illegal command given */
+#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
+
+/* Interrupt status macros */
+#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR))
+#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC))
+#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN))
+#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S))
+#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \
+ (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
+#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL))
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS 0x07 /* Valid bits */
+#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID 0x01 /* One msg byte sent */
+#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
+#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
+ * bytes to be lost
+ */
+#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5 0x05
+#define ESP_STEP_FINI6 0x06
+#define ESP_STEP_FINI7 0x07
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG 0x01 /* Target test mode */
+#define ESP_TEST_INI 0x02 /* Initiator test mode */
+#define ESP_TEST_TS 0x04 /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a only */
+#define ESP_UID_F100A 0x00 /* ESP FAS100A */
+#define ESP_UID_F236 0x02 /* ESP FAS236 */
+#define ESP_UID_REV 0x07 /* ESP revision */
+#define ESP_UID_FAM 0xf8 /* ESP family */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */
+#define ESP_FF_SSTEP 0xe0 /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
+#define ESP_CCF_F2 0x02 /* 10MHz */
+#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
+
+/* HME only... */
+#define ESP_BUSID_RESELID 0x10
+#define ESP_BUSID_CTR32BIT 0x40
+
+#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */
+#define ESP_TIMEO_CONST 8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+ ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
+
+
+extern struct proc_dir_entry proc_scsi_esp;
+
+/* UGLY, UGLY, UGLY! */
+extern int nesps, esps_in_use, esps_running;
+
+/* For our interrupt engine. */
+#define for_each_esp(esp) \
+ for((esp) = espchain; (esp); (esp) = (esp)->next)
+
+
+/* External functions */
+extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+ unchar cmd);
+extern struct NCR_ESP *esp_allocate(Scsi_Host_Template *, void *);
+extern void esp_initialize(struct NCR_ESP *);
+extern void esp_intr(int, void *, struct pt_regs *);
+#endif /* !(NCR53C9X_H) */
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 0290331ce..fedb3ed66 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -196,8 +196,8 @@ __initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
static unsigned char called = 0;
struct Scsi_Host *instance;
caddr_t address;
- int key;
- struct ConfigDev *cd;
+ unsigned int key;
+ const struct ConfigDev *cd;
if (!MACH_IS_AMIGA || called)
return 0;
@@ -206,8 +206,8 @@ __initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
tpnt->proc_dir = &proc_scsi_a2091;
tpnt->proc_info = &wd33c93_proc_info;
- while ((key = zorro_find(MANUF_COMMODORE, PROD_A2091, 0, 0)) ||
- (key = zorro_find(MANUF_COMMODORE, PROD_A590, 0, 0))) {
+ while ((key = zorro_find(ZORRO_PROD_CBM_A590_A2091_1, 0, 0)) ||
+ (key = zorro_find(ZORRO_PROD_CBM_A590_A2091_2, 0, 0))) {
cd = zorro_get_board(key);
address = cd->cd_BoardAddr;
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index f07d5e2cd..7ec76b19a 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -33,14 +33,17 @@ struct proc_dir_entry proc_scsi_amiga7xx = {
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
+extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+ u32 base, int io_port, int irq, int dma,
+ long long options, int clock);
+
int amiga7xx_detect(Scsi_Host_Template *tpnt)
{
static unsigned char called = 0;
- int key, clock;
- int num = 0;
- unsigned long address;
+ unsigned int key;
+ int num = 0, clock;
long long options;
- struct ConfigDev *cd;
+ const struct ConfigDev *cd;
if (called || !MACH_IS_AMIGA)
return 0;
@@ -48,8 +51,9 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
tpnt->proc_dir = &proc_scsi_amiga7xx;
#ifdef CONFIG_WARPENGINE_SCSI
- if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
+ if ((key = zorro_find(ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, 0, 0)))
{
+ unsigned long address;
cd = zorro_get_board(key);
address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
@@ -59,7 +63,8 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
clock = 50000000; /* 50MHz SCSI Clock */
ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
- 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
+ options, clock);
zorro_config_board(key, 0);
num++;
@@ -73,17 +78,18 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
clock = 50000000; /* 50MHz SCSI Clock */
- ncr53c7xx_init(tpnt, 0, 710,
- (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
- 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
+ options, clock);
num++;
}
#endif
#ifdef CONFIG_A4091_SCSI
- while ( (key = zorro_find(MANUF_COMMODORE, PROD_A4091, 0, 0)) ||
- (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
+ while ( (key = zorro_find(ZORRO_PROD_CBM_A4091_1, 0, 0)) ||
+ (key = zorro_find(ZORRO_PROD_CBM_A4091_2, 0, 0)) )
{
+ unsigned long address;
cd = zorro_get_board(key);
address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
@@ -93,14 +99,34 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
clock = 50000000; /* 50MHz SCSI Clock */
ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
- 0, IRQ_AMIGA_PORTS, DMA_NONE,
- options, clock);
+ 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
zorro_config_board(key, 0);
num++;
}
#endif
+#ifdef CONFIG_GVP_TURBO_SCSI
+ if((key = zorro_find(ZORRO_PROD_GVP_GFORCE_040_060, 0, 0)))
+ {
+ cd = zorro_get_board(key);
+ address = ZTWO_VADDR((unsigned long)cd->cd_BoardAddr);
+
+ options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
+ OPTION_INTFLY | OPTION_SYNCHRONOUS |
+ OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710,
+ (u32)(unsigned char *)(address + 0x40000),
+ 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock);
+
+ zorro_config_board(key, 0);
+ num++;
+ }
+#endif
+
called = 1;
return num;
}
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index 09317d376..d8f68c628 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -6,7 +6,7 @@ int amiga7xx_detect(Scsi_Host_Template *);
const char *NCR53c7x0_info(void);
int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
new file mode 100644
index 000000000..60d461182
--- /dev/null
+++ b/drivers/scsi/atari_dma_emul.c
@@ -0,0 +1,466 @@
+/*
+ * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
+ *
+ * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
+ *
+ * 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.
+ *
+ * This code was written using the Hades TOS source code as a
+ * reference. This source code can be found on the home page
+ * of Medusa Computer Systems.
+ *
+ * Version 0.1, 1997-09-24.
+ *
+ * This code should be considered experimental. It has only been
+ * tested on a Hades with a 68060. It might not work on a Hades
+ * with a 68040. Make backups of your hard drives before using
+ * this code.
+ */
+
+#include <asm/uaccess.h>
+
+#define hades_dma_ctrl (*(unsigned char *) 0xffff8717)
+#define hades_psdm_reg (*(unsigned char *) 0xffff8741)
+
+#define TRANSFER_SIZE 16
+
+struct m68040_frame {
+ unsigned long effaddr; /* effective address */
+ unsigned short ssw; /* special status word */
+ unsigned short wb3s; /* write back 3 status */
+ unsigned short wb2s; /* write back 2 status */
+ unsigned short wb1s; /* write back 1 status */
+ unsigned long faddr; /* fault address */
+ unsigned long wb3a; /* write back 3 address */
+ unsigned long wb3d; /* write back 3 data */
+ unsigned long wb2a; /* write back 2 address */
+ unsigned long wb2d; /* write back 2 data */
+ unsigned long wb1a; /* write back 1 address */
+ unsigned long wb1dpd0; /* write back 1 data/push data 0*/
+ unsigned long pd1; /* push data 1*/
+ unsigned long pd2; /* push data 2*/
+ unsigned long pd3; /* push data 3*/
+};
+
+static void writeback (unsigned short wbs, unsigned long wba,
+ unsigned long wbd, void *old_buserr)
+{
+ mm_segment_t fs = get_fs();
+ static void *save_buserr;
+
+ __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
+ "move.l %0,8(%%a0)\n\t"
+ :
+ : "r" (&&bus_error)
+ : "a0" );
+
+ save_buserr = old_buserr;
+
+ set_fs (MAKE_MM_SEG(wbs & WBTM_040));
+
+ switch (wbs & WBSIZ_040) {
+ case BA_SIZE_BYTE:
+ put_user (wbd & 0xff, (char *)wba);
+ break;
+ case BA_SIZE_WORD:
+ put_user (wbd & 0xffff, (short *)wba);
+ break;
+ case BA_SIZE_LONG:
+ put_user (wbd, (int *)wba);
+ break;
+ }
+
+ set_fs (fs);
+ return;
+
+bus_error:
+ __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
+ "bcs.s .jump_old\n\t"
+ "cmp.l %1,2(%%sp)\n\t"
+ "bls.s .restore_old\n"
+ ".jump_old:\n\t"
+ "move.l %2,-(%%sp)\n\t"
+ "rts\n"
+ ".restore_old:\n\t"
+ "move.l %%a0,-(%%sp)\n\t"
+ "movec.l %%vbr,%%a0\n\t"
+ "move.l %2,8(%%a0)\n\t"
+ "move.l (%%sp)+,%%a0\n\t"
+ "rte\n\t"
+ :
+ : "i" (writeback), "i" (&&bus_error),
+ "m" (save_buserr) );
+}
+
+/*
+ * static inline void set_restdata_reg(unsigned char *cur_addr)
+ *
+ * Set the rest data register if necessary.
+ */
+
+static inline void set_restdata_reg(unsigned char *cur_addr)
+{
+ if (((long) cur_addr & ~3) != 0)
+ tt_scsi_dma.dma_restdata =
+ *((unsigned long *) ((long) cur_addr & ~3));
+}
+
+/*
+ * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+ *
+ * This code emulates TT SCSI DMA on the Hades.
+ *
+ * Note the following:
+ *
+ * 1. When there is no byte available to read from the SCSI bus, or
+ * when a byte cannot yet bet written to the SCSI bus, a bus
+ * error occurs when reading or writing the pseudo DMA data
+ * register (hades_psdm_reg). We have to catch this bus error
+ * and try again to read or write the byte. If after several tries
+ * we still get a bus error, the interrupt handler is left. When
+ * the byte can be read or written, the interrupt handler is
+ * called again.
+ *
+ * 2. The SCSI interrupt must be disabled in this interrupt handler.
+ *
+ * 3. If we set the EOP signal, the SCSI controller still expects one
+ * byte to be read or written. Therefore the last byte is transferred
+ * separately, after setting the EOP signal.
+ *
+ * 4. When this function is left, the address pointer (start_addr) is
+ * converted to a physical address. Because it points one byte
+ * further than the last transfered byte, it can point outside the
+ * current page. If virt_to_phys() is called with this address we
+ * might get an access error. Therefore virt_to_phys() is called with
+ * start_addr - 1 if the count has reached zero. The result is
+ * increased with one.
+ */
+
+static void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+{
+ unsigned long dma_base;
+ register unsigned long dma_cnt asm ("d3");
+ static long save_buserr;
+ register unsigned long save_sp asm ("d4");
+ register int tries asm ("d5");
+ register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
+ register unsigned char *eff_addr;
+ register unsigned char *psdm_reg;
+ unsigned long rem;
+
+ atari_disable_irq(IRQ_TT_MFP_SCSI);
+
+ /*
+ * Read the dma address and count registers.
+ */
+
+ dma_base = SCSI_DMA_READ_P(dma_addr);
+ dma_cnt = SCSI_DMA_READ_P(dma_cnt);
+
+ /*
+ * Check if DMA is still enabled.
+ */
+
+ if ((tt_scsi_dma.dma_ctrl & 2) == 0)
+ {
+ atari_enable_irq(IRQ_TT_MFP_SCSI);
+ return;
+ }
+
+ if (dma_cnt == 0)
+ {
+ printk(KERN_NOTICE "DMA emulation: count is zero.\n");
+ tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
+ atari_enable_irq(IRQ_TT_MFP_SCSI);
+ return;
+ }
+
+ /*
+ * Install new bus error routine.
+ */
+
+ __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
+ "move.l 8(%%a0),%0\n\t"
+ "move.l %1,8(%%a0)\n\t"
+ : "=&r" (save_buserr)
+ : "r" (&&scsi_bus_error)
+ : "a0" );
+
+ hades_dma_ctrl &= 0xfc; /* Bus error and EOP off. */
+
+ /*
+ * Save the stack pointer.
+ */
+
+ __asm__ __volatile__ ("move.l %%sp,%0\n\t"
+ : "=&r" (save_sp) );
+
+ tries = 100; /* Maximum number of bus errors. */
+ start_addr = phys_to_virt(dma_base);
+ end_addr = start_addr + dma_cnt;
+
+scsi_loop:
+ dma_cnt--;
+ rem = dma_cnt & (TRANSFER_SIZE - 1);
+ dma_cnt &= ~(TRANSFER_SIZE - 1);
+ psdm_reg = &hades_psdm_reg;
+
+ if (tt_scsi_dma.dma_ctrl & 1) /* Read or write? */
+ {
+ /*
+ * SCSI write. Abort when count is zero.
+ */
+
+ switch (rem)
+ {
+ case 0:
+ while (dma_cnt > 0)
+ {
+ dma_cnt -= TRANSFER_SIZE;
+
+ *psdm_reg = *start_addr++;
+ case 15:
+ *psdm_reg = *start_addr++;
+ case 14:
+ *psdm_reg = *start_addr++;
+ case 13:
+ *psdm_reg = *start_addr++;
+ case 12:
+ *psdm_reg = *start_addr++;
+ case 11:
+ *psdm_reg = *start_addr++;
+ case 10:
+ *psdm_reg = *start_addr++;
+ case 9:
+ *psdm_reg = *start_addr++;
+ case 8:
+ *psdm_reg = *start_addr++;
+ case 7:
+ *psdm_reg = *start_addr++;
+ case 6:
+ *psdm_reg = *start_addr++;
+ case 5:
+ *psdm_reg = *start_addr++;
+ case 4:
+ *psdm_reg = *start_addr++;
+ case 3:
+ *psdm_reg = *start_addr++;
+ case 2:
+ *psdm_reg = *start_addr++;
+ case 1:
+ *psdm_reg = *start_addr++;
+ }
+ }
+
+ hades_dma_ctrl |= 1; /* Set EOP. */
+ udelay(10);
+ *psdm_reg = *start_addr++; /* Dummy byte. */
+ tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
+ }
+ else
+ {
+ /*
+ * SCSI read. Abort when count is zero.
+ */
+
+ switch (rem)
+ {
+ case 0:
+ while (dma_cnt > 0)
+ {
+ dma_cnt -= TRANSFER_SIZE;
+
+ *start_addr++ = *psdm_reg;
+ case 15:
+ *start_addr++ = *psdm_reg;
+ case 14:
+ *start_addr++ = *psdm_reg;
+ case 13:
+ *start_addr++ = *psdm_reg;
+ case 12:
+ *start_addr++ = *psdm_reg;
+ case 11:
+ *start_addr++ = *psdm_reg;
+ case 10:
+ *start_addr++ = *psdm_reg;
+ case 9:
+ *start_addr++ = *psdm_reg;
+ case 8:
+ *start_addr++ = *psdm_reg;
+ case 7:
+ *start_addr++ = *psdm_reg;
+ case 6:
+ *start_addr++ = *psdm_reg;
+ case 5:
+ *start_addr++ = *psdm_reg;
+ case 4:
+ *start_addr++ = *psdm_reg;
+ case 3:
+ *start_addr++ = *psdm_reg;
+ case 2:
+ *start_addr++ = *psdm_reg;
+ case 1:
+ *start_addr++ = *psdm_reg;
+ }
+ }
+
+ hades_dma_ctrl |= 1; /* Set EOP. */
+ udelay(10);
+ *start_addr++ = *psdm_reg;
+ tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
+
+ set_restdata_reg(start_addr);
+ }
+
+ if (start_addr != end_addr)
+ printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
+
+ dma_cnt = end_addr - start_addr;
+
+scsi_end:
+ dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :
+ virt_to_phys(start_addr);
+
+ SCSI_DMA_WRITE_P(dma_addr, dma_base);
+ SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
+
+ /*
+ * Restore old bus error routine.
+ */
+
+ __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
+ "move.l %0,8(%%a0)\n\t"
+ :
+ : "r" (save_buserr)
+ : "a0" );
+
+ atari_enable_irq(IRQ_TT_MFP_SCSI);
+
+ return;
+
+scsi_bus_error:
+ /*
+ * First check if the bus error is caused by our code.
+ * If not, call the original handler.
+ */
+
+ __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
+ "bcs.s .old_vector\n\t"
+ "cmp.l %1,2(%%sp)\n\t"
+ "bls.s .scsi_buserr\n"
+ ".old_vector:\n\t"
+ "move.l %2,-(%%sp)\n\t"
+ "rts\n"
+ ".scsi_buserr:\n\t"
+ :
+ : "i" (&&scsi_loop), "i" (&&scsi_end),
+ "m" (save_buserr) );
+
+ if (CPU_IS_060)
+ {
+ /*
+ * Get effective address and restore the stack.
+ */
+
+ __asm__ __volatile__ ("move.l 8(%%sp),%0\n\t"
+ "move.l %1,%%sp\n\t"
+ : "=a&" (eff_addr)
+ : "r" (save_sp) );
+ }
+ else
+ {
+ register struct m68040_frame *frame;
+
+ __asm__ __volatile__ ("lea 8(%%sp),%0\n\t"
+ : "=a&" (frame) );
+
+ if (tt_scsi_dma.dma_ctrl & 1)
+ {
+ /*
+ * Bus error while writing.
+ */
+
+ if (frame->wb3s & WBV_040)
+ {
+ if (frame->wb3a == (long) &hades_psdm_reg)
+ start_addr--;
+ else
+ writeback(frame->wb3s, frame->wb3a,
+ frame->wb3d, &&scsi_bus_error);
+ }
+
+ if (frame->wb2s & WBV_040)
+ {
+ if (frame->wb2a == (long) &hades_psdm_reg)
+ start_addr--;
+ else
+ writeback(frame->wb2s, frame->wb2a,
+ frame->wb2d, &&scsi_bus_error);
+ }
+
+ if (frame->wb1s & WBV_040)
+ {
+ if (frame->wb1a == (long) &hades_psdm_reg)
+ start_addr--;
+ }
+ }
+ else
+ {
+ /*
+ * Bus error while reading.
+ */
+
+ if (frame->wb3s & WBV_040)
+ writeback(frame->wb3s, frame->wb3a,
+ frame->wb3d, &&scsi_bus_error);
+ }
+
+ eff_addr = (unsigned char *) frame->faddr;
+
+ __asm__ __volatile__ ("move.l %0,%%sp\n\t"
+ :
+ : "r" (save_sp) );
+ }
+
+ dma_cnt = end_addr - start_addr;
+
+ if (eff_addr == &hades_psdm_reg)
+ {
+ /*
+ * Bus error occured while reading the pseudo
+ * DMA register. Time out.
+ */
+
+ tries--;
+
+ if (tries <= 0)
+ {
+ if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
+ set_restdata_reg(start_addr);
+
+ if (dma_cnt <= 1)
+ printk(KERN_CRIT "DMA emulation: Fatal "
+ "error while %s the last byte.\n",
+ (tt_scsi_dma.dma_ctrl & 1)
+ ? "writing" : "reading");
+
+ goto scsi_end;
+ }
+ else
+ goto scsi_loop;
+ }
+ else
+ {
+ /*
+ * Bus error during pseudo DMA transfer.
+ * Terminate the DMA transfer.
+ */
+
+ hades_dma_ctrl |= 3; /* Set EOP and bus error. */
+ if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
+ set_restdata_reg(start_addr);
+ goto scsi_end;
+ }
+}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 50ce159a2..8c43432a7 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -107,6 +107,7 @@
#include "NCR5380.h"
#include "constants.h"
#include <asm/atari_stdma.h>
+#include <asm/atari_stram.h>
#include <asm/io.h>
#include <linux/stat.h>
@@ -255,6 +256,10 @@ static int setup_hostid = -1;
MODULE_PARM(setup_hostid, "i");
+#if defined(CONFIG_TT_DMA_EMUL)
+#include "atari_dma_emul.c"
+#endif
+
#if defined(REAL_DMA)
static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
@@ -652,8 +657,12 @@ int atari_scsi_detect (Scsi_Host_Template *host)
*/
if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
!ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
- atari_dma_buffer = scsi_init_malloc(STRAM_BUFFER_SIZE,
- GFP_ATOMIC | GFP_DMA);
+ atari_dma_buffer = atari_stram_alloc( STRAM_BUFFER_SIZE, NULL, "SCSI" );
+ if (!atari_dma_buffer) {
+ printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+ "double buffer\n" );
+ return( 0 );
+ }
atari_dma_phys_buffer = VTOP( atari_dma_buffer );
atari_dma_orig_addr = 0;
}
@@ -682,7 +691,14 @@ int atari_scsi_detect (Scsi_Host_Template *host)
atari_dma_residual = 0;
#endif /* REAL_DMA */
#ifdef REAL_DMA
- if (is_medusa || is_hades) {
+#ifdef CONFIG_TT_DMA_EMUL
+ if (MACH_IS_HADES) {
+ request_irq(IRQ_AUTO_2, hades_dma_emulator,
+ IRQ_TYPE_PRIO, "Hades DMA emulator",
+ hades_dma_emulator);
+ }
+#endif
+ if (MACH_IS_MEDUSA || MACH_IS_HADES) {
/* While the read overruns (described by Drew Eckhardt in
* NCR5380.c) never happened on TTs, they do in fact on the Medusa
* (This was the cause why SCSI didn't work right for so long
@@ -739,7 +755,7 @@ int atari_scsi_release (struct Scsi_Host *sh)
if (IS_A_TT())
free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
if (atari_dma_buffer)
- scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE);
+ atari_stram_free (atari_dma_buffer);
return 1;
}
#endif
@@ -1003,11 +1019,11 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
int write_flag )
{
unsigned long possible_len, limit;
-
- if (is_hades)
+#ifndef CONFIG_TT_DMA_EMUL
+ if (MACH_IS_HADES)
/* Hades has no SCSI DMA at all :-( Always force use of PIO */
return( 0 );
-
+#endif
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
return( wanted_len );
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 165a68e60..b1fa60b11 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -199,14 +199,22 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static int num_gvp11 = 0;
+#define CHECK_WD33C93
+
__initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
struct Scsi_Host *instance;
caddr_t address;
- enum GVP_ident epc;
- int key = 0;
- struct ConfigDev *cd;
+ unsigned int epc;
+ unsigned int key = 0, skey;
+ const struct ConfigDev *cd;
+ unsigned int default_dma_xfer_mask;
+#ifdef CHECK_WD33C93
+ volatile unsigned char *sasr_3393, *scmd_3393;
+ unsigned char save_sasr;
+ unsigned char q, qq;
+#endif
if (!MACH_IS_AMIGA || called)
return 0;
@@ -215,7 +223,27 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
tpnt->proc_dir = &proc_scsi_gvp11;
tpnt->proc_info = &wd33c93_proc_info;
- while ((key = zorro_find(MANUF_GVP, PROD_GVPIISCSI, 0, key))) {
+ while (1) {
+ /*
+ * This should (hopefully) be the correct way to identify
+ * all the different GVP SCSI controllers (except for the
+ * SERIES I though).
+ */
+ skey = key;
+
+ if ((key = zorro_find(ZORRO_PROD_GVP_COMBO_030_R3_SCSI, 0, skey)) ||
+ (key = zorro_find(ZORRO_PROD_GVP_SERIES_II, 0, skey)))
+ default_dma_xfer_mask = ~0x00ffffff;
+ else if ((key = zorro_find(ZORRO_PROD_GVP_GFORCE_030_SCSI, 0, skey)) ||
+ (key = zorro_find(ZORRO_PROD_GVP_A530_SCSI, 0, skey)) ||
+ (key = zorro_find(ZORRO_PROD_GVP_COMBO_030_R4_SCSI, 0, skey)))
+ default_dma_xfer_mask = ~0x01ffffff;
+ else if ((key = zorro_find(ZORRO_PROD_GVP_A1291, 0, skey)) ||
+ (key = zorro_find(ZORRO_PROD_GVP_GFORCE_040_SCSI_1, 0, skey)))
+ default_dma_xfer_mask = ~0x07ffffff;
+ else
+ break;
+
cd = zorro_get_board(key);
address = cd->cd_BoardAddr;
@@ -227,23 +255,77 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
if (cd->cd_BoardSize != 0x10000)
continue;
- /* check extended product code */
- epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
- epc = epc & GVP_PRODMASK;
+#ifdef CHECK_WD33C93
- /*
- * This should (hopefully) be the correct way to identify
- * all the different GVP SCSI controllers (except for the
- * SERIES I though).
+ /*
+ * These darn GVP boards are a problem - it can be tough to tell
+ * whether or not they include a SCSI controller. This is the
+ * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+ * probes for a WD33c93 chip: If we find one, it's extremely
+ * likely that this card supports SCSI, regardless of Product_
+ * Code, Board_Size, etc.
*/
- if (!((epc == GVP_A1291_SCSI) ||
- (epc == GVP_GFORCE_040_SCSI) ||
- (epc == GVP_GFORCE_030_SCSI) ||
- (epc == GVP_A530_SCSI) ||
- (epc == GVP_COMBO_R4_SCSI) ||
- (epc == GVP_COMBO_R3_SCSI) ||
- (epc == GVP_SERIESII)))
- continue;
+
+ /* Get pointers to the presumed register locations and save contents */
+
+ sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
+ scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
+ save_sasr = *sasr_3393;
+
+ /* First test the AuxStatus Reg */
+
+ q = *sasr_3393; /* read it */
+ if (q & 0x08) /* bit 3 should always be clear */
+ continue;
+ *sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */
+ if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
+ *sasr_3393 = save_sasr; /* Oops - restore this byte */
+ continue;
+ }
+ if (*sasr_3393 != q) { /* should still read the same */
+ *sasr_3393 = save_sasr; /* Oops - restore this byte */
+ continue;
+ }
+ if (*scmd_3393 != q) /* and so should the image at 0x1f */
+ continue;
+
+
+ /* Ok, we probably have a wd33c93, but let's check a few other places
+ * for good measure. Make sure that this works for both 'A and 'B
+ * chip versions.
+ */
+
+ *sasr_3393 = WD_SCSI_STATUS;
+ q = *scmd_3393;
+ *sasr_3393 = WD_SCSI_STATUS;
+ *scmd_3393 = ~q;
+ *sasr_3393 = WD_SCSI_STATUS;
+ qq = *scmd_3393;
+ *sasr_3393 = WD_SCSI_STATUS;
+ *scmd_3393 = q;
+ if (qq != q) /* should be read only */
+ continue;
+ *sasr_3393 = 0x1e; /* this register is unimplemented */
+ q = *scmd_3393;
+ *sasr_3393 = 0x1e;
+ *scmd_3393 = ~q;
+ *sasr_3393 = 0x1e;
+ qq = *scmd_3393;
+ *sasr_3393 = 0x1e;
+ *scmd_3393 = q;
+ if (qq != q || qq != 0xff) /* should be read only, all 1's */
+ continue;
+ *sasr_3393 = WD_TIMEOUT_PERIOD;
+ q = *scmd_3393;
+ *sasr_3393 = WD_TIMEOUT_PERIOD;
+ *scmd_3393 = ~q;
+ *sasr_3393 = WD_TIMEOUT_PERIOD;
+ qq = *scmd_3393;
+ *sasr_3393 = WD_TIMEOUT_PERIOD;
+ *scmd_3393 = q;
+ if (qq != (~q & 0xff)) /* should be read/write */
+ continue;
+#endif
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
instance->base = (unsigned char *)ZTWO_VADDR(address);
@@ -252,22 +334,9 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
if (gvp11_xfer_mask)
HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
- else{
- switch (epc){
- case GVP_COMBO_R3_SCSI:
- case GVP_SERIESII:
- HDATA(instance)->dma_xfer_mask = ~0x00ffffff;
- break;
- case GVP_GFORCE_030_SCSI:
- case GVP_A530_SCSI:
- case GVP_COMBO_R4_SCSI:
- HDATA(instance)->dma_xfer_mask = ~0x01ffffff;
- break;
- default:
- HDATA(instance)->dma_xfer_mask = ~0x07ffffff;
- break;
- }
- }
+ else
+ HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;
+
DMA(instance)->secret2 = 1;
DMA(instance)->secret1 = 0;
@@ -283,16 +352,17 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
* Check for 14MHz SCSI clock
*/
if (epc & GVP_SCSICLKMASK)
- wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
- dma_setup, dma_stop, WD33C93_FS_8_10);
+ wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
+ dma_setup, dma_stop, WD33C93_FS_8_10);
else
- wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
- dma_setup, dma_stop, WD33C93_FS_12_15);
+ wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
+ dma_setup, dma_stop, WD33C93_FS_12_15);
if (num_gvp11++ == 0) {
- first_instance = instance;
- gvp11_template = instance->hostt;
- request_irq(IRQ_AMIGA_PORTS, gvp11_intr, 0, "GVP11 SCSI", gvp11_intr);
+ first_instance = instance;
+ gvp11_template = instance->hostt;
+ request_irq(IRQ_AMIGA_PORTS, gvp11_intr, 0,
+ "GVP11 SCSI", gvp11_intr);
}
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
zorro_config_board(key, 0);
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
new file mode 100644
index 000000000..c3ab67906
--- /dev/null
+++ b/drivers/scsi/mvme16x.c
@@ -0,0 +1,60 @@
+/*
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mvme16xhw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "mvme16x.h"
+#include "asm/mvme16xhw.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_mvme16x = {
+ PROC_SCSI_MVME16x, 7, "MVME16x",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+ u32 base, int io_port, int irq, int dma,
+ long long options, int clock);
+
+int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
+{
+ static unsigned char called = 0;
+ int clock;
+ long long options;
+
+ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+ printk ("SCSI detection disabled, SCSI chip not present\n");
+ return 0;
+ }
+ if (called)
+ return 0;
+
+ tpnt->proc_dir = &proc_scsi_mvme16x;
+
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 66000000; /* 66MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)0xfff47000,
+ 0, 0x55, DMA_NONE,
+ options, clock);
+ called = 1;
+ return 1;
+}
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
new file mode 100644
index 000000000..1bebf337c
--- /dev/null
+++ b/drivers/scsi/mvme16x.h
@@ -0,0 +1,53 @@
+#ifndef MVME16x_SCSI_H
+#define MVME16x_SCSI_H
+
+#include <linux/types.h>
+
+int mvme16x_scsi_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_mvme16x;
+
+#define MVME16x_SCSI {/* next */ NULL, \
+ /* usage_count */ NULL, \
+ /* proc_dir_entry */ NULL, \
+ /* proc_info */ NULL, \
+ /* name */ "MVME16x SCSI", \
+ /* detect */ mvme16x_scsi_detect, \
+ /* release */ NULL, \
+ /* info */ NULL, \
+ /* command */ NULL, \
+ /* queuecommand */ NCR53c7xx_queue_command, \
+ /* abort */ NCR53c7xx_abort, \
+ /* reset */ NCR53c7xx_reset, \
+ /* slave_attach */ NULL, \
+ /* bios_param */ NULL /*scsicam_bios_param*/, \
+ /* can_queue */ 24, \
+ /* this_id */ 7, \
+ /* sg_tablesize */ 127, \
+ /* cmd_per_lun */ 3, \
+ /* present */ 0, \
+ /* unchecked_isa_dma */ 0, \
+ /* use_clustering */ DISABLE_CLUSTERING }
+#endif
+#endif /* MVME16x_SCSI_H */
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index fa0dc8f06..9826fb990 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -312,7 +312,14 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#define ASKED_FOR_SENSE 0x20
+#ifdef __mc68000__
+#include <asm/pgtable.h>
+#define CONTIGUOUS_BUFFERS(X,Y) \
+ (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))
+#else
#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+#endif
+
/*
* This is the crap from the old error handling code. We have it in a special
@@ -455,14 +462,6 @@ struct scsi_device {
unsigned device_blocked:1; /* Device returned QUEUE_FULL. */
};
-#ifdef __mc68000__
-#include <asm/pgtable.h>
-#define CONTIGUOUS_BUFFERS(X,Y) \
- (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))
-#else
-#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
-#endif
-
/*
* The Scsi_Cmnd structure is used by scsi.c internally, and for communication
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index ce448de91..afd9fd6a9 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -1,10 +1,13 @@
-/* $Id: sgiwd93.c,v 1.4 1998/03/04 10:49:47 ralf Exp $
+/*
* sgiwd93.c: SGI WD93 scsi driver.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* (In all truth, Jed Schimmel wrote all this code.)
+ *
+ * $Id: sgiwd93.c,v 1.7 1996/07/23 09:00:16 dm Exp $
*/
+#include <linux/init.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blk.h>
@@ -214,7 +217,7 @@ static inline void init_hpc_chain(uchar *buf)
hcp->desc.pnext = PHYSADDR(buf);
}
-int sgiwd93_detect(Scsi_Host_Template *HPsUX)
+__initfunc(int sgiwd93_detect(Scsi_Host_Template *HPsUX))
{
static unsigned char called = 0;
struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0;
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 6d60d12ae..6946cc788 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -1490,7 +1490,7 @@ int wd33c93_abort (Scsi_Cmnd *cmd)
}
#define MAX_WD33C93_HOSTS 4
-#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *))
+#define MAX_SETUP_ARGS ((int)(sizeof(setup_args) / sizeof(char *)))
#define SETUP_BUFFER_SIZE 200
static char setup_buffer[SETUP_BUFFER_SIZE];
static char setup_used[MAX_SETUP_ARGS];
diff --git a/drivers/sgi/char/cons_newport.c b/drivers/sgi/char/cons_newport.c
index b8a7f958d..b49ba172b 100644
--- a/drivers/sgi/char/cons_newport.c
+++ b/drivers/sgi/char/cons_newport.c
@@ -3,9 +3,9 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: cons_newport.c,v 1.7 1998/03/03 01:23:05 ralf Exp $
+ * $Id: cons_newport.c,v 1.8 1998/03/03 16:57:28 ralf Exp $
*/
-
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
@@ -573,8 +573,7 @@ struct graphics_ops newport_graphic_ops = {
newport_reset, newport_ioctl /* g_reset_console, g_ioctl */
};
-struct graphics_ops *
-newport_probe (int slot, const char **name)
+__initfunc(struct graphics_ops * newport_probe (int slot, const char **name))
{
struct newport_regs *p;
diff --git a/drivers/sgi/char/graphics.c b/drivers/sgi/char/graphics.c
index 663d124fa..3f9a80d14 100644
--- a/drivers/sgi/char/graphics.c
+++ b/drivers/sgi/char/graphics.c
@@ -22,6 +22,7 @@
* the reasons behind them.
*/
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -292,15 +293,13 @@ static struct miscdevice dev_opengl = {
};
/* This is called later from the misc-init routine */
-void
-gfx_register (void)
+__initfunc(void gfx_register (void))
{
misc_register (&dev_graphics);
misc_register (&dev_opengl);
}
-void
-gfx_init (const char **name)
+__initfunc(void gfx_init (const char **name))
{
struct console_ops *console;
struct graphics_ops *g;
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index e377d3241..12176d6d2 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -1,6 +1,9 @@
-/* sgiserial.c: Serial port driver for SGI machines.
+/*
+ * sgiserial.c: Serial port driver for SGI machines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id$
*/
#include <linux/config.h> /* for CONFIG_REMOTE_DEBUG */
diff --git a/drivers/sgi/char/streamable.c b/drivers/sgi/char/streamable.c
index f26aad0e2..02129fde4 100644
--- a/drivers/sgi/char/streamable.c
+++ b/drivers/sgi/char/streamable.c
@@ -5,9 +5,10 @@
* Major 10 is the streams clone device. The IRIX Xsgi server just
* opens /dev/gfx and closes it inmediately.
*
+ * $Id$
*/
-
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/kbd_kern.h>
@@ -351,8 +352,7 @@ static struct miscdevice dev_input_mouse = {
SGI_STREAMS_KEYBOARD, "streams-mouse", &sgi_mouse_fops
};
-void
-streamable_init (void)
+__initfunc(void streamable_init (void))
{
printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n",
SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR);
diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c
index dfef772eb..83a26a717 100644
--- a/drivers/sgi/char/usema.c
+++ b/drivers/sgi/char/usema.c
@@ -20,9 +20,10 @@
* usema(7m), usinit(3p), usnewsema(3p)
* /usr/include/sys/usioctl.h
*
-*/
-
+ * $Id$
+ */
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/file.h>
@@ -186,8 +187,7 @@ static struct miscdevice dev_usemaclone = {
SGI_USEMACLONE, "usemaclone", &sgi_usemaclone_fops
};
-void
-usema_init(void)
+__initfunc(void usema_init(void))
{
printk("usemaclone misc device registered (minor: %d)\n",
SGI_USEMACLONE);
diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c
index bf95b84d5..e00108b0b 100644
--- a/drivers/sound/pas2_card.c
+++ b/drivers/sound/pas2_card.c
@@ -164,7 +164,7 @@ static int config_pas_hw(struct address_info *hw_config)
}
else
{
- if (request_irq(pas_irq, pasintr, "PAS16", 0, NULL) < 0)
+ if (request_irq(pas_irq, pasintr, 0, "PAS16", NULL) < 0)
ok = 0;
}
}
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index e39e33bfc..b4766876b 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -7,43 +7,70 @@ if [ "$CONFIG_FB" = "y" ]; then
mainmenu_option next_comment
comment 'Frame buffer devices'
- if [ "$CONFIG_AMIGA" = "y" ]; then
+ if [ "$CONFIG_APOLLO" = "y" ]; then
+ define_bool CONFIG_FB_APOLLO y
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
bool 'Amiga native chipset support' CONFIG_FB_AMIGA
if [ "$CONFIG_FB_AMIGA" != "n" ]; then
bool 'Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
bool 'Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
bool 'Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
fi
- tristate 'Amiga Cybervision support' CONFIG_FB_CYBER
+ tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
bool 'Atari native chipset support' CONFIG_FB_ATARI
-# tristate 'Mach64 Frame Buffer support' CONFIG_FB_MACH64
+ bool 'ATI Mach64 display support' CONFIG_FB_ATY
+ fi
+ if [ "$CONFIG_PPC" = "y" ]; then
+ bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
+ bool 'S3 Trio frame buffer device support' CONFIG_FB_S3TRIO
+ if [ "$CONFIG_FB_OF" = "y" ]; then
+# 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
+# bool 'Chips 65550 display support' CONFIG_FB_CT65550
+# bool 'S3 Trio display support' CONFIG_FB_S3TRIO
+ fi
+ fi
+ if [ "$CONFIG_MAC" = "y" ]; then
+ define_bool CONFIG_FB_MAC y
+ fi
+ if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
+ define_bool CONFIG_FB_TGA y
fi
- if [ "$CONFIG_CHRP" = "y" -o "$CONFIG_PMAC" = "y" ]; then
- bool 'Open Firmware frame buffer device support' CONFIG_FB_OPEN_FIRMWARE
- fi
- tristate 'Virtual Frame Buffer support' CONFIG_FB_VIRTUAL
+ tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED
if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
- tristate 'Monochrome support' CONFIG_FBCON_MFB
- tristate 'Interleaved bitplanes support' CONFIG_FBCON_ILBM
- tristate 'Normal bitplanes support' CONFIG_FBCON_AFB
- tristate 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
- tristate 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
- tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
- tristate '8 bpp packed pixel support' CONFIG_FBCON_CFB8
- tristate '16 bpp packed pixel support' CONFIG_FBCON_CFB16
- tristate 'Cybervision support (accelerated)' CONFIG_FBCON_CYBER
- tristate 'RetinaZ3 support (accelerated)' CONFIG_FBCON_RETINAZ3
+ bool 'Monochrome support' CONFIG_FBCON_MFB
+ bool '2 bpp packed pixels support' CONFIG_FBCON_CFB2
+ bool '4 bpp packed pixels support' CONFIG_FBCON_CFB4
+ bool '8 bpp packed pixels support' CONFIG_FBCON_CFB8
+ bool '16 bpp packed pixels support' CONFIG_FBCON_CFB16
+ bool '24 bpp packed pixels support' CONFIG_FBCON_CFB24
+ bool '32 bpp packed pixels support' CONFIG_FBCON_CFB32
+ bool 'Amiga bitplanes support' CONFIG_FBCON_AFB
+ bool 'Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
+ bool 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
+ bool 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
+ bool 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
+ bool 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
else
- if [ "$CONFIG_FB_AMIGA" != "n" -o "$CONFIG_FB_ATARI" != "n" -o \
- "$CONFIG_FB_CYBER" != "n" -o "$CONFIG_FB_RETINAZ3" != "n" -o \
- "$CONFIG_FB_VIRTUAL" != "n" ]; then
+ if [ "$CONFIG_FB_AMIGA" = "y" -o "$CONFIG_FB_AMIGA" = "m" -o \
+ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
+ "$CONFIG_FB_CYBER" = "y" -o "$CONFIG_FB_CYBER" = "m" -o \
+ "$CONFIG_FB_RETINAZ3" = "y" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRGE" = "m" -o \
+ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_MFB y
fi
if [ "$CONFIG_FB_AMIGA" = "y" -o "$CONFIG_FB_AMIGA" = "m" ]; then
@@ -55,20 +82,32 @@ if [ "$CONFIG_FB" = "y" ]; then
define_bool CONFIG_FBCON_IPLAN2P4 y
define_bool CONFIG_FBCON_IPLAN2P8 y
fi
+ if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ define_bool CONFIG_FBCON_MAC y
+ define_bool CONFIG_FBCON_CFB2 y
+ define_bool CONFIG_FBCON_CFB4 y
+ fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
- "$CONFIG_FB_OPEN_FIRMWARE" = "y" -o \
+ "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_OF" = "m" -o \
+ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_TGA" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_CFB8 y
fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
+ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_ATY" = "m" -o \
+ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_CFB16 y
fi
- if [ "$CONFIG_FB_CYBER" = "y" -o "$CONFIG_FB_CYBER" = "m" ]; then
- define_bool CONFIG_FBCON_CYBER y
+ if [ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB24 y
fi
- if [ "$CONFIG_FB_RETINAZ3" = "y" -o "$CONFIG_FB_RETINAZ3" = "m" ]; then
- define_bool CONFIG_FBCON_RETINAZ3 y
+ if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
+ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_ATY" = "m" -o \
+ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB32 y
fi
fi
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ebed69d68..2349e4720 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -22,15 +22,11 @@ MOD_LIST_NAME := VIDEO_MODULES
# Frame Buffer Console
ifeq ($(CONFIG_FB),y)
- L_OBJS += fonts.o font_8x8.o font_8x16.o pearl_8x8.o
- LX_OBJS += fbcon.o fbcmap.o
+ L_OBJS += fonts.o font_8x8.o font_8x16.o pearl_8x8.o font_6x11.o
+ LX_OBJS += fbcon.o fbcmap.o fbgen.o
endif
-# Frame buffer devices
-
-ifeq ($(CONFIG_APOLLO),y)
-L_OBJS += dn_fb.o
-endif
+# Frame Buffer Devices
ifeq ($(CONFIG_FB_AMIGA),y)
L_OBJS += amifb.o
@@ -40,6 +36,10 @@ else
endif
endif
+ifeq ($(CONFIG_FB_APOLLO),y)
+L_OBJS += dnfb.o
+endif
+
ifeq ($(CONFIG_FB_ATARI),y)
L_OBJS += atafb.o
else
@@ -48,134 +48,114 @@ else
endif
endif
+ifeq ($(CONFIG_FB_ATY),y)
+L_OBJS += atyfb.o
+endif
+
ifeq ($(CONFIG_FB_CYBER),y)
-LX_OBJS += cyberfb.o
+L_OBJS += cyberfb.o
else
ifeq ($(CONFIG_FB_CYBER),m)
- MX_OBJS += cyberfb.o
+ M_OBJS += cyberfb.o
endif
endif
+ifeq ($(CONFIG_FB_MAC),y)
+L_OBJS += macfb.o
+endif
+
+ifeq ($(CONFIG_FB_OF),y)
+L_OBJS += offb.o
+endif
+
ifeq ($(CONFIG_FB_RETINAZ3),y)
-LX_OBJS += retz3fb.o
+L_OBJS += retz3fb.o
else
ifeq ($(CONFIG_FB_RETINAZ3),m)
- MX_OBJS += retz3fb.o
+ M_OBJS += retz3fb.o
endif
endif
-ifeq ($(CONFIG_FB_VIRTUAL),y)
-L_OBJS += vfb.o
+ifeq ($(CONFIG_FB_S3TRIO),y)
+L_OBJS += S3triofb.o
else
- ifeq ($(CONFIG_FB_VIRTUAL),m)
- M_OBJS += vfb.o
+ ifeq ($(CONFIG_FB_S3TRIO),m)
+ M_OBJS += S3triofb.o
endif
endif
-ifeq ($(CONFIG_FB_OPEN_FIRMWARE),y)
-L_OBJS += offb.o
+ifeq ($(CONFIG_FB_TGA),y)
+L_OBJS += tgafb.o
endif
-ifeq ($(CONFIG_FB_MACH64),y)
-L_OBJS += mach64fb.o
+ifeq ($(CONFIG_FB_VIRGE),y)
+L_OBJS += virgefb.o
else
- ifeq ($(CONFIG_FB_MACH64),m)
- M_OBJS += mach64fb.o
+ ifeq ($(CONFIG_FB_VIRGE),m)
+ M_OBJS += virgefb.o
endif
endif
-ifeq ($(CONFIG_FB_TGA),y)
-L_OBJS += tgafb.o
+ifeq ($(CONFIG_FB_VIRTUAL),y)
+L_OBJS += vfb.o
+else
+ ifeq ($(CONFIG_FB_VIRTUAL),m)
+ M_OBJS += vfb.o
+ endif
endif
-# Low level drivers
+# Generic Low Level Drivers
-ifeq ($(CONFIG_FBCON_AFB),y)
-L_OBJS += fbcon-afb.o
-else
- ifeq ($(CONFIG_FBCON_AFB),m)
- M_OBJS += fbcon-afb.o
- endif
+ifdef CONFIG_FBCON_AFB
+LX_OBJS += fbcon-afb.o
endif
-ifeq ($(CONFIG_FBCON_CFB8),y)
-L_OBJS += fbcon-cfb8.o
-else
- ifeq ($(CONFIG_FBCON_CFB8),m)
- M_OBJS += fbcon-cfb8.o
- endif
+ifdef CONFIG_FBCON_CFB2
+LX_OBJS += fbcon-cfb2.o
endif
-ifeq ($(CONFIG_FBCON_CFB16),y)
+ifdef CONFIG_FBCON_CFB4
+LX_OBJS += fbcon-cfb4.o
+endif
+
+ifdef CONFIG_FBCON_CFB8
+LX_OBJS += fbcon-cfb8.o
+endif
+
+ifdef CONFIG_FBCON_CFB16
LX_OBJS += fbcon-cfb16.o
-else
- ifeq ($(CONFIG_FBCON_CFB16),m)
- MX_OBJS += fbcon-cfb16.o
- endif
endif
-ifeq ($(CONFIG_FBCON_ILBM),y)
-L_OBJS += fbcon-ilbm.o
-else
- ifeq ($(CONFIG_FBCON_ILBM),m)
- M_OBJS += fbcon-ilbm.o
- endif
+ifdef CONFIG_FBCON_CFB24
+LX_OBJS += fbcon-cfb24.o
endif
-ifeq ($(CONFIG_FBCON_IPLAN2P2),y)
-L_OBJS += fbcon-iplan2p2.o
-else
- ifeq ($(CONFIG_FBCON_IPLAN2P2),m)
- M_OBJS += fbcon-iplan2p2.o
- endif
+ifdef CONFIG_FBCON_CFB32
+LX_OBJS += fbcon-cfb32.o
endif
-ifeq ($(CONFIG_FBCON_IPLAN2P4),y)
-L_OBJS += fbcon-iplan2p4.o
-else
- ifeq ($(CONFIG_FBCON_IPLAN2P4),m)
- M_OBJS += fbcon-iplan2p4.o
- endif
+ifdef CONFIG_FBCON_ILBM
+LX_OBJS += fbcon-ilbm.o
endif
-ifeq ($(CONFIG_FBCON_IPLAN2P8),y)
-L_OBJS += fbcon-iplan2p8.o
-else
- ifeq ($(CONFIG_FBCON_IPLAN2P8),m)
- M_OBJS += fbcon-iplan2p8.o
- endif
+ifdef CONFIG_FBCON_IPLAN2P2
+LX_OBJS += fbcon-iplan2p2.o
endif
-ifeq ($(CONFIG_FBCON_MFB),y)
-L_OBJS += fbcon-mfb.o
-else
- ifeq ($(CONFIG_FBCON_MFB),m)
- M_OBJS += fbcon-mfb.o
- endif
+ifdef CONFIG_FBCON_IPLAN2P4
+LX_OBJS += fbcon-iplan2p4.o
endif
-ifeq ($(CONFIG_FBCON_CYBER),y)
-L_OBJS += fbcon-cyber.o
-else
- ifeq ($(CONFIG_FBCON_CYBER),m)
- M_OBJS += fbcon-cyber.o
- endif
+ifdef CONFIG_FBCON_IPLAN2P8
+LX_OBJS += fbcon-iplan2p8.o
endif
-ifeq ($(CONFIG_FBCON_RETINAZ3),y)
-L_OBJS += fbcon-retz3.o
-else
- ifeq ($(CONFIG_FBCON_RETINAZ3),m)
- M_OBJS += fbcon-retz3.o
- endif
+ifdef CONFIG_FBCON_MAC
+LX_OBJS += fbcon-mac.o
endif
-ifeq ($(CONFIG_FBCON_MACH64),y)
-L_OBJS += fbcon-mach64.o
-else
- ifeq ($(CONFIG_FBCON_MACH64),m)
- M_OBJS += fbcon-mach64.o
- endif
+ifdef CONFIG_FBCON_MFB
+LX_OBJS += fbcon-mfb.o
endif
# GSP Console
@@ -184,7 +164,7 @@ ifdef CONFIG_AMIGA_GSP
L_OBJS := $(L_OBJS) gspcon.o gspcore.o
endif
-# VGA Console
+# VGA Text Console
ifdef CONFIG_ABSTRACT_CONSOLE
ifdef CONFIG_VGA_CONSOLE
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
new file mode 100644
index 000000000..16c0b888a
--- /dev/null
+++ b/drivers/video/S3triofb.c
@@ -0,0 +1,885 @@
+/*
+ * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
+ *
+ * Copyright (C) 1997 Peter De Schrijver
+ *
+ * This driver is partly based on the PowerMac console driver:
+ *
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * and on the Open Firmware based frame buffer device:
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+/*
+ Bugs : + OF dependencies should be removed.
+ + This driver should be merged with the CyberVision driver. The
+ CyberVision is a Zorro III implementation of the S3Trio64 chip.
+
+*/
+
+#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/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <linux/pci.h>
+
+#include "fbcon-cfb8.h"
+
+
+#define mem_in8(addr) in_8((void *)(addr))
+#define mem_in16(addr) in_le16((void *)(addr))
+#define mem_in32(addr) in_le32((void *)(addr))
+
+#define mem_out8(val, addr) out_8((void *)(addr), val)
+#define mem_out16(val, addr) out_le16((void *)(addr), val)
+#define mem_out32(val, addr) out_le32((void *)(addr), val)
+
+#define IO_OUT16VAL(v, r) (((v) << 8) | (r))
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+static int currcon = 0;
+static struct display disp;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[256];
+static char s3trio_name[16] = "S3Trio ";
+
+
+static struct fb_fix_screeninfo fb_fix;
+static struct fb_var_screeninfo fb_var = { 0, };
+
+
+ /*
+ * Interface used by the world
+ */
+
+void of_video_setup(char *options, int *ints);
+
+static int s3trio_open(struct fb_info *info);
+static int s3trio_release(struct fb_info *info);
+static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+ struct fb_info *);
+static int s3trio_console_setmode(struct vc_mode *mode, int doit);
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+ /*
+ * Interface to the low level console driver
+ */
+
+unsigned long s3trio_fb_init(unsigned long mem_start);
+static int s3triofbcon_switch(int con, struct fb_info *info);
+static int s3triofbcon_updatevar(int con, struct fb_info *info);
+static void s3triofbcon_blank(int blank, struct fb_info *info);
+static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
+
+ /*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static struct display_switch fbcon_trio8;
+#endif
+
+ /*
+ * Accelerated Functions used by the low level console driver
+ */
+
+static void Trio_WaitQueue(u_short fifo);
+static void Trio_WaitBlit(void);
+static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
+ u_short desty, u_short width, u_short height,
+ u_short mode);
+static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
+ u_short mode, u_short color);
+static void Trio_MoveCursor(u_short x, u_short y);
+
+
+ /*
+ * Internal routines
+ */
+
+static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+static int s3trio_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);
+
+
+static struct fb_ops s3trio_ops = {
+ s3trio_open, s3trio_release, s3trio_get_fix, s3trio_get_var, s3trio_set_var,
+ s3trio_get_cmap, s3trio_set_cmap, s3trio_pan_display, NULL, s3trio_ioctl
+};
+
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int s3trio_open(struct fb_info *info)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int s3trio_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+
+ /*
+ * Get the Fixed Part of the Display
+ */
+
+static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ memcpy(fix, &fb_fix, sizeof(fb_fix));
+ return 0;
+}
+
+
+ /*
+ * Get the User Defined Part of the Display
+ */
+
+static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ memcpy(var, &fb_var, sizeof(fb_var));
+ return 0;
+}
+
+
+ /*
+ * Set the User Defined Part of the Display
+ */
+
+static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
+ var->xres_virtual > fb_var.xres_virtual ||
+ var->yres_virtual > fb_var.yres_virtual ||
+ var->bits_per_pixel > fb_var.bits_per_pixel ||
+ var->nonstd || var->vmode != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+ memcpy(var, &fb_var, sizeof(fb_var));
+ return 0;
+}
+
+
+ /*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+
+static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xoffset || var->yoffset)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+ /*
+ * Get the Colormap
+ */
+
+static int s3trio_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, s3trio_getcolreg,
+ info);
+ 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(fb_display[con].var.bits_per_pixel),
+ cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+ /*
+ * Set the Colormap
+ */
+
+static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ 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)))
+ return err;
+ }
+ if (con == currcon) /* current console? */
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, s3trio_setcolreg,
+ info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+
+static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+__initfunc(int s3trio_resetaccel(void)) {
+
+
+#define EC01_ENH_ENB 0x0005
+#define EC01_LAW_ENB 0x0010
+#define EC01_MMIO_ENB 0x0020
+
+#define EC00_RESET 0x8000
+#define EC00_ENABLE 0x4000
+#define MF_MULT_MISC 0xE000
+#define SRC_FOREGROUND 0x0020
+#define SRC_BACKGROUND 0x0000
+#define MIX_SRC 0x0007
+#define MF_T_CLIP 0x1000
+#define MF_L_CLIP 0x2000
+#define MF_B_CLIP 0x3000
+#define MF_R_CLIP 0x4000
+#define MF_PIX_CONTROL 0xA000
+#define MFA_SRC_FOREGR_MIX 0x0000
+#define MF_PIX_CONTROL 0xA000
+
+ outw(EC00_RESET, 0x42e8);
+ inw( 0x42e8);
+ outw(EC00_ENABLE, 0x42e8);
+ inw( 0x42e8);
+ outw(EC01_ENH_ENB | EC01_LAW_ENB,
+ 0x4ae8);
+ outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
+
+ /* Now set some basic accelerator registers */
+ Trio_WaitQueue(0x0400);
+ outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
+ outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
+ outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
+ outw(MF_L_CLIP | 0, 0xbee8 );
+ outw(MF_R_CLIP | (640 - 1), 0xbee8);
+ outw(MF_B_CLIP | (480 - 1), 0xbee8);
+ Trio_WaitQueue(0x0400);
+ outw(0xffff, 0xaae8); /* Enable all planes */
+ outw(0xffff, 0xaae8); /* Enable all planes */
+ outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
+
+}
+
+__initfunc(int s3trio_init(void)) {
+
+ u_char bus, dev;
+ unsigned int t32;
+ unsigned short cmd;
+ int i;
+
+ bus=0;
+ dev=(3<<3);
+ pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
+ if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
+ pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
+ pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
+ pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
+
+ pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
+ pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
+
+/* This is a gross hack as OF only maps enough memory for the framebuffer and
+ we want to use MMIO too. We should find out which chunk of address space
+ we can use here */
+ pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
+
+ /* unlock s3 */
+
+ outb(0x01, 0x3C3);
+
+ outb(inb(0x03CC) | 1, 0x3c2);
+
+ outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
+ outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
+ outb(0x33,0x3d4);
+ outw(IO_OUT16VAL( inb(0x3d5) & ~(0x2 |
+ 0x10 | 0x40) , 0x33),0x3d4);
+
+ outw(IO_OUT16VAL(0x6,0x8), 0x3c4);
+
+ /* switch to MMIO only mode */
+
+ outb(0x58,0x3d4);
+ outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10,0x58),0x3d4);
+ outw(IO_OUT16VAL(8,0x53),0x3d4);
+
+ /* switch off I/O accesses */
+
+#if 0
+ pcibios_write_config_word(bus, dev, PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#endif
+ }
+
+ return 0;
+}
+
+
+ /*
+ * Initialisation
+ * We heavily rely on OF for the moment. This needs fixing.
+ */
+
+__initfunc(unsigned long s3trio_fb_init(unsigned long mem_start))
+{
+ struct device_node *dp;
+ int i, err, *pp, len;
+ unsigned *up, address;
+ u_long *CursorBase;
+
+ if (!prom_display_paths[0])
+ return mem_start;
+ if (!(dp = find_path_device(prom_display_paths[0])))
+ return mem_start;
+
+ strncat(s3trio_name, dp->name, sizeof(s3trio_name));
+ s3trio_name[sizeof(s3trio_name)-1] = '\0';
+ strcpy(fb_fix.id, s3trio_name);
+
+ if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
+ && *pp!=PCI_VENDOR_ID_S3) {
+ printk("%s: can't find S3 Trio board\n", dp->full_name);
+ return mem_start;
+ }
+
+ if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
+ && *pp!=PCI_DEVICE_ID_S3_TRIO) {
+ printk("%s: can't find S3 Trio board\n", dp->full_name);
+ return mem_start;
+ }
+
+ if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+ && len == sizeof(int) && *pp != 8) {
+ printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+ return mem_start;
+ }
+ if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+ && len == sizeof(int))
+ fb_var.xres = fb_var.xres_virtual = *pp;
+ if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+ && len == sizeof(int))
+ fb_var.yres = fb_var.yres_virtual = *pp;
+ if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+ && len == sizeof(int))
+ fb_fix.line_length = *pp;
+ else
+ fb_fix.line_length = fb_var.xres_virtual;
+ fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
+
+ s3trio_init();
+ address=0xc6000000;
+ fb_fix.smem_start = ioremap(address,64*1024*1024);
+ fb_fix.type = FB_TYPE_PACKED_PIXELS;
+ fb_fix.type_aux = 0;
+
+
+ s3trio_resetaccel();
+
+ mem_out8(0x30,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0x2d,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0x2e,fb_fix.smem_start+0x1008000 + 0x03D4);
+
+ mem_out8(0x50,fb_fix.smem_start+0x1008000 + 0x03D4);
+
+ /* disable HW cursor */
+
+ mem_out8(0x39,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0xa0,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x4e,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x4f,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ /* init HW cursor */
+
+ CursorBase=(u_long *)(fb_fix.smem_start + 2*1024*1024 - 0x400);
+ for (i=0; i < 8; i++) {
+ *(CursorBase +(i*4)) = 0xffffff00;
+ *(CursorBase+1+(i*4)) = 0xffff0000;
+ *(CursorBase+2+(i*4)) = 0xffff0000;
+ *(CursorBase+3+(i*4)) = 0xffff0000;
+ }
+ for (i=8; i < 64; i++) {
+ *(CursorBase +(i*4)) = 0xffff0000;
+ *(CursorBase+1+(i*4)) = 0xffff0000;
+ *(CursorBase+2+(i*4)) = 0xffff0000;
+ *(CursorBase+3+(i*4)) = 0xffff0000;
+ }
+
+
+ mem_out8(0x4c,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(((2*1024 - 1)&0xf00)>>8,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x4d,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8((2*1024 - 1) & 0xff,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_in8(fb_fix.smem_start+0x1008000 + 0x03D4);
+
+ mem_out8(0x4a,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
+ mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
+ mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x4b,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
+ mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
+ mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
+ mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+
+ s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
+ s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
+ memset((char *)fb_fix.smem_start,0,640*480);
+
+#if 0
+ Trio_RectFill(0,0,90,90,7,1);
+#endif
+
+ fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
+ fb_var.xoffset = fb_var.yoffset = 0;
+ fb_var.bits_per_pixel = 8;
+ fb_var.grayscale = 0;
+ fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
+ fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
+ fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
+ fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
+ fb_var.nonstd = 0;
+ fb_var.activate = 0;
+ fb_var.height = fb_var.width = -1;
+ fb_var.accel = 5;
+ fb_var.pixclock = 1;
+ fb_var.left_margin = fb_var.right_margin = 0;
+ fb_var.upper_margin = fb_var.lower_margin = 0;
+ fb_var.hsync_len = fb_var.vsync_len = 0;
+ fb_var.sync = 0;
+ fb_var.vmode = FB_VMODE_NONINTERLACED;
+
+ disp.var = fb_var;
+ disp.cmap.start = 0;
+ disp.cmap.len = 0;
+ disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
+ disp.screen_base = fb_fix.smem_start;
+ disp.visual = fb_fix.visual;
+ disp.type = fb_fix.type;
+ disp.type_aux = fb_fix.type_aux;
+ disp.ypanstep = 0;
+ disp.ywrapstep = 0;
+ disp.line_length = fb_fix.line_length;
+ disp.can_soft_blank = 1;
+ disp.inverse = 0;
+#ifdef CONFIG_FBCON_CFB8
+ disp.dispsw = &fbcon_trio8;
+#else
+ disp.dispsw = NULL;
+#endif
+
+ strcpy(fb_info.modename, "Trio64 ");
+ strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
+ fb_info.node = -1;
+ fb_info.fbops = &s3trio_ops;
+#if 0
+ fb_info.fbvar_num = 1;
+ fb_info.fbvar = &fb_var;
+#endif
+ fb_info.disp = &disp;
+ fb_info.fontname[0] = '\0';
+ fb_info.changevar = NULL;
+ fb_info.switch_con = &s3triofbcon_switch;
+ fb_info.updatevar = &s3triofbcon_updatevar;
+ fb_info.blank = &s3triofbcon_blank;
+#if 0
+ fb_info.setcmap = &s3triofbcon_setcmap;
+#endif
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info) {
+ display_info.height = fb_var.yres;
+ display_info.width = fb_var.xres;
+ display_info.depth = 8;
+ display_info.pitch = fb_fix.line_length;
+ display_info.mode = 0;
+ strncpy(display_info.name, dp->name, sizeof(display_info.name));
+ display_info.fb_address = (unsigned long)fb_fix.smem_start;
+ display_info.disp_reg_address = address + 0x1008000;
+ display_info.cmap_adr_address = address + 0x1008000 + 0x3c8;
+ display_info.cmap_data_address = address + 0x1008000 + 0x3c9;
+ console_fb_info = &fb_info;
+ console_setmode_ptr = s3trio_console_setmode;
+ console_set_cmap_ptr = s3trio_set_cmap;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
+
+ err = register_framebuffer(&fb_info);
+ if (err < 0)
+ return mem_start;
+
+ printk("fb%d: S3 Trio frame buffer device on %s\n",
+ GET_FB_IDX(fb_info.node), dp->full_name);
+
+ return mem_start;
+}
+
+
+static int s3triofbcon_switch(int con, struct fb_info *info)
+{
+ /* 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,
+ s3trio_getcolreg, info);
+
+ currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con);
+ return 0;
+}
+
+ /*
+ * Update the `var' structure (called by fbcon.c)
+ */
+
+static int s3triofbcon_updatevar(int con, struct fb_info *info)
+{
+ /* Nothing */
+ return 0;
+}
+
+ /*
+ * Blank the display.
+ */
+
+static void s3triofbcon_blank(int blank, struct fb_info *info)
+{
+ /* Nothing */
+}
+
+ /*
+ * Set the colormap
+ */
+
+static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
+{
+ return(s3trio_set_cmap(cmap, 1, con, &fb_info));
+}
+
+
+ /*
+ * Read a single color register and split it into
+ * colors/transparent. Return != 0 for invalid regno.
+ */
+
+static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info)
+{
+ if (regno > 255)
+ return 1;
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ return 0;
+}
+
+
+ /*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ if (regno > 255)
+ return 1;
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ mem_out8(regno,fb_fix.smem_start+0x1008000 + 0x3c8);
+ mem_out8((red & 0xff) >> 2,fb_fix.smem_start+0x1008000 + 0x3c9);
+ mem_out8((green & 0xff) >> 2,fb_fix.smem_start+0x1008000 + 0x3c9);
+ mem_out8((blue & 0xff) >> 2,fb_fix.smem_start+0x1008000 + 0x3c9);
+
+ return 0;
+}
+
+
+static void do_install_cmap(int con)
+{
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+ s3trio_setcolreg, &fb_info);
+ else
+ fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, s3trio_setcolreg, &fb_info);
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+
+ /*
+ * Backward compatibility mode for Xpmac
+ */
+
+static int s3trio_console_setmode(struct vc_mode *mode, int doit)
+{
+ int err;
+ struct fb_var_screeninfo var;
+ struct s3trio_par par;
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX )
+ return -EINVAL;
+ par.video_mode = mode->mode;
+
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ par.color_mode = CMODE_32;
+ break;
+ case 16:
+ par.color_mode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ par.color_mode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ encode_var(&var, &par);
+ if ((err = decode_var(&var, &par)))
+ return err;
+ if (doit)
+ s3trio_set_var(&var, currcon, 0);
+ return 0;
+}
+
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+void s3trio_video_setup(char *options, int *ints) {
+
+ return;
+
+}
+
+static void Trio_WaitQueue(u_short fifo) {
+
+ u_short status;
+
+ do
+ {
+ status = mem_in16(fb_fix.smem_start + 0x1000000 + 0x9AE8);
+ } while (!(status & fifo));
+
+}
+
+static void Trio_WaitBlit(void) {
+
+ u_short status;
+
+ do
+ {
+ status = mem_in16(fb_fix.smem_start + 0x1000000 + 0x9AE8);
+ } while (status & 0x200);
+
+}
+
+static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
+ u_short desty, u_short width, u_short height,
+ u_short mode) {
+
+ u_short blitcmd = 0xc011;
+
+ /* Set drawing direction */
+ /* -Y, X maj, -X (default) */
+
+ if (curx > destx)
+ blitcmd |= 0x0020; /* Drawing direction +X */
+ else {
+ curx += (width - 1);
+ destx += (width - 1);
+ }
+
+ if (cury > desty)
+ blitcmd |= 0x0080; /* Drawing direction +Y */
+ else {
+ cury += (height - 1);
+ desty += (height - 1);
+ }
+
+ Trio_WaitQueue(0x0400);
+
+ outw(0xa000, 0xBEE8);
+ outw(0x60 | mode, 0xBAE8);
+
+ outw(curx, 0x86E8);
+ outw(cury, 0x82E8);
+
+ outw(destx, 0x8EE8);
+ outw(desty, 0x8AE8);
+
+ outw(height - 1, 0xBEE8);
+ outw(width - 1, 0x96E8);
+
+ outw(blitcmd, 0x9AE8);
+
+}
+
+static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
+ u_short mode, u_short color) {
+
+ u_short blitcmd = 0x40b1;
+
+ Trio_WaitQueue(0x0400);
+
+ outw(0xa000, 0xBEE8);
+ outw((0x20 | mode), 0xBAE8);
+ outw(0xe000, 0xBEE8);
+ outw(color, 0xA6E8);
+ outw(x, 0x86E8);
+ outw(y, 0x82E8);
+ outw((height - 1), 0xBEE8);
+ outw((width - 1), 0x96E8);
+ outw(blitcmd, 0x9AE8);
+
+}
+
+
+static void Trio_MoveCursor(u_short x, u_short y) {
+
+ mem_out8(0x39, fb_fix.smem_start + 0x1008000 + 0x3d4);
+ mem_out8(0xa0, fb_fix.smem_start + 0x1008000 + 0x3d5);
+
+ mem_out8(0x46, fb_fix.smem_start + 0x1008000 + 0x3d4);
+ mem_out8((x & 0x0700) >> 8, fb_fix.smem_start + 0x1008000 + 0x3d5);
+ mem_out8(0x47, fb_fix.smem_start + 0x1008000 + 0x3d4);
+ mem_out8(x & 0x00ff, fb_fix.smem_start + 0x1008000 + 0x3d5);
+
+ mem_out8(0x48, fb_fix.smem_start + 0x1008000 + 0x3d4);
+ mem_out8((y & 0x0700) >> 8, fb_fix.smem_start + 0x1008000 + 0x3d5);
+ mem_out8(0x49, fb_fix.smem_start + 0x1008000 + 0x3d4);
+ mem_out8(y & 0x00ff, fb_fix.smem_start + 0x1008000 + 0x3d5);
+
+}
+
+
+ /*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width)
+{
+ sx *= 8; dx *= 8; width *= 8;
+ Trio_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
+ (u_short)(dy*p->fontheight), (u_short)width,
+ (u_short)(height*p->fontheight), (u_short)S3_NEW);
+}
+
+static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
+{
+ unsigned char bg;
+
+ sx *= 8; width *= 8;
+ bg = attr_bgcol_ec(p,conp);
+ Trio_RectFill((u_short)sx,
+ (u_short)(sy*p->fontheight),
+ (u_short)width,
+ (u_short)(height*p->fontheight),
+ (u_short)S3_NEW,
+ (u_short)bg);
+}
+
+static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+ Trio_WaitBlit();
+ fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
+{
+ Trio_WaitBlit();
+ fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+static void fbcon_trio8_revc(struct display *p, int xx, int yy)
+{
+ Trio_WaitBlit();
+ fbcon_cfb8_revc(p, xx, yy);
+}
+
+static struct display_switch fbcon_trio8 = {
+ fbcon_cfb8_setup, fbcon_trio8_bmove, fbcon_trio8_clear, fbcon_trio8_putc,
+ fbcon_trio8_putcs, fbcon_trio8_revc
+};
+#endif
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 7aa9df61a..09ff067df 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -60,6 +60,11 @@
#include <asm/amigaints.h>
#include <asm/setup.h>
+#include "fbcon-afb.h"
+#include "fbcon-ilbm.h"
+#include "fbcon-mfb.h"
+
+
#define DEBUG
#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
@@ -535,15 +540,6 @@ static u_short maxfmode, chipset;
/*
- * Monitor Specifications
- *
- * These are typical for a `generic' Amiga monitor (e.g. A1960)
- */
-
-static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
-
-
- /*
* Various macros
*/
@@ -672,7 +668,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite;
* Current Video Mode
*/
-static struct amiga_fb_par {
+static struct amifb_par {
/* General Values */
@@ -740,6 +736,7 @@ static struct amiga_fb_par {
static int currcon = 0;
static struct display disp;
+
static struct fb_info fb_info;
@@ -789,229 +786,199 @@ static u_short is_lace = 0; /* Screen is laced */
* The rest of the name is filled in during initialization
*/
-static char amiga_fb_name[16] = "Amiga ";
+static char amifb_name[16] = "Amiga ";
- /*
- * Predefined Video Mode Names
- *
- * The a2024-?? modes don't work yet because there's no A2024 driver.
- */
-
-static char *amiga_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
/*
- * AmigaOS Video Modes
- */
-
- "ntsc", /* 640x200, 15 kHz, 60 Hz (NTSC) */
- "ntsc-lace", /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
- "pal", /* 640x256, 15 kHz, 50 Hz (PAL) */
- "pal-lace", /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
- "multiscan", /* 640x480, 29 kHz, 57 Hz */
- "multiscan-lace", /* 640x960, 29 kHz, 57 Hz interlaced */
- "a2024-10", /* 1024x800, 10 Hz (Not yet supported) */
- "a2024-15", /* 1024x800, 15 Hz (Not yet supported) */
- "euro36", /* 640x200, 15 kHz, 72 Hz */
- "euro36-lace", /* 640x400, 15 kHz, 72 Hz interlaced */
- "euro72", /* 640x400, 29 kHz, 68 Hz */
- "euro72-lace", /* 640x800, 29 kHz, 68 Hz interlaced */
- "super72", /* 800x300, 23 kHz, 70 Hz */
- "super72-lace", /* 800x600, 23 kHz, 70 Hz interlaced */
- "dblntsc", /* 640x200, 27 kHz, 57 Hz doublescan */
- "dblntsc-ff", /* 640x400, 27 kHz, 57 Hz */
- "dblntsc-lace", /* 640x800, 27 kHz, 57 Hz interlaced */
- "dblpal", /* 640x256, 27 kHz, 47 Hz doublescan */
- "dblpal-ff", /* 640x512, 27 kHz, 47 Hz */
- "dblpal-lace", /* 640x1024, 27 kHz, 47 Hz interlaced */
-
- /*
- * VGA Video Modes
- */
-
- "vga", /* 640x480, 31 kHz, 60 Hz (VGA) */
- "vga70", /* 640x400, 31 kHz, 70 Hz (VGA) */
-
- /*
- * User Defined Video Modes: to be set after boot up using e.g. fbset
- */
-
- "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
-static struct fb_var_screeninfo amiga_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
+ * Predefined Video Modes
+ *
*/
- { 0, },
-
- /*
- * AmigaOS Video Modes
- */
+static struct fb_videomode amifb_predefined[] __initdata = {
- {
- /* ntsc */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 44, 16, 76, 2,
- FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* ntsc-lace */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 88, 33, 76, 4,
- FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* pal */
- 640, 256, 640, 256, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 40, 14, 76, 2,
- FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* pal-lace */
- 640, 512, 640, 512, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 80, 29, 76, 4,
- FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* multiscan */
- 640, 480, 640, 480, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 29, 8, 72, 8,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-
- }, {
- /* multiscan-lace */
- 640, 960, 640, 960, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 58, 16, 72, 16,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* a2024-10 (Not yet supported) */
- 1024, 800, 1024, 800, 0, 0, 2, 0,
- {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* a2024-15 (Not yet supported) */
- 1024, 800, 1024, 800, 0, 0, 2, 0,
- {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro36 */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro36-lace */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro72 */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro72-lace */
- 640, 800, 640, 800, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* super72 */
- 800, 300, 800, 300, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* super72-lace */
- 800, 600, 800, 600, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblntsc */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
- 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
- }, {
- /* dblntsc-ff */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblntsc-lace */
- 640, 800, 640, 800, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblpal */
- 640, 256, 640, 256, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
- 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
- }, {
- /* dblpal-ff */
- 640, 512, 640, 512, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblpal-lace */
- 640, 1024, 640, 1024, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- },
-
- /*
- * VGA Video Modes
- */
+ /*
+ * AmigaOS Video Modes
+ */
- {
- /* vga */
- 640, 480, 640, 480, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* vga70 */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
- FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- },
+ {
+ "ntsc", { /* 640x200, 15 kHz, 60 Hz (NTSC) */
+ 640, 200, 640, 200, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 106, 86, 44, 16, 76, 2,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "ntsc-lace", { /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
+ 640, 400, 640, 400, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 106, 86, 88, 33, 76, 4,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "pal", { /* 640x256, 15 kHz, 50 Hz (PAL) */
+ 640, 256, 640, 256, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 106, 86, 40, 14, 76, 2,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "pal-lace", { /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
+ 640, 512, 640, 512, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 106, 86, 80, 29, 76, 4,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "multiscan", { /* 640x480, 29 kHz, 57 Hz */
+ 640, 480, 640, 480, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 96, 112, 29, 8, 72, 8,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "multiscan-lace", { /* 640x960, 29 kHz, 57 Hz interlaced */
+ 640, 960, 640, 960, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 96, 112, 58, 16, 72, 16,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "euro36", { /* 640x200, 15 kHz, 72 Hz */
+ 640, 200, 640, 200, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 92, 124, 6, 6, 52, 5,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "euro36-lace", { /* 640x400, 15 kHz, 72 Hz interlaced */
+ 640, 400, 640, 400, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 92, 124, 12, 12, 52, 10,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "euro72", { /* 640x400, 29 kHz, 68 Hz */
+ 640, 400, 640, 400, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 164, 92, 9, 9, 80, 8,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "euro72-lace", { /* 640x800, 29 kHz, 68 Hz interlaced */
+ 640, 800, 640, 800, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 164, 92, 18, 18, 80, 16,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "super72", { /* 800x300, 23 kHz, 70 Hz */
+ 800, 300, 800, 300, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 212, 140, 10, 11, 80, 7,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "super72-lace", { /* 800x600, 23 kHz, 70 Hz interlaced */
+ 800, 600, 800, 600, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 212, 140, 20, 22, 80, 14,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblntsc", { /* 640x200, 27 kHz, 57 Hz doublescan */
+ 640, 200, 640, 200, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 18, 17, 80, 4,
+ 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblntsc-ff", { /* 640x400, 27 kHz, 57 Hz */
+ 640, 400, 640, 400, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 36, 35, 80, 7,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblntsc-lace", { /* 640x800, 27 kHz, 57 Hz interlaced */
+ 640, 800, 640, 800, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 72, 70, 80, 14,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblpal", { /* 640x256, 27 kHz, 47 Hz doublescan */
+ 640, 256, 640, 256, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 14, 13, 80, 4,
+ 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblpal-ff", { /* 640x512, 27 kHz, 47 Hz */
+ 640, 512, 640, 512, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 28, 27, 80, 7,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "dblpal-lace", { /* 640x1024, 27 kHz, 47 Hz interlaced */
+ 640, 1024, 640, 1024, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 196, 124, 56, 54, 80, 14,
+ 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+ }
+ },
+
+ /*
+ * VGA Video Modes
+ */
+
+ {
+ "vga", { /* 640x480, 31 kHz, 60 Hz (VGA) */
+ 640, 480, 640, 480, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 64, 96, 30, 9, 112, 2,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "vga70", { /* 640x400, 31 kHz, 70 Hz (VGA) */
+ 640, 400, 640, 400, 0, 0, 4, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_SHRES, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ },
- /*
- * User Defined Video Modes
- */
+#if 0
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+ /*
+ * A2024 video modes
+ * These modes don't work yet because there's no A2024 driver.
+ */
+
+ {
+ "a2024-10", { /* 1024x800, 10 Hz */
+ 1024, 800, 1024, 800, 0, 0, 2, 0,
+ {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }, {
+ "a2024-15", { /* 1024x800, 15 Hz */
+ 1024, 800, 1024, 800, 0, 0, 2, 0,
+ {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }
+ }
+#endif
};
-#define NUM_USER_MODES (8)
-#define NUM_TOTAL_MODES arraysize(amiga_fb_predefined)
-#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES)
+#define NUM_TOTAL_MODES arraysize(amifb_predefined)
static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
-
static int amifb_inverse = 0;
-static int amifb_usermode = 0;
+static int amifb_usermode __initdata = 0;
+static int amifb_userdepth __initdata = -1;
/*
* Some default modes
@@ -1023,6 +990,9 @@ static int amifb_usermode = 0;
#define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */
#define DEFMODE_AGA "vga70" /* for AGA */
+static struct fb_var_screeninfo amifb_default;
+
+
/*
* Macros for the conversion from real world values to hardware register
* values
@@ -1181,40 +1151,47 @@ static u_short sprfetchmode[3] = {
* Interface used by the world
*/
-void amiga_video_setup(char *options, int *ints);
-
-static int amiga_fb_open(int fbidx);
-static int amiga_fb_release(int fbidx);
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
+void amifb_setup(char *options, int *ints);
+
+static int amifb_open(struct fb_info *info);
+static int amifb_release(struct fb_info *info);
+static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int amifb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int amifb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
+static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var,
+ u_char *data, int con);
+static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var,
+ u_char *data, int con);
+static int amifb_get_cursorstate(struct fb_cursorstate *state, int con);
+static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
/*
* Interface to the low level console driver
*/
-unsigned long amiga_fb_init(unsigned long mem_start);
-static int amifbcon_switch(int con);
-static int amifbcon_updatevar(int con);
-static void amifbcon_blank(int blank);
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con);
+unsigned long amifb_init(unsigned long mem_start);
+static int amifbcon_switch(int con, struct fb_info *info);
+static int amifbcon_updatevar(int con, struct fb_info *info);
+static void amifbcon_blank(int blank, struct fb_info *info);
/*
* Internal routines
*/
-static void do_install_cmap(int con);
+static void do_install_cmap(int con, struct fb_info *info);
static int flash_cursor(void);
static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static void get_video_mode(const char *name);
@@ -1227,22 +1204,22 @@ static char *strtoke(char *s,const char *ct);
*/
static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amiga_fb_par *par);
+ struct amifb_par *par);
static int ami_decode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par);
+ struct amifb_par *par);
static int ami_encode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par);
-static void ami_get_par(struct amiga_fb_par *par);
+ struct amifb_par *par);
+static void ami_get_par(struct amifb_par *par);
static void ami_set_var(struct fb_var_screeninfo *var);
#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par);
+static void ami_set_par(struct amifb_par *par);
#endif
static void ami_pan_var(struct fb_var_screeninfo *var);
static int ami_update_par(void);
static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
+ u_int transp, struct fb_info *info);
static void ami_update_display(void);
static void ami_init_display(void);
static void ami_do_blank(void);
@@ -1265,29 +1242,14 @@ static void ami_rebuild_copper(void);
extern unsigned short ami_intena_vals[];
-static struct fb_ops amiga_fb_ops = {
- amiga_fb_open, amiga_fb_release, amiga_fb_get_fix, amiga_fb_get_var,
- amiga_fb_set_var, amiga_fb_get_cmap, amiga_fb_set_cmap,
- amiga_fb_pan_display, amiga_fb_ioctl
+static struct fb_ops amifb_ops = {
+ amifb_open, amifb_release, amifb_get_fix, amifb_get_var,
+ amifb_set_var, amifb_get_cmap, amifb_set_cmap,
+ amifb_pan_display, NULL, amifb_ioctl
};
-struct useropts {
- long xres;
- long yres;
- long xres_virtual;
- long yres_virtual;
- long bits_per_pixel;
- long left_margin;
- long right_margin;
- long upper_margin;
- long lower_margin;
- long hsync_len;
- long vsync_len;
-} useropts __initdata = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
-};
-__initfunc(void amiga_video_setup(char *options, int *ints))
+__initfunc(void amifb_setup(char *options, int *ints))
{
char *this_opt;
char mcap_spec[80];
@@ -1313,51 +1275,51 @@ __initfunc(void amiga_video_setup(char *options, int *ints))
else if (!strncmp(this_opt, "fstart:", 7))
min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
else if (!strncmp(this_opt, "depth:", 6))
- useropts.bits_per_pixel = simple_strtoul(this_opt+6, NULL, 0);
+ amifb_userdepth = simple_strtoul(this_opt+6, NULL, 0);
else if (!strncmp(this_opt, "size:", 5)) {
p = this_opt + 5;
if (*p != ';')
- useropts.xres = simple_strtoul(p, NULL, 0);
+ amifb_default.xres = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p != ';')
- useropts.yres = simple_strtoul(p, NULL, 0);
+ amifb_default.yres = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p != ';')
- useropts.xres_virtual = simple_strtoul(p, NULL, 0);
+ amifb_default.xres_virtual = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p != ';')
- useropts.yres_virtual = simple_strtoul(p, NULL, 0);
+ amifb_default.yres_virtual = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p)
- useropts.bits_per_pixel = simple_strtoul(p, NULL, 0);
+ amifb_default.bits_per_pixel = simple_strtoul(p, NULL, 0);
} else if (!strncmp(this_opt, "timing:", 7)) {
p = this_opt + 7;
if (*p != ';')
- useropts.left_margin = simple_strtoul(p, NULL, 0);
+ amifb_default.left_margin = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p != ';')
- useropts.right_margin = simple_strtoul(p, NULL, 0);
+ amifb_default.right_margin = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p != ';')
- useropts.upper_margin = simple_strtoul(p, NULL, 0);
+ amifb_default.upper_margin = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p)
- useropts.lower_margin = simple_strtoul(p, NULL, 0);
+ amifb_default.lower_margin = simple_strtoul(p, NULL, 0);
} else if (!strncmp(this_opt, "sync:", 5)) {
p = this_opt + 5;
if (*p != ';')
- useropts.hsync_len = simple_strtoul(p, NULL, 0);
+ amifb_default.hsync_len = simple_strtoul(p, NULL, 0);
if (!(p = strchr(p, ';')))
continue;
if (*++p)
- useropts.vsync_len = simple_strtoul(p, NULL, 0);
+ amifb_default.vsync_len = simple_strtoul(p, NULL, 0);
} else
get_video_mode(this_opt);
}
@@ -1395,10 +1357,10 @@ __initfunc(void amiga_video_setup(char *options, int *ints))
if (hmax <= 0 || hmax <= hmin)
goto cap_invalid;
- vfmin = vmin;
- vfmax = vmax;
- hfmin = hmin;
- hfmax = hmax;
+ fb_info.monspecs.vfmin = vmin;
+ fb_info.monspecs.vfmax = vmax;
+ fb_info.monspecs.hfmin = hmin;
+ fb_info.monspecs.hfmax = hmax;
cap_invalid:
;
}
@@ -1408,7 +1370,7 @@ cap_invalid:
* Open/Release the frame buffer device
*/
-static int amiga_fb_open(int fbidx)
+static int amifb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -1418,7 +1380,7 @@ static int amiga_fb_open(int fbidx)
return(0);
}
-static int amiga_fb_release(int fbidx)
+static int amifb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
@@ -1429,9 +1391,10 @@ static int amiga_fb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
- struct amiga_fb_par par;
+ struct amifb_par par;
if (con == -1)
ami_get_par(&par);
@@ -1448,12 +1411,13 @@ static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
+static int amifb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
int err = 0;
if (con == -1) {
- struct amiga_fb_par par;
+ struct amifb_par par;
ami_get_par(&par);
err = ami_encode_var(var, &par);
@@ -1466,11 +1430,12 @@ static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
* Set the User Defined Part of the Display
*/
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
+static int amifb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
int err, activate = var->activate;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
- struct amiga_fb_par par;
+ struct amifb_par par;
struct display *display;
if (con >= 0)
@@ -1513,13 +1478,32 @@ static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = amifb_inverse;
+ switch (fix.type) {
+#ifdef CONFIG_FBCON_ILBM
+ case FB_TYPE_INTERLEAVED_PLANES:
+ display->dispsw = &fbcon_ilbm;
+ break;
+#endif
+#ifdef CONFIG_FBCON_AFB
+ case FB_TYPE_PLANES:
+ display->dispsw = &fbcon_afb;
+ break;
+#endif
+#ifdef CONFIG_FBCON_MFB
+ case FB_TYPE_PACKED_PIXELS: /* depth == 1 */
+ display->dispsw = &fbcon_mfb;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ }
if (fb_info.changevar)
(*fb_info.changevar)(con);
}
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
if (con == currcon)
ami_set_var(&display->var);
@@ -1533,7 +1517,8 @@ static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
@@ -1562,15 +1547,16 @@ static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int amifb_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,
- ami_getcolreg);
+ ami_getcolreg, info);
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
@@ -1579,7 +1565,8 @@ static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
int err;
@@ -1591,7 +1578,7 @@ static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
}
if (con == currcon) /* current console? */
return fb_set_cmap(cmap, &fb_display[con].var, kspc,
- ami_setcolreg);
+ ami_setcolreg, info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
@@ -1601,8 +1588,8 @@ static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
* Amiga Frame Buffer Specific ioctls
*/
-static int amiga_fb_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg, int con)
+static int amifb_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg, int con, struct fb_info *info)
{
int i;
@@ -1612,7 +1599,7 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
if (!i) {
- i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
+ i = amifb_get_fix_cursorinfo(&crsrfix, con);
copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
}
return i;
@@ -1622,7 +1609,7 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
if (!i) {
- i = amiga_fb_get_var_cursorinfo(&crsrvar,
+ i = amifb_get_var_cursorinfo(&crsrvar,
((struct fb_var_cursorinfo *)arg)->data, con);
copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
}
@@ -1634,7 +1621,7 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
if (!i) {
copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
- i = amiga_fb_set_var_cursorinfo(&crsrvar,
+ i = amifb_set_var_cursorinfo(&crsrvar,
((struct fb_var_cursorinfo *)arg)->data, con);
}
return i;
@@ -1644,7 +1631,7 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
if (!i) {
- i = amiga_fb_get_cursorstate(&crsrstate, con);
+ i = amifb_get_cursorstate(&crsrstate, con);
copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
}
return i;
@@ -1655,27 +1642,27 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
if (!i) {
copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
- i = amiga_fb_set_cursorstate(&crsrstate, con);
+ i = amifb_set_cursorstate(&crsrstate, con);
}
return i;
}
#ifdef DEBUG
case FBCMD_GET_CURRENTPAR : {
- struct amiga_fb_par par;
+ struct amifb_par par;
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amiga_fb_par));
+ i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par));
if (!i) {
ami_get_par(&par);
- copy_to_user((void *)arg, &par, sizeof(struct amiga_fb_par));
+ copy_to_user((void *)arg, &par, sizeof(struct amifb_par));
}
return i;
}
case FBCMD_SET_CURRENTPAR : {
- struct amiga_fb_par par;
+ struct amifb_par par;
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amiga_fb_par));
+ i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par));
if (!i) {
- copy_from_user(&par, (void *)arg, sizeof(struct amiga_fb_par));
+ copy_from_user(&par, (void *)arg, sizeof(struct amifb_par));
ami_set_par(&par);
}
return i;
@@ -1689,27 +1676,27 @@ static int amiga_fb_ioctl(struct inode *inode, struct file *file,
* Hardware Cursor
*/
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
{
return ami_get_fix_cursorinfo(fix, con);
}
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
{
return ami_get_var_cursorinfo(var, data, con);
}
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
{
return ami_set_var_cursorinfo(var, data, con);
}
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
+static int amifb_get_cursorstate(struct fb_cursorstate *state, int con)
{
return ami_get_cursorstate(state, con);
}
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
+static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
{
return ami_set_cursorstate(state, con);
}
@@ -1719,7 +1706,7 @@ static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
* Initialisation
*/
-__initfunc(unsigned long amiga_fb_init(unsigned long mem_start))
+__initfunc(unsigned long amifb_init(unsigned long mem_start))
{
int err, tag, i;
u_long chipptr;
@@ -1745,7 +1732,7 @@ __initfunc(unsigned long amiga_fb_init(unsigned long mem_start))
switch (amiga_chipset) {
#ifdef CONFIG_FB_AMIGA_OCS
case CS_OCS:
- strcat(amiga_fb_name, "OCS");
+ strcat(amifb_name, "OCS");
default_chipset:
chipset = TAG_OCS;
maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
@@ -1761,7 +1748,7 @@ default_chipset:
#ifdef CONFIG_FB_AMIGA_ECS
case CS_ECS:
- strcat(amiga_fb_name, "ECS");
+ strcat(amifb_name, "ECS");
chipset = TAG_ECS;
maxdepth[TAG_SHRES] = 2;
maxdepth[TAG_HIRES] = 4;
@@ -1785,7 +1772,7 @@ default_chipset:
#ifdef CONFIG_FB_AMIGA_AGA
case CS_AGA:
- strcat(amiga_fb_name, "AGA");
+ strcat(amifb_name, "AGA");
chipset = TAG_AGA;
maxdepth[TAG_SHRES] = 8;
maxdepth[TAG_HIRES] = 8;
@@ -1804,7 +1791,7 @@ default_chipset:
default:
#ifdef CONFIG_FB_AMIGA_OCS
printk("Unknown graphics chipset, defaulting to OCS\n");
- strcat(amiga_fb_name, "Unknown");
+ strcat(amifb_name, "Unknown");
goto default_chipset;
#else /* CONFIG_FB_AMIGA_OCS */
return mem_start;
@@ -1824,26 +1811,42 @@ default_chipset:
* Replace the Tag Values with the Real Pixel Clock Values
*/
- for (i = 0; i < NUM_PREDEF_MODES; i++) {
- tag = amiga_fb_predefined[i].pixclock;
+ if (amifb_userdepth != -1)
+ amifb_default.bits_per_pixel = amifb_userdepth;
+ for (i = 0; i < NUM_TOTAL_MODES; i++) {
+ struct fb_var_screeninfo *var = &amifb_predefined[i].var;
+ tag = var->pixclock;
if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
- amiga_fb_predefined[i].pixclock = pixclock[tag];
- if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag])
- amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag];
+ var->pixclock = pixclock[tag];
+ if (var->bits_per_pixel > maxdepth[tag])
+ var->bits_per_pixel = maxdepth[tag];
}
}
+ tag = amifb_default.pixclock;
+ if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
+ amifb_default.pixclock = pixclock[tag];
+ if (amifb_default.bits_per_pixel > maxdepth[tag])
+ amifb_default.bits_per_pixel = maxdepth[tag];
+ }
+
+ /*
+ * These monitor specs are for a typical Amiga monitor (e.g. A1960)
+ */
+ if (fb_info.monspecs.hfmin == 0) {
+ fb_info.monspecs.hfmin = 15000;
+ fb_info.monspecs.hfmax = 38000;
+ fb_info.monspecs.vfmin = 49;
+ fb_info.monspecs.vfmax = 90;
+ }
- strcpy(fb_info.modename, amiga_fb_name);
+ strcpy(fb_info.modename, amifb_name);
fb_info.changevar = NULL;
fb_info.node = -1;
- fb_info.fbops = &amiga_fb_ops;
- fb_info.fbvar_num = NUM_TOTAL_MODES;
- fb_info.fbvar = amiga_fb_predefined;
+ fb_info.fbops = &amifb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &amifbcon_switch;
fb_info.updatevar = &amifbcon_updatevar;
fb_info.blank = &amifbcon_blank;
- fb_info.setcmap = &amifbcon_setcmap;
err = register_framebuffer(&fb_info);
if (err < 0)
@@ -1889,10 +1892,11 @@ default_chipset:
custom.intena = IF_VERTB;
custom.intena = IF_SETCLR | IF_COPER;
- amiga_fb_set_var(&amiga_fb_predefined[0], -1);
+ amifb_set_var(&amifb_default, -1, &fb_info);
- printk("%s frame buffer device, using %ldK of video memory\n",
- fb_info.modename, videomemorysize>>10);
+ printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename,
+ videomemorysize>>10);
/* TODO: This driver cannot be unloaded yet */
MOD_INC_USE_COUNT;
@@ -1900,17 +1904,17 @@ default_chipset:
return mem_start;
}
-static int amifbcon_switch(int con)
+static int amifbcon_switch(int con, struct fb_info *info)
{
/* 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, ami_getcolreg);
+ &fb_display[currcon].var, 1, ami_getcolreg, info);
currcon = con;
ami_set_var(&fb_display[con].var);
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -1918,7 +1922,7 @@ static int amifbcon_switch(int con)
* Update the `var' structure (called by fbcon.c)
*/
-static int amifbcon_updatevar(int con)
+static int amifbcon_updatevar(int con, struct fb_info *info)
{
ami_pan_var(&fb_display[con].var);
return 0;
@@ -1928,7 +1932,7 @@ static int amifbcon_updatevar(int con)
* Blank the display.
*/
-static void amifbcon_blank(int blank)
+static void amifbcon_blank(int blank, struct fb_info *info)
{
do_blank = blank ? blank : -1;
}
@@ -1937,23 +1941,17 @@ static void amifbcon_blank(int blank)
* Set the colormap
*/
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con)
-{
- return(amiga_fb_set_cmap(cmap, 1, con));
-}
-
-
-static void do_install_cmap(int con)
+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,
- ami_setcolreg);
+ ami_setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
&fb_display[con].var, 1,
- ami_setcolreg);
+ ami_setcolreg, info);
}
static int flash_cursor(void)
@@ -2039,33 +2037,9 @@ __initfunc(static void get_video_mode(const char *name))
{
int i;
- for (i = 1; i < NUM_PREDEF_MODES; i++) {
- if (!strcmp(name, amiga_fb_modenames[i])) {
- amiga_fb_predefined[0] = amiga_fb_predefined[i];
-
- if (useropts.xres != -1)
- amiga_fb_predefined[0].xres = useropts.xres;
- if (useropts.yres != -1)
- amiga_fb_predefined[0].yres = useropts.yres;
- if (useropts.xres_virtual != -1)
- amiga_fb_predefined[0].xres_virtual = useropts.xres_virtual;
- if (useropts.yres_virtual != -1)
- amiga_fb_predefined[0].yres_virtual = useropts.yres_virtual;
- if (useropts.bits_per_pixel != -1)
- amiga_fb_predefined[0].bits_per_pixel = useropts.bits_per_pixel;
- if (useropts.left_margin != -1)
- amiga_fb_predefined[0].left_margin = useropts.left_margin;
- if (useropts.right_margin != -1)
- amiga_fb_predefined[0].right_margin = useropts.right_margin;
- if (useropts.upper_margin != -1)
- amiga_fb_predefined[0].upper_margin = useropts.upper_margin;
- if (useropts.lower_margin != -1)
- amiga_fb_predefined[0].lower_margin = useropts.lower_margin;
- if (useropts.hsync_len != -1)
- amiga_fb_predefined[0].hsync_len = useropts.hsync_len;
- if (useropts.vsync_len != -1)
- amiga_fb_predefined[0].vsync_len = useropts.vsync_len;
-
+ for (i = 0; i < NUM_TOTAL_MODES; i++) {
+ if (!strcmp(name, amifb_predefined[i].name)) {
+ amifb_default = amifb_predefined[i].var;
amifb_usermode = i;
return;
}
@@ -2073,23 +2047,22 @@ __initfunc(static void get_video_mode(const char *name))
}
/*
- * Probe the Video Modes
+ * Probe the Video Modes
*/
__initfunc(static void check_default_mode(void))
{
- struct amiga_fb_par par;
+ struct amifb_par par;
int mode;
- for (mode = 0; mode < NUM_PREDEF_MODES; mode++) {
- if (!ami_decode_var(&amiga_fb_predefined[mode], &par)) {
- if (mode)
- amiga_fb_predefined[0] = amiga_fb_predefined[mode];
+ if (!ami_decode_var(&amifb_default, &par))
+ return;
+ printk("Can't use default video mode. Probing video modes...\n");
+ for (mode = 0; mode < NUM_TOTAL_MODES; mode++)
+ if (!ami_decode_var(&amifb_predefined[mode].var, &par)) {
+ amifb_default = amifb_predefined[mode].var;
return;
}
- if (!mode)
- printk("Can't use default video mode. Probing video modes...\n");
- }
panic("Can't find any usable video mode");
}
@@ -2141,13 +2114,19 @@ __initfunc(static char *strtoke(char *s,const char *ct))
*/
static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amiga_fb_par *par)
+ struct amifb_par *par)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, amiga_fb_name);
+ strcpy(fix->id, amifb_name);
fix->smem_start = (char *)videomemory;
fix->smem_len = videomemorysize;
+#ifdef CONFIG_FBCON_MFB
+ if (par->bpp == 1) {
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ } else
+#endif
if (amifb_ilbm) {
fix->type = FB_TYPE_INTERLEAVED_PLANES;
fix->type_aux = par->next_line;
@@ -2169,6 +2148,7 @@ static int ami_encode_fix(struct fb_fix_screeninfo *fix,
fix->xpanstep = 16<<maxfmode;
fix->ypanstep = 1;
}
+ fix->accel = FB_ACCEL_AMIGABLITT;
return 0;
}
@@ -2178,11 +2158,11 @@ static int ami_encode_fix(struct fb_fix_screeninfo *fix,
*/
static int ami_decode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par)
+ struct amifb_par *par)
{
u_short clk_shift, line_shift;
u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
- u_long hrate = 0, vrate = 0;
+ u_int htotal, vtotal;
/*
* Find a matching Pixel Clock
@@ -2319,8 +2299,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
DPRINTK("diwstrt_v too low for pal\n");
return -EINVAL;
}
- hrate = 15625;
- vrate = 50;
+ htotal = PAL_HTOTAL>>clk_shift;
+ vtotal = PAL_VTOTAL>>1;
if (!IS_OCS) {
par->beamcon0 = BMC0_PAL;
par->bplcon3 |= BPC3_BRDRBLNK;
@@ -2349,8 +2329,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
DPRINTK("diwstrt_v too low for ntsc\n");
return -EINVAL;
}
- hrate = 15750;
- vrate = 60;
+ htotal = NTSC_HTOTAL>>clk_shift;
+ vtotal = NTSC_VTOTAL>>1;
if (!IS_OCS) {
par->beamcon0 = 0;
par->bplcon3 |= BPC3_BRDRBLNK;
@@ -2409,9 +2389,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
par->beamcon0 |= BMC0_VSYTRUE;
if (var->sync & FB_SYNC_COMP_HIGH_ACT)
par->beamcon0 |= BMC0_CSYTRUE;
- hrate = (amiga_masterclock+par->htotal/2)/par->htotal;
- vrate = div2(par->vtotal) * par->htotal;
- vrate = (amiga_masterclock+vrate/2)/vrate;
+ htotal = par->htotal>>clk_shift;
+ vtotal = par->vtotal>>1;
} else {
DPRINTK("only broadcast modes possible for ocs\n");
return -EINVAL;
@@ -2546,7 +2525,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
par->crsr.spot_x = par->crsr.spot_y = 0;
par->crsr.height = par->crsr.width = 0;
- if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax) {
+ if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
+ &fb_info)) {
DPRINTK("mode doesn't fit for monitor\n");
return -EINVAL;
}
@@ -2560,7 +2540,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
*/
static int ami_encode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par)
+ struct amifb_par *par)
{
u_short clk_shift, line_shift;
int i;
@@ -2606,7 +2586,6 @@ static int ami_encode_var(struct fb_var_screeninfo *var,
var->height = -1;
var->width = -1;
- var->accel = 0;
var->pixclock = pixclock[clk_shift];
@@ -2657,7 +2636,7 @@ static int ami_encode_var(struct fb_var_screeninfo *var,
* Get current hardware setting
*/
-static void ami_get_par(struct amiga_fb_par *par)
+static void ami_get_par(struct amifb_par *par)
{
*par = currentpar;
}
@@ -2676,7 +2655,7 @@ static void ami_set_var(struct fb_var_screeninfo *var)
}
#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par)
+static void ami_set_par(struct amifb_par *par)
{
do_vmode_pan = 0;
do_vmode_full = 0;
@@ -2695,7 +2674,7 @@ static void ami_set_par(struct amiga_fb_par *par)
static void ami_pan_var(struct fb_var_screeninfo *var)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
par->xoffset = var->xoffset;
par->yoffset = var->yoffset;
@@ -2715,7 +2694,7 @@ static void ami_pan_var(struct fb_var_screeninfo *var)
static int ami_update_par(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
clk_shift = par->clk_shift;
@@ -2780,7 +2759,7 @@ static int ami_update_par(void)
*/
static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
+ u_int *transp, struct fb_info *info)
{
if (IS_AGA) {
if (regno > 255)
@@ -2804,7 +2783,7 @@ static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
*/
static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
+ u_int transp, struct fb_info *info)
{
#if defined(CONFIG_FB_AMIGA_AGA)
u_short bplcon3 = currentpar.bplcon3;
@@ -2867,7 +2846,7 @@ static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static void ami_update_display(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
custom.bplcon1 = par->bplcon1;
custom.bpl1mod = par->bpl1mod;
@@ -2882,7 +2861,7 @@ static void ami_update_display(void)
static void ami_init_display(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
@@ -2938,7 +2917,7 @@ static void ami_init_display(void)
static void ami_do_blank(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
#if defined(CONFIG_FB_AMIGA_AGA)
u_short bplcon3 = par->bplcon3;
#endif
@@ -3023,7 +3002,7 @@ static void ami_do_blank(void)
static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
fix->crsr_width = fix->crsr_xsize = par->crsr.width;
fix->crsr_height = fix->crsr_ysize = par->crsr.height;
@@ -3034,7 +3013,7 @@ static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
register u_short *lspr, *sspr;
#ifdef __mc68000__
register u_long datawords asm ("d2");
@@ -3109,7 +3088,7 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i
static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
register u_short *lspr, *sspr;
#ifdef __mc68000__
register u_long datawords asm ("d2");
@@ -3228,7 +3207,7 @@ static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i
static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
state->xoffset = par->crsr.crsr_x;
state->yoffset = par->crsr.crsr_y;
@@ -3238,7 +3217,7 @@ static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
par->crsr.crsr_x = state->xoffset;
par->crsr.crsr_y = state->yoffset;
@@ -3250,7 +3229,7 @@ static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
static void ami_set_sprite(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
copins *copl, *cops;
u_short hs, vs, ve;
u_long pl, ps, pt;
@@ -3333,7 +3312,7 @@ __initfunc(static void ami_init_copper(void))
static void ami_reinit_copper(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
@@ -3345,7 +3324,7 @@ static void ami_reinit_copper(void)
static void ami_build_copper(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
copins *copl, *cops;
u_long p;
@@ -3422,7 +3401,7 @@ static void ami_build_copper(void)
static void ami_rebuild_copper(void)
{
- struct amiga_fb_par *par = &currentpar;
+ struct amifb_par *par = &currentpar;
copins *copl, *cops;
u_short line, h_end1, h_end2;
short i;
@@ -3507,7 +3486,7 @@ static void ami_rebuild_copper(void)
#ifdef MODULE
int init_module(void)
{
- return(amiga_fb_init(NULL));
+ return(amifb_init(NULL));
}
void cleanup_module(void)
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index ada071f2b..ff7aedfe7 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -66,10 +66,31 @@
#include <asm/atarihw.h>
#include <asm/atariints.h>
+#include <asm/atari_stram.h>
#include <linux/fb.h>
#include <asm/atarikb.h>
+#ifdef CONFIG_FBCON_CFB8
+#include "fbcon-cfb8.h"
+#endif
+#ifdef CONFIG_FBCON_CFB16
+#include "fbcon-cfb16.h"
+#endif
+#ifdef CONFIG_FBCON_IPLAN2P2
+#include "fbcon-iplan2p2.h"
+#endif
+#ifdef CONFIG_FBCON_IPLAN2P4
+#include "fbcon-iplan2p4.h"
+#endif
+#ifdef CONFIG_FBCON_IPLAN2P8
+#include "fbcon-iplan2p8.h"
+#endif
+#ifdef CONFIG_FBCON_MFB
+#include "fbcon-mfb.h"
+#endif
+
+
#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
#define SWITCH_SND6 0x40
#define SWITCH_SND7 0x80
@@ -92,16 +113,18 @@ static int use_hwscroll = 1;
static int sttt_xres=640,st_yres=400,tt_yres=480;
static int sttt_xres_virtual=640,sttt_yres_virtual=400;
static int ovsc_offset=0, ovsc_addlen=0;
-int ovsc_switchmode=0;
-static struct atari_fb_par {
+static struct atafb_par {
unsigned long screen_base;
int yres_virtual;
+#if defined ATAFB_TT || defined ATAFB_STE
union {
struct {
int mode;
int sync;
} tt, st;
+#endif
+#ifdef ATAFB_FALCON
struct falcon_hw {
/* Here are fields for storing a video mode, as direct
* parameters for the hardware.
@@ -121,6 +144,7 @@ static struct atari_fb_par {
short ste_mode;
short bpp;
} falcon;
+#endif
/* Nothing needed for external mode */
} hw;
} current_par;
@@ -130,6 +154,7 @@ static struct atari_fb_par {
* hardware extensions (e.g. ScreenBlaster) */
static int DontCalcRes = 0;
+#ifdef ATAFB_FALCON
#define HHT hw.falcon.hht
#define HBB hw.falcon.hbb
#define HBE hw.falcon.hbe
@@ -150,6 +175,7 @@ static int DontCalcRes = 0;
#define VMO_DOUBLE 0x01
#define VMO_INTER 0x02
#define VMO_PREMASK 0x0c
+#endif
static struct fb_info fb_info;
@@ -239,26 +265,22 @@ extern int fontheight_8x16;
extern int fontwidth_8x16;
extern unsigned char fontdata_8x16[];
-/* import first 16 colors from fbcon.c */
-extern unsigned short packed16_cmap[16];
-
-
/* ++roman: This structure abstracts from the underlying hardware (ST(e),
* TT, or Falcon.
*
* int (*detect)( void )
* This function should detect the current video mode settings and
- * store them in atari_fb_predefined[0] for later reference by the
+ * store them in atafb_predefined[0] for later reference by the
* user. Return the index+1 of an equivalent predefined mode or 0
* if there is no such.
*
* int (*encode_fix)( struct fb_fix_screeninfo *fix,
- * struct atari_fb_par *par )
+ * struct atafb_par *par )
* This function should fill in the 'fix' structure based on the
* values in the 'par' structure.
*
* int (*decode_var)( struct fb_var_screeninfo *var,
- * struct atari_fb_par *par )
+ * struct atafb_par *par )
* Get the video params out of 'var'. If a value doesn't fit, round
* it up, if it's too big, return EINVAL.
* Round up in the following order: bits_per_pixel, xres, yres,
@@ -266,26 +288,26 @@ extern unsigned short packed16_cmap[16];
* horizontal timing, vertical timing.
*
* int (*encode_var)( struct fb_var_screeninfo *var,
- * struct atari_fb_par *par );
+ * struct atafb_par *par );
* Fill the 'var' structure based on the values in 'par' and maybe
* other values read out of the hardware.
*
- * void (*get_par)( struct atari_fb_par *par )
+ * void (*get_par)( struct atafb_par *par )
* Fill the hardware's 'par' structure.
*
- * void (*set_par)( struct atari_fb_par *par )
+ * void (*set_par)( struct atafb_par *par )
* Set the hardware according to 'par'.
*
* int (*setcolreg)( unsigned regno, unsigned red,
* unsigned green, unsigned blue,
- * unsigned transp )
+ * unsigned transp, struct fb_info *info )
* Set a single color register. The values supplied are already
* rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno.
*
* int (*getcolreg)( unsigned regno, unsigned *red,
* unsigned *green, unsigned *blue,
- * unsigned *transp )
+ * unsigned *transp, struct fb_info *info )
* Read a single color register and split it into
* colors/transparent. Return != 0 for invalid regno.
*
@@ -305,23 +327,23 @@ extern unsigned short packed16_cmap[16];
static struct fb_hwswitch {
int (*detect)( void );
int (*encode_fix)( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par );
+ struct atafb_par *par );
int (*decode_var)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par );
+ struct atafb_par *par );
int (*encode_var)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par );
- void (*get_par)( struct atari_fb_par *par );
- void (*set_par)( struct atari_fb_par *par );
+ struct atafb_par *par );
+ void (*get_par)( struct atafb_par *par );
+ void (*set_par)( struct atafb_par *par );
int (*getcolreg)( unsigned regno, unsigned *red,
unsigned *green, unsigned *blue,
- unsigned *transp );
+ unsigned *transp, struct fb_info *info );
int (*setcolreg)( unsigned regno, unsigned red,
unsigned green, unsigned blue,
- unsigned transp );
+ unsigned transp, struct fb_info *info );
void (*set_screen_base)( unsigned long s_base );
int (*blank)( int blank_mode );
int (*pan_display)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par);
+ struct atafb_par *par);
} *fbhw;
static char *autodetect_names[] = {"autodetect", NULL};
@@ -337,15 +359,6 @@ static char *vga16_names[] = {"vga16", "default3", NULL};
static char *vga256_names[] = {"vga256", NULL};
static char *falh2_names[] = {"falh2", NULL};
static char *falh16_names[] = {"falh16", NULL};
-static char *user0_names[] = {"user0", NULL};
-static char *user1_names[] = {"user1", NULL};
-static char *user2_names[] = {"user2", NULL};
-static char *user3_names[] = {"user3", NULL};
-static char *user4_names[] = {"user4", NULL};
-static char *user5_names[] = {"user5", NULL};
-static char *user6_names[] = {"user6", NULL};
-static char *user7_names[] = {"user7", NULL};
-static char *dummy_names[] = {"dummy", NULL};
static char **fb_var_names[] = {
/* Writing the name arrays directly in this array (via "(char *[]){...}")
@@ -365,22 +378,11 @@ static char **fb_var_names[] = {
vga256_names,
falh2_names,
falh16_names,
- dummy_names, dummy_names, dummy_names, dummy_names,
- dummy_names, dummy_names, dummy_names, dummy_names,
- dummy_names, dummy_names,
- user0_names,
- user1_names,
- user2_names,
- user3_names,
- user4_names,
- user5_names,
- user6_names,
- user7_names,
NULL
/* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
};
-static struct fb_var_screeninfo atari_fb_predefined[] = {
+static struct fb_var_screeninfo atafb_predefined[] = {
/*
* yres_virtual==0 means use hw-scrolling if possible, else yres
*/
@@ -436,53 +438,9 @@ static struct fb_var_screeninfo atari_fb_predefined[] = {
896, 608, 896, 0, 0, 0, 4, 0,
{0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- /* Minor 14..23 free for more standard video modes */
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- /* Minor 24..31 reserved for user defined video modes */
- { /* user0, initialized to Rx;y;d from commandline, if supplied */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user1 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user2 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user3 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user4 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user5 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user6 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user7 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }
};
-static int num_atari_fb_predefined=arraysize(atari_fb_predefined);
+static int num_atafb_predefined=arraysize(atafb_predefined);
static int
@@ -492,7 +450,7 @@ get_video_mode(char *vname)
char **name;
int i;
name_list=fb_var_names;
- for (i = 0 ; i < num_atari_fb_predefined ; i++) {
+ for (i = 0 ; i < num_atafb_predefined ; i++) {
name=*(name_list++);
if (! name || ! *name)
break;
@@ -512,7 +470,7 @@ get_video_mode(char *vname)
#ifdef ATAFB_TT
static int tt_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int mode;
@@ -539,7 +497,7 @@ static int tt_encode_fix( struct fb_fix_screeninfo *fix,
static int tt_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int xres=var->xres;
int yres=var->yres;
@@ -620,7 +578,7 @@ static int tt_decode_var( struct fb_var_screeninfo *var,
}
static int tt_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int linelen, i;
var->red.offset=0;
@@ -716,7 +674,7 @@ static int tt_encode_var( struct fb_var_screeninfo *var,
}
-static void tt_get_par( struct atari_fb_par *par )
+static void tt_get_par( struct atafb_par *par )
{
unsigned long addr;
par->hw.tt.mode=shifter_tt.tt_shiftmode;
@@ -727,7 +685,7 @@ static void tt_get_par( struct atari_fb_par *par )
par->screen_base = PTOV(addr);
}
-static void tt_set_par( struct atari_fb_par *par )
+static void tt_set_par( struct atafb_par *par )
{
shifter_tt.tt_shiftmode=par->hw.tt.mode;
shifter.syncmode=par->hw.tt.sync;
@@ -739,7 +697,7 @@ static void tt_set_par( struct atari_fb_par *par )
static int tt_getcolreg( unsigned regno, unsigned *red,
unsigned *green, unsigned *blue,
- unsigned *transp )
+ unsigned *transp, struct fb_info *info )
{
if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
regno += 254;
@@ -756,7 +714,7 @@ static int tt_getcolreg( unsigned regno, unsigned *red,
static int tt_setcolreg( unsigned regno, unsigned red,
unsigned green, unsigned blue,
- unsigned transp )
+ unsigned transp, struct fb_info *info )
{
if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
regno += 254;
@@ -772,7 +730,7 @@ static int tt_setcolreg( unsigned regno, unsigned red,
static int tt_detect( void )
-{ struct atari_fb_par par;
+{ struct atafb_par par;
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP, because the Sound
@@ -789,7 +747,7 @@ static int tt_detect( void )
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
tt_get_par(&par);
- tt_encode_var(&atari_fb_predefined[0], &par);
+ tt_encode_var(&atafb_predefined[0], &par);
return 1;
}
@@ -807,10 +765,6 @@ static int f030_bus_width; /* Falcon ram bus width (for vid_control) */
#define F_MON_VGA 2
#define F_MON_TV 3
-/* Multisync monitor capabilities */
-/* Atari-TOS defaults if no boot option present */
-static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000;
-
static struct pixel_clock {
unsigned long f; /* f/[Hz] */
unsigned long t; /* t/[ps] (=1/f) */
@@ -837,7 +791,7 @@ static inline int hxx_prescale(struct falcon_hw *hw)
}
static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
strcpy(fix->id, "Atari Builtin");
fix->smem_start = (char *)real_screen_base;
@@ -867,7 +821,7 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
static int falcon_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int bpp = var->bits_per_pixel;
int xres = var->xres;
@@ -943,7 +897,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
if (mon_type == F_MON_SM || DontCalcRes) {
/* Skip all calculations. VGA/TV/SC1224 only supported. */
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
if (bpp > myvar->bits_per_pixel ||
var->xres > myvar->xres ||
@@ -1069,11 +1023,14 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
/* Choose master pixelclock depending on hor. timing */
plen = 1 * xstretch;
- if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f)
+ if ((plen * xres + f25.right+f25.hsync+f25.left) *
+ fb_info.monspecs.hfmin < f25.f)
pclock = &f25;
- else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f)
+ else if ((plen * xres + f32.right+f32.hsync+f32.left) *
+ fb_info.monspecs.hfmin < f32.f)
pclock = &f32;
- else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f
+ else if ((plen * xres + fext.right+fext.hsync+fext.left) *
+ fb_info.monspecs.hfmin < fext.f
&& fext.f)
pclock = &fext;
else
@@ -1246,14 +1203,14 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
/* check hor. frequency */
hfreq = pclock->f / ((par->HHT+2)*prescale*2);
- if (hfreq > hfmax && mon_type!=F_MON_VGA) {
+ if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
/* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
/* Too high -> enlarge margin */
left_margin += 1;
right_margin += 1;
goto again;
}
- if (hfreq > hfmax || hfreq < hfmin)
+ if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
return -EINVAL;
/* Vxx-registers */
@@ -1282,45 +1239,52 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
/* V-frequency check, hope I didn't create any loop here. */
/* Interlace and doubleline are mutually exclusive. */
vfreq = (hfreq * 2) / (par->VFT + 1);
- if (vfreq > vfmax && !doubleline && !interlace) {
+ if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
/* Too high -> try again with doubleline */
doubleline = 1;
goto again;
}
- else if (vfreq < vfmin && !interlace && !doubleline) {
+ else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
/* Too low -> try again with interlace */
interlace = 1;
goto again;
}
- else if (vfreq < vfmin && doubleline) {
+ else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
/* Doubleline too low -> clear doubleline and enlarge margins */
int lines;
doubleline = 0;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>vfmax; lines++)
+ for (lines=0;
+ (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
+ lines++)
;
upper_margin += lines;
lower_margin += lines;
goto again;
}
- else if (vfreq > vfmax && doubleline) {
+ else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
/* Doubleline too high -> enlarge margins */
int lines;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines+=2)
+ for (lines=0;
+ (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+ lines+=2)
;
upper_margin += lines;
lower_margin += lines;
goto again;
}
- else if (vfreq > vfmax && interlace) {
+ else if (vfreq > fb_info.monspecs.vfmax && interlace) {
/* Interlace, too high -> enlarge margins */
int lines;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++)
+ for (lines=0;
+ (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+ lines++)
;
upper_margin += lines;
lower_margin += lines;
goto again;
}
- else if (vfreq < vfmin || vfreq > vfmax)
+ else if (vfreq < fb_info.monspecs.vfmin ||
+ vfreq > fb_info.monspecs.vfmax)
return -EINVAL;
set_screen_base:
@@ -1339,7 +1303,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
}
static int falcon_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
/* !!! only for VGA !!! */
int linelen, i;
@@ -1425,12 +1389,13 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->transp.msb_right=0;
linelen = var->xres_virtual * var->bits_per_pixel / 8;
- if (screen_len)
+ if (screen_len) {
if (par->yres_virtual)
var->yres_virtual = par->yres_virtual;
else
/* yres_virtual==0 means use maximum */
var->yres_virtual = screen_len / linelen;
+ }
else {
if (hwscroll < 0)
var->yres_virtual = 2 * var->yres;
@@ -1506,7 +1471,7 @@ static int f_change_mode = 0;
static struct falcon_hw f_new_mode;
static int f_pan_display = 0;
-static void falcon_get_par( struct atari_fb_par *par )
+static void falcon_get_par( struct atafb_par *par )
{
unsigned long addr;
struct falcon_hw *hw = &par->hw.falcon;
@@ -1543,7 +1508,7 @@ static void falcon_get_par( struct atari_fb_par *par )
((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
}
-static void falcon_set_par( struct atari_fb_par *par )
+static void falcon_set_par( struct atafb_par *par )
{
f_change_mode = 0;
@@ -1627,7 +1592,7 @@ static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
static int falcon_pan_display( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int xoffset;
int bpp = fb_display[currcon].var.bits_per_pixel;
@@ -1659,7 +1624,7 @@ static int falcon_pan_display( struct fb_var_screeninfo *var,
static int falcon_getcolreg( unsigned regno, unsigned *red,
unsigned *green, unsigned *blue,
- unsigned *transp )
+ unsigned *transp, struct fb_info *info )
{ unsigned long col;
if (regno > 255)
@@ -1679,7 +1644,7 @@ static int falcon_getcolreg( unsigned regno, unsigned *red,
static int falcon_setcolreg( unsigned regno, unsigned red,
unsigned green, unsigned blue,
- unsigned transp )
+ unsigned transp, struct fb_info *info )
{
if (regno > 255)
return 1;
@@ -1690,7 +1655,7 @@ static int falcon_setcolreg( unsigned regno, unsigned red,
(((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
((blue & 0xe) >> 1) | ((blue & 1) << 3);
#ifdef CONFIG_FBCON_CFB16
- packed16_cmap[regno] = (red << 11) | (green << 5) | blue;
+ fbcon_cfb16_cmap[regno] = (red << 11) | (green << 5) | blue;
#endif
}
return 0;
@@ -1738,7 +1703,7 @@ static int falcon_blank( int blank_mode )
static int falcon_detect( void )
{
- struct atari_fb_par par;
+ struct atafb_par par;
unsigned char fhw;
/* Determine connected monitor and set monitor parameters */
@@ -1748,18 +1713,18 @@ static int falcon_detect( void )
f030_bus_width = fhw << 6 & 0x80;
switch (mon_type) {
case F_MON_SM:
- vfmin = 70;
- vfmax = 72;
- hfmin = 35713;
- hfmax = 35715;
+ fb_info.monspecs.vfmin = 70;
+ fb_info.monspecs.vfmax = 72;
+ fb_info.monspecs.hfmin = 35713;
+ fb_info.monspecs.hfmax = 35715;
break;
case F_MON_SC:
case F_MON_TV:
/* PAL...NTSC */
- vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
- vfmax = 60;
- hfmin = 15620;
- hfmax = 15755;
+ fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
+ fb_info.monspecs.vfmax = 60;
+ fb_info.monspecs.hfmin = 15620;
+ fb_info.monspecs.hfmax = 15755;
break;
}
/* initialize hsync-len */
@@ -1769,7 +1734,7 @@ static int falcon_detect( void )
fext.hsync = h_syncs[mon_type] / fext.t;
falcon_get_par(&par);
- falcon_encode_var(&atari_fb_predefined[0], &par);
+ falcon_encode_var(&atafb_predefined[0], &par);
/* Detected mode is always the "autodetect" slot */
return 1;
@@ -1782,7 +1747,7 @@ static int falcon_detect( void )
#ifdef ATAFB_STE
static int stste_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int mode;
@@ -1813,7 +1778,7 @@ static int stste_encode_fix( struct fb_fix_screeninfo *fix,
static int stste_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int xres=var->xres;
int yres=var->yres;
@@ -1871,7 +1836,7 @@ static int stste_decode_var( struct fb_var_screeninfo *var,
}
static int stste_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int linelen, i;
var->red.offset=0;
@@ -1922,12 +1887,13 @@ static int stste_encode_var( struct fb_var_screeninfo *var,
if (! use_hwscroll)
var->yres_virtual=var->yres;
- else if (screen_len)
+ else if (screen_len) {
if (par->yres_virtual)
var->yres_virtual = par->yres_virtual;
else
/* yres_virtual==0 means use maximum */
var->yres_virtual = screen_len / linelen;
+ }
else {
if (hwscroll < 0)
var->yres_virtual = 2 * var->yres;
@@ -1948,7 +1914,7 @@ static int stste_encode_var( struct fb_var_screeninfo *var,
}
-static void stste_get_par( struct atari_fb_par *par )
+static void stste_get_par( struct atafb_par *par )
{
unsigned long addr;
par->hw.st.mode=shifter_tt.st_shiftmode;
@@ -1960,7 +1926,7 @@ static void stste_get_par( struct atari_fb_par *par )
par->screen_base = PTOV(addr);
}
-static void stste_set_par( struct atari_fb_par *par )
+static void stste_set_par( struct atafb_par *par )
{
shifter_tt.st_shiftmode=par->hw.st.mode;
shifter.syncmode=par->hw.st.sync;
@@ -1972,7 +1938,7 @@ static void stste_set_par( struct atari_fb_par *par )
static int stste_getcolreg( unsigned regno, unsigned *red,
unsigned *green, unsigned *blue,
- unsigned *transp )
+ unsigned *transp, struct fb_info *info )
{ unsigned col;
if (regno > 15)
@@ -1995,7 +1961,7 @@ static int stste_getcolreg( unsigned regno, unsigned *red,
static int stste_setcolreg( unsigned regno, unsigned red,
unsigned green, unsigned blue,
- unsigned transp )
+ unsigned transp, struct fb_info *info )
{
if (regno > 15)
return 1;
@@ -2015,7 +1981,7 @@ static int stste_setcolreg( unsigned regno, unsigned red,
static int stste_detect( void )
-{ struct atari_fb_par par;
+{ struct atafb_par par;
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP, because the Sound
@@ -2028,7 +1994,7 @@ static int stste_detect( void )
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
stste_get_par(&par);
- stste_encode_var(&atari_fb_predefined[0], &par);
+ stste_encode_var(&atafb_predefined[0], &par);
if (!ATARIHW_PRESENT(EXTD_SHIFTER))
use_hwscroll = 0;
@@ -2067,12 +2033,12 @@ static void stste_set_screen_base(unsigned long s_base)
#define SYNC_DELAY (mono_moni ? 1500 : 2000)
/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
-static void st_ovsc_switch(int switchmode)
+static void st_ovsc_switch(void)
{
unsigned long flags;
register unsigned char old, new;
- if ((switchmode & (SWITCH_ACIA | SWITCH_SND6 | SWITCH_SND7)) == 0)
+ if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
return;
save_flags(flags);
cli();
@@ -2093,11 +2059,15 @@ static void st_ovsc_switch(int switchmode)
mfp.tim_ct_b = 0x10;
udelay(SYNC_DELAY);
- if (switchmode == SWITCH_ACIA)
- acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE);
- else {
+ if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
+ if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+ if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | switchmode;
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+ ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
+ ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
}
restore_flags(flags);
}
@@ -2107,7 +2077,7 @@ static void st_ovsc_switch(int switchmode)
#ifdef ATAFB_EXT
static int ext_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
strcpy(fix->id,"Unknown Extern");
@@ -2157,9 +2127,9 @@ static int ext_encode_fix( struct fb_fix_screeninfo *fix,
static int ext_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
if (var->bits_per_pixel > myvar->bits_per_pixel ||
var->xres > myvar->xres ||
@@ -2173,7 +2143,7 @@ static int ext_decode_var( struct fb_var_screeninfo *var,
static int ext_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
int i;
@@ -2217,12 +2187,12 @@ static int ext_encode_var( struct fb_var_screeninfo *var,
}
-static void ext_get_par( struct atari_fb_par *par )
+static void ext_get_par( struct atafb_par *par )
{
par->screen_base = external_addr;
}
-static void ext_set_par( struct atari_fb_par *par )
+static void ext_set_par( struct atafb_par *par )
{
}
@@ -2238,10 +2208,8 @@ static void ext_set_par( struct atari_fb_par *par )
static int ext_getcolreg( unsigned regno, unsigned *red,
unsigned *green, unsigned *blue,
- unsigned *transp )
-
-{ unsigned char colmask = (1 << external_bitspercol) - 1;
-
+ unsigned *transp, struct fb_info *info )
+{
if (! external_vgaiobase)
return 1;
@@ -2254,7 +2222,7 @@ static int ext_getcolreg( unsigned regno, unsigned *red,
static int ext_setcolreg( unsigned regno, unsigned red,
unsigned green, unsigned blue,
- unsigned transp )
+ unsigned transp, struct fb_info *info )
{ unsigned char colmask = (1 << external_bitspercol) - 1;
@@ -2292,8 +2260,8 @@ static int ext_setcolreg( unsigned regno, unsigned red,
static int ext_detect( void )
{
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
- struct atari_fb_par dummy_par;
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+ struct atafb_par dummy_par;
myvar->xres = external_xres;
myvar->xres_virtual = external_xres_virtual;
@@ -2319,7 +2287,7 @@ static void set_screen_base(unsigned long s_base)
static int pan_display( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
+ struct atafb_par *par )
{
if (!fbhw->set_screen_base ||
(!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
@@ -2369,7 +2337,7 @@ static struct fb_hwswitch ext_switch = {
-static void atari_fb_get_par( struct atari_fb_par *par )
+static void atafb_get_par( struct atafb_par *par )
{
if (current_par_valid) {
*par=current_par;
@@ -2379,7 +2347,7 @@ static void atari_fb_get_par( struct atari_fb_par *par )
}
-static void atari_fb_set_par( struct atari_fb_par *par )
+static void atafb_set_par( struct atafb_par *par )
{
fbhw->set_par(par);
current_par=*par;
@@ -2396,7 +2364,7 @@ static void atari_fb_set_par( struct atari_fb_par *par )
/* used for hardware scrolling */
static int
-fb_update_var(int con)
+fb_update_var(int con, struct fb_info *info)
{
int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
fb_display[con].var.bits_per_pixel>>3;
@@ -2412,12 +2380,12 @@ static int
do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
{
int err,activate;
- struct atari_fb_par par;
+ struct atafb_par par;
if ((err=fbhw->decode_var(var, &par)))
return err;
activate=var->activate;
if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
- atari_fb_set_par(&par);
+ atafb_set_par(&par);
fbhw->encode_var(var, &par);
var->activate=activate;
return 0;
@@ -2426,17 +2394,17 @@ do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
/* Functions for handling colormap */
static void
-do_install_cmap(int con)
+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,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
&(fb_display[con].var), 1,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
}
@@ -2444,7 +2412,7 @@ do_install_cmap(int con)
* Open/Release the frame buffer device
*/
-static int atari_fb_open(int fbidx)
+static int atafb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -2454,7 +2422,7 @@ static int atari_fb_open(int fbidx)
return(0);
}
-static int atari_fb_release(int fbidx)
+static int atafb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
@@ -2462,11 +2430,11 @@ static int atari_fb_release(int fbidx)
static int
-atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
{
- struct atari_fb_par par;
+ struct atafb_par par;
if (con == -1)
- atari_fb_get_par(&par);
+ atafb_get_par(&par);
else
fbhw->decode_var(&fb_display[con].var,&par);
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
@@ -2474,11 +2442,11 @@ atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
}
static int
-atari_fb_get_var(struct fb_var_screeninfo *var, int con)
+atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
- struct atari_fb_par par;
+ struct atafb_par par;
if (con == -1) {
- atari_fb_get_par(&par);
+ atafb_get_par(&par);
fbhw->encode_var(var, &par);
}
else
@@ -2487,9 +2455,10 @@ atari_fb_get_var(struct fb_var_screeninfo *var, int con)
}
static void
-atari_fb_set_disp(int con)
+atafb_set_disp(int con, struct fb_info *info)
{
struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
struct display *display;
if (con >= 0)
@@ -2497,7 +2466,8 @@ atari_fb_set_disp(int con)
else
display = &disp; /* used during initialization */
- atari_fb_get_fix(&fix, con);
+ atafb_get_fix(&fix, con, info);
+ atafb_get_var(&var, con, info);
if (con == -1)
con=0;
display->screen_base = (u_char *)fix.smem_start;
@@ -2514,10 +2484,50 @@ atari_fb_set_disp(int con)
display->can_soft_blank = 1;
display->inverse =
(fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+ switch (fix.type) {
+ case FB_TYPE_INTERLEAVED_PLANES:
+ switch (var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_IPLAN2P2
+ case 2:
+ display->dispsw = &fbcon_iplan2p2;
+ break;
+#endif
+#ifdef CONFIG_FBCON_IPLAN2P4
+ case 4:
+ display->dispsw = &fbcon_iplan2p4;
+ break;
+#endif
+#ifdef CONFIG_FBCON_IPLAN2P8
+ case 8:
+ display->dispsw = &fbcon_iplan2p8;
+ break;
+#endif
+ }
+ break;
+ case FB_TYPE_PACKED_PIXELS:
+ switch (var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_MFB
+ case 1:
+ display->dispsw = &fbcon_mfb;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ }
+ break;
+ }
}
static int
-atari_fb_set_var(struct fb_var_screeninfo *var, int con)
+atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
int err,oldxres,oldyres,oldbpp,oldxres_virtual,
oldyres_virtual,oldyoffset;
@@ -2536,10 +2546,10 @@ atari_fb_set_var(struct fb_var_screeninfo *var, int con)
|| oldyres_virtual != var->yres_virtual
|| oldbpp != var->bits_per_pixel
|| oldyoffset != var->yoffset) {
- atari_fb_set_disp(con);
+ atafb_set_disp(con, info);
(*fb_info.changevar)(con);
fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
}
var->activate=0;
@@ -2549,22 +2559,22 @@ atari_fb_set_var(struct fb_var_screeninfo *var, int con)
static int
-atari_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+atafb_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,
- fbhw->getcolreg);
+ fbhw->getcolreg, info);
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
static int
-atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+atafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
int err;
if (! fb_display[con].cmap.len) { /* no colormap allocated ? */
@@ -2575,14 +2585,14 @@ atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
}
if (con == currcon) /* current console ? */
return fb_set_cmap(cmap, &(fb_display[con].var), kspc,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
}
static int
-atari_fb_pan_display(struct fb_var_screeninfo *var, int con)
+atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
int xoffset = var->xoffset;
int yoffset = var->yoffset;
@@ -2606,33 +2616,33 @@ atari_fb_pan_display(struct fb_var_screeninfo *var, int con)
}
static int
-atari_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg, int con)
+atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info)
{
switch (cmd) {
#ifdef FBCMD_GET_CURRENTPAR
case FBCMD_GET_CURRENTPAR:
if (copy_to_user((void *)arg, (void *)&current_par,
- sizeof(struct atari_fb_par)))
+ sizeof(struct atafb_par)))
return -EFAULT;
return 0;
#endif
#ifdef FBCMD_SET_CURRENTPAR
case FBCMD_SET_CURRENTPAR:
if (copy_from_user((void *)&current_par, (void *)arg,
- sizeof(struct atari_fb_par)))
+ sizeof(struct atafb_par)))
return -EFAULT;
- atari_fb_set_par(&current_par);
+ atafb_set_par(&current_par);
return 0;
#endif
}
return -EINVAL;
}
-static struct fb_ops atari_fb_ops = {
- atari_fb_open, atari_fb_release, atari_fb_get_fix, atari_fb_get_var,
- atari_fb_set_var, atari_fb_get_cmap, atari_fb_set_cmap,
- atari_fb_pan_display, atari_fb_ioctl
+static struct fb_ops atafb_ops = {
+ atafb_open, atafb_release, atafb_get_fix, atafb_get_var,
+ atafb_set_var, atafb_get_cmap, atafb_set_cmap,
+ atafb_pan_display, NULL, atafb_ioctl
};
static void
@@ -2645,14 +2655,14 @@ check_default_par( int detected_mode )
/* First try the user supplied mode */
if (default_par) {
- var=atari_fb_predefined[default_par-1];
+ var=atafb_predefined[default_par-1];
var.activate = FB_ACTIVATE_TEST;
if (do_fb_set_var(&var,1))
default_par=0; /* failed */
}
/* Next is the autodetected one */
if (! default_par) {
- var=atari_fb_predefined[detected_mode-1]; /* autodetect */
+ var=atafb_predefined[detected_mode-1]; /* autodetect */
var.activate = FB_ACTIVATE_TEST;
if (!do_fb_set_var(&var,1))
default_par=detected_mode;
@@ -2665,7 +2675,7 @@ check_default_par( int detected_mode )
default_par=get_video_mode(default_name);
if (! default_par)
panic("can't set default video mode\n");
- var=atari_fb_predefined[default_par-1];
+ var=atafb_predefined[default_par-1];
var.activate = FB_ACTIVATE_TEST;
if (! do_fb_set_var(&var,1))
break; /* ok */
@@ -2677,16 +2687,17 @@ check_default_par( int detected_mode )
}
static int
-atafb_switch(int con)
+atafb_switch(int con, struct fb_info *info)
{
/* 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, fbhw->getcolreg);
+ &(fb_display[currcon].var), 1, fbhw->getcolreg,
+ info);
do_fb_set_var(&fb_display[con].var,1);
currcon=con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -2698,7 +2709,7 @@ atafb_switch(int con)
* 4 = off
*/
static void
-atafb_blank(int blank)
+atafb_blank(int blank, struct fb_info *info)
{
unsigned short black[16];
struct fb_cmap cmap;
@@ -2713,19 +2724,13 @@ atafb_blank(int blank)
cmap.start=0;
cmap.len=16;
fb_set_cmap(&cmap, &(fb_display[currcon].var), 1,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
}
else
- do_install_cmap(currcon);
-}
-
-static int
-atafb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(atari_fb_set_cmap(cmap, 1, con));
+ do_install_cmap(currcon, info);
}
-__initfunc(unsigned long atari_fb_init(unsigned long mem_start))
+__initfunc(unsigned long atafb_init(unsigned long mem_start))
{
int err;
int pad;
@@ -2770,6 +2775,16 @@ __initfunc(unsigned long atari_fb_init(unsigned long mem_start))
panic("Cannot initialize video hardware\n");
#endif
} while (0);
+
+ /* Multisync monitor capabilities */
+ /* Atari-TOS defaults if no boot option present */
+ if (fb_info.monspecs.hfmin == 0) {
+ fb_info.monspecs.hfmin = 31000;
+ fb_info.monspecs.hfmax = 32000;
+ fb_info.monspecs.vfmin = 58;
+ fb_info.monspecs.vfmax = 62;
+ }
+
detected_mode = fbhw->detect();
check_default_par(detected_mode);
#ifdef ATAFB_EXT
@@ -2778,13 +2793,14 @@ __initfunc(unsigned long atari_fb_init(unsigned long mem_start))
mem_req = default_mem_req + ovsc_offset +
ovsc_addlen;
mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE;
- screen_base = (unsigned long) atari_stram_alloc(mem_req, &mem_start);
+ screen_base = (unsigned long)atari_stram_alloc(mem_req, &mem_start,
+ "atafb");
memset((char *) screen_base, 0, mem_req);
pad = ((screen_base + PAGE_SIZE-1) & PAGE_MASK) - screen_base;
screen_base+=pad;
real_screen_base=screen_base+ovsc_offset;
screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
- st_ovsc_switch(ovsc_switchmode);
+ st_ovsc_switch();
if (CPU_IS_040_OR_060) {
/* On a '040+, the cache mode of video RAM must be set to
* write-through also for internal video hardware! */
@@ -2815,32 +2831,29 @@ __initfunc(unsigned long atari_fb_init(unsigned long mem_start))
strcpy(fb_info.modename, "Atari Builtin ");
fb_info.changevar = NULL;
fb_info.node = -1;
- fb_info.fbops = &atari_fb_ops;
- fb_info.fbvar_num = num_atari_fb_predefined;
- fb_info.fbvar = atari_fb_predefined;
+ fb_info.fbops = &atafb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &atafb_switch;
fb_info.updatevar = &fb_update_var;
fb_info.blank = &atafb_blank;
- fb_info.setcmap = &atafb_setcmap;
- do_fb_set_var(&atari_fb_predefined[default_par-1], 1);
+ do_fb_set_var(&atafb_predefined[default_par-1], 1);
strcat(fb_info.modename, fb_var_names[default_par-1][0]);
err=register_framebuffer(&fb_info);
if (err < 0)
return(err);
- atari_fb_get_var(&disp.var, -1);
- atari_fb_set_disp(-1);
+ atafb_get_var(&disp.var, -1, &fb_info);
+ atafb_set_disp(-1, &fb_info);
printk("Determined %dx%d, depth %d\n",
disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
if ((disp.var.xres != disp.var.xres_virtual) ||
(disp.var.yres != disp.var.yres_virtual))
printk(" virtual %dx%d\n",
disp.var.xres_virtual, disp.var.yres_virtual);
- do_install_cmap(0);
- printk("%s frame buffer device, using %dK of video memory\n",
- fb_info.modename, screen_len>>10);
+ do_install_cmap(0, &fb_info);
+ printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename, screen_len>>10);
/* TODO: This driver cannot be unloaded yet */
MOD_INC_USE_COUNT;
@@ -2870,7 +2883,7 @@ static char * strtoke(char * s,const char * ct)
return sbegin;
}
-__initfunc(void atari_video_setup( char *options, int *ints ))
+__initfunc(void atafb_setup( char *options, int *ints ))
{
char *this_opt;
int temp;
@@ -2902,15 +2915,6 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
if (hwscroll > 200)
hwscroll = 200;
}
- else if (! strncmp(this_opt, "sw_",3)) {
- if (! strcmp(this_opt+3, "acia"))
- ovsc_switchmode = SWITCH_ACIA;
- else if (! strcmp(this_opt+3, "snd6"))
- ovsc_switchmode = SWITCH_SND6;
- else if (! strcmp(this_opt+3, "snd7"))
- ovsc_switchmode = SWITCH_SND7;
- else ovsc_switchmode = SWITCH_NONE;
- }
#ifdef ATAFB_EXT
else if (!strcmp(this_opt,"mv300")) {
external_bitspercol = 8;
@@ -2939,12 +2943,8 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
if (*int_str) {
/* Format to config extended internal video hardware like OverScan:
- "<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+ "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
Explanation:
- <switch-type> type to switch on higher resolution
- sw_acia : via keyboard ACIA
- sw_snd6 : via bit 6 of the soundchip port
- sw_snd7 : via bit 7 of the soundchip port
<xres>: x-resolution
<yres>: y-resolution
The following are only needed if you have an overscan which
@@ -2974,9 +2974,9 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
if (ovsc_offset || (sttt_yres_virtual != st_yres))
use_hwscroll=0;
+ int_invalid:
+ ;
}
- else
- int_invalid: ovsc_switchmode = SWITCH_NONE;
#ifdef ATAFB_EXT
if (*ext_str) {
@@ -3103,10 +3103,10 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
hmax = 1000 * simple_strtoul(p, NULL, 10);
if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
- vfmin = vmin;
- vfmax = vmax;
- hfmin = hmin;
- hfmax = hmax;
+ fb_info.monspecs.vfmin = vmin;
+ fb_info.monspecs.vfmax = vmax;
+ fb_info.monspecs.hfmin = hmin;
+ fb_info.monspecs.hfmax = hmax;
cap_invalid:
;
}
@@ -3126,9 +3126,9 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
depth = simple_strtoul(p, NULL, 10);
if ((temp=get_video_mode("user0"))) {
default_par=temp;
- atari_fb_predefined[default_par-1].xres = xres;
- atari_fb_predefined[default_par-1].yres = yres;
- atari_fb_predefined[default_par-1].bits_per_pixel = depth;
+ atafb_predefined[default_par-1].xres = xres;
+ atafb_predefined[default_par-1].yres = yres;
+ atafb_predefined[default_par-1].bits_per_pixel = depth;
}
user_invalid:
@@ -3139,7 +3139,7 @@ __initfunc(void atari_video_setup( char *options, int *ints ))
#ifdef MODULE
int init_module(void)
{
- return(atari_fb_init(NULL));
+ return(atafb_init(NULL));
}
void cleanup_module(void)
@@ -3147,6 +3147,7 @@ void cleanup_module(void)
/* Not reached because the usecount will never
be decremented to zero */
unregister_framebuffer(&fb_info);
- /* TODO: clean up ... */
+ /* atari_stram_free( screen_base ); */
+ /* TODO: further clean up ... */
}
#endif /* MODULE */
diff --git a/drivers/video/ati-gt.h b/drivers/video/ati-gt.h
new file mode 100644
index 000000000..32dc792b5
--- /dev/null
+++ b/drivers/video/ati-gt.h
@@ -0,0 +1,203 @@
+/* the usage for the following structs vary from the gx and vt:
+and sdram and sgram gt's
+ pll registers (sdram) 6,7,11;
+ crtc_h_sync_strt_wid[3];
+ dsp1[3] (sdram,sgram,unused)
+ dsp2[3] (offset regbase+24, depends on colour mode);
+ crtc_h_tot_disp,crtc_v_tot_disp,crtc_v_sync_strt_wid,unused;
+ pll registers (sgram) 7,11;
+*/
+
+/* Register values for 1280x1024, 75Hz mode (20). no 16/32 */
+static struct aty_regvals aty_gt_reg_init_20 = {
+ { 0x41, 0xf9, 0x04 },
+ { 0xe02a7, 0x1401a6, 0 },
+ { 0x260957, 0x2806d6, 0 },
+ { 0x10006b6, 0x20006b6, 0x30006b6 },
+
+ 0x9f00d2, 0x03ff0429, 0x30400, 0,
+ { 0xb5, 0x04 }
+};
+
+#if 0
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct aty_regvals aty_gt_reg_init_19 = {
+};
+#endif
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_gt_reg_init_18 = {
+ { 0x41, 0xe6, 0x04 },
+ { 0x300295, 0x300194, 0x300593 },
+ { 0x260a1c, 0x380561, 0},
+ { 0x1000744, 0x2000744, 0x3000744 },
+
+ 0x8f00b5, 0x3650392, 0x230368, 0,
+ { 0xe6, 0x04 }
+};
+
+/* Register values for 1024x768, 75Hz mode (17), 32 bpp untested */
+static struct aty_regvals aty_gt_reg_init_17 = {
+ { 0x41, 0xb5, 0x04 },
+ { 0xc0283, 0xc0182, 0xc0581 },
+ { 0x36066d, 0x3806d6, 0},
+ { 0xa0049e, 0x100049e, 0x200049e },
+
+ 0x7f00a3, 0x2ff031f, 0x30300, 0,
+ { 0xb8, 0x04 }
+};
+
+#if 0
+/* Register values for x, Hz mode (16) */
+static struct aty_regvals aty_gt_reg_init_16 = {
+};
+#endif
+
+/* Register values for 1024x768, 70Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+ { 0x41, 0xad, 0x04 },
+ { 0x310284, 0x310183, 0x310582 },
+ { 0x0, 0x380727 },
+ { 0x0 },
+ 0x7f00a5, 0x2ff0325, 0x260302,
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_gt_reg_init_14 = {
+ { 0x40, 0xe1, 0x14 },
+ { 0x310284, 0x310183, 0x310582 },
+ { 0x3607c0, 0x380840, 0x0 },
+ { 0xa80592, 0x1000592, 0x0 },
+
+ 0x7f00a7, 0x2ff0325, 0x260302, 0,
+ { 0xe1, 0x14 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_gt_reg_init_13 = {
+ { 0x40, 0xc6, 0x14 },
+ { 0x28026d, 0x28016c, 0x28056b },
+ { 0x3608cf, 0x380960, 0 },
+ { 0xb00655, 0x1000655, 0x2000655 },
+
+ 0x67008f, 0x26f029a, 0x230270, 0,
+ { 0xc6, 0x14 }
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_gt_reg_init_12 = {
+ { 0x42, 0xe4, 0x04 },
+ { 0xa0267, 0xa0166, 0x0a0565},
+ { 0x360a33, 0x48056d, 0},
+ { 0xc00755, 0x1000755, 0x02000755},
+
+ 0x630083, 0x2570270, 0x30258, 0,
+ { 0xe4, 0x4 }
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_gt_reg_init_11 = {
+ { 0x42, 0xe6, 0x04 },
+ { 0xf026c, 0xf016b, 0xf056a },
+ { 0x360a1d, 0x480561, 0},
+ { 0xc00745, 0x1000745, 0x2000745 },
+
+ 0x630081, 0x02570299, 0x6027c
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_gt_reg_init_10 = {
+ { 0x42, 0xb8, 0x04 },
+ { 0x10026a, 0x100169, 0x100568 },
+ { 0x460652, 0x4806ba, 0},
+ { 0x68048b, 0xa0048b, 0x100048b },
+
+ 0x630083, 0x02570273, 0x40258, 0,
+ { 0xb8, 0x4 }
+};
+
+/* Register values for 800x600, 56Hz mode (9) */
+static struct aty_regvals aty_gt_reg_init_9 = {
+ { 0x42, 0xf9, 0x14 },
+ { 0x90268, 0x90167, 0x090566 },
+ { 0x460701, 0x480774, 0},
+ { 0x700509, 0xa80509, 0x1000509 },
+
+ 0x63007f, 0x2570270, 0x20258
+};
+
+#if 0
+/* Register values for 768x576, 50Hz mode (8) */
+static struct aty_regvals aty_gt_reg_init_8 = {
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_gt_reg_init_7 = {
+};
+#endif
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_gt_reg_init_6 = {
+ { 0x42, 0xd1, 0x14 },
+ { 0x280259, 0x280158, 0x280557 },
+ { 0x460858, 0x4808e2, 0},
+ { 0x780600, 0xb00600, 0x1000600 },
+
+ 0x4f006b, 0x1df020c, 0x2301e2, 0,
+ { 0x8b, 0x4 }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_gt_reg_init_5 = {
+ { 0x43, 0xe8, 0x04 },
+ { 0x2c0253, 0x2c0152, 0x2c0551 },
+ { 0x460a06, 0x580555, 0},
+ { 0x880734, 0xc00734, 0x1000734 },
+
+ 0x4f0063, 0x1df020c, 0x2201e9, 0,
+ { 0xe8, 0x04 }
+};
+
+#if 0
+/* Register values for x, Hz mode (4) */
+static struct aty_regvals aty_gt_reg_init_4 = {
+};
+
+/* Register values for x, Hz mode (3) */
+static struct aty_regvals aty_gt_reg_init_3 = {
+};
+
+/* Register values for x, Hz mode (2) */
+static struct aty_regvals aty_gt_reg_init_2 = {
+};
+
+/* Register values for x, Hz mode (1) */
+static struct aty_regvals aty_gt_reg_init_1 = {
+};
+#endif
+
+/* yikes, more data structures (dsp2)
+ * XXX kludge for sgram
+ */
+static int sgram_dsp[20][3] = {
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0x5203d7,0x7803d9,0xb803dd}, //5
+ {0x940666,0xe0066a,0x1700672}, //6
+ {0,0,0},
+ {0,0,0},
+ {0x88055f,0xd80563,0x170056b}, //9
+ {0x8404d9,0xb804dd,0x17004e5}, //10
+ {0x7803e2,0xb803e6,0x17003ee}, //11
+ {0x7803eb,0xb803ef,0x17003f7}, //12
+ {0xe806c5,0x17006cd,0x2e006dd}, //13
+ {0xe005f6,0x17005fe,0x2e0060e}, //14
+ {0xd8052c,0x1700534,0x2e00544}, //15
+ {0,0,0},
+ {0xb804f2,0x17004e5,0x2e0050a}, //17
+ {0xb803e6,0x17003ee,0x2e003fe}, //18
+ {0,0,0},
+ {0,0,0},
+};
diff --git a/drivers/video/ati-gx.h b/drivers/video/ati-gx.h
new file mode 100644
index 000000000..df48c1865
--- /dev/null
+++ b/drivers/video/ati-gx.h
@@ -0,0 +1,122 @@
+/* Register values for 1280x1024, 75Hz (WAS 60) mode (20) */
+static struct aty_regvals aty_gx_reg_init_20 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x1200a5, 0x1200a3, 0x1200a3 },
+ { 0x30c0200, 0x30e0300, 0x30e0300 },
+ { 0x2, 0x3, 0x3 },
+
+ 0x9f00d2, 0x3ff0429, 0x30400, 0x28100040,
+ { 0xd4, 0x9 }
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_gx_reg_init_18 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x300097, 0x300095, 0x300094 },
+ { 0x3090200, 0x30e0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
+
+ 0x8f00b5, 0x3650392, 0x230368, 0x24100040,
+ { 0x53, 0x3 }
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gx_reg_init_17 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x2c0087, 0x2c0085, 0x2c0084 },
+ { 0x3070200, 0x30e0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
+
+ 0x7f00a5, 0x2ff0323, 0x230302, 0x20100000,
+ { 0x42, 0x3 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gx_reg_init_15 = {
+ { 0, 0, 0 },
+
+ { 0x310086, 0x310084, 0x310084 },
+ { 0x3070200, 0x30e0300, 0x30e0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+ { 0x88, 0x7 }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_gx_reg_init_14 = {
+ { 0, 0, 0 },
+
+ { 0x310086, 0x310084, 0x310084 },
+ { 0x3060200, 0x30d0300, 0x30d0300 },
+ { 0x2002312, 0x3002312, 0x3002312 },
+
+ 0x7f00a7, 0x2ff0325, 0x260302, 0x20100000,
+ { 0x6c, 0x6 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_gx_reg_init_13 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x28006f, 0x28006d, 0x28006c },
+ { 0x3050200, 0x30b0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
+
+ 0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+ { 0x4f, 0x5 }
+};
+
+#if 0 /* not filled in yet */
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_gx_reg_init_12 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_gx_reg_init_11 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_gx_reg_init_10 = {
+ { 0x10, 0x28, 0x50 },
+ { },
+ { } /* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_gx_reg_init_7 = {
+ { 0x10, 0x30, 0x68 },
+ { },
+ { } /* pixel clock = 57.29MHz for V=75.01Hz */
+};
+#endif
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_gx_reg_init_6 = {
+ { 0x200, 0x200, 0x200 },
+
+ { 0x28005b, 0x280059, 0x280058 },
+ { 0x3040200, 0x3060300, 0x30c0600 },
+ { 0x2002312, 0x3002312, 0x6002312 },
+
+ 0x4f006b, 0x1df020c, 0x2301e2, 0x14100040,
+ { 0x35, 0x07 }
+};
+
+#if 0 /* not filled in yet */
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_gx_reg_init_5 = {
+ { 0x200, 0x200, 0x200 },
+ { },
+ { 0x35, 0x07 }
+};
+#endif
diff --git a/drivers/video/ati-vt.h b/drivers/video/ati-vt.h
new file mode 100644
index 000000000..3b25d6d5d
--- /dev/null
+++ b/drivers/video/ati-vt.h
@@ -0,0 +1,147 @@
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_vt_reg_init_20 = {
+ { 0, 0, 0 },
+
+ { 0x002e02a7, 0x002e02a7, 0 },
+ { 0x03070200, 0x03070200, 0 },
+ { 0x0a00cb22, 0x0b00cb23, 0 },
+
+ 0x009f00d2, 0x03ff0429, 0x00030400, 0x28000000,
+ { 0x00, 0xaa }
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct aty_regvals aty_vt_reg_init_19 = {
+ { 0, 0, 0 },
+ { 0x003202a3, 0x003201a2, 0 },
+ { 0x030b0200, 0x030b0300, 0 },
+ { 0x0a00cb22, 0x0b00cb23, 0 },
+
+ 0x009f00d1, 0x03bf03e7, 0x000303c0, 0x28000000,
+ { 0x00, 0xc6 }
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_vt_reg_init_18 = {
+ { 0, 0, 0 },
+
+ { 0x00300295, 0x00300194, 0 },
+ { 0x03080200, 0x03080300, 0 },
+ { 0x0a00cb21, 0x0b00cb22, 0 },
+
+ 0x008f00b5, 0x03650392, 0x00230368, 0x24000000,
+ { 0x00, 0x9d }
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_vt_reg_init_17 = {
+ { 0, 0, 0 },
+
+ { 0x002c0283, 0x002c0182, 0 },
+ { 0x03080200, 0x03080300, 0 },
+ { 0x0a00cb21, 0x0b00cb22, 0 },
+
+ 0x007f00a3, 0x02ff031f, 0x00030300, 0x20000000,
+ { 0x01, 0xf7 }
+};
+
+/* Register values for 1024x768, 70Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+ { 0, 0, 0 },
+ { 0x00310284, 0x00310183, 0 },
+ { 0x03080200, 0x03080300, 0 },
+ { 0x0a00cb21, 0x0b00cb22, 0 },
+
+ 0x007f00a5, 0x02ff0325, 0x00260302, 0x20000000,
+ { 0x01, 0xeb }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_vt_reg_init_14 = {
+ { 0, 0, 0 },
+
+ { 0x00310284, 0x00310183, 0x00310582 }, /* 32 bit 0x00310582 */
+ { 0x03080200, 0x03080300, 0x03070600 }, /* 32 bit 0x03070600 */
+ { 0x0a00cb21, 0x0b00cb22, 0x0e00cb23 },
+
+ 0x007f00a7, 0x02ff0325, 0x00260302, 0x20000000,
+ { 0x01, 0xcc }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_vt_reg_init_13 = {
+ { 0, 0, 0 },
+
+ { 0x0028026d, 0x0028016c, 0x0028056b },
+ { 0x03080200, 0x03070300, 0x03090600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x0067008f, 0x026f029a, 0x00230270, 0x1a000000,
+ { 0x01, 0xb4 }
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_vt_reg_init_12 = {
+ { 0, 0, 0 },
+
+ { 0x002a0267, 0x002a0166, 0x002a0565 },
+ { 0x03040200, 0x03060300, 0x03070600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x00630083, 0x02570270, 0x00030258, 0x19000000,
+ { 0x01, 0x9c }
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_vt_reg_init_11 = {
+ { 0, 0, 0 },
+
+ { 0x002f026c, 0x002f016b, 0x002f056a },
+ { 0x03050200, 0x03070300, 0x03090600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x00630081, 0x02570299, 0x0006027c, 0x19000000,
+ { 0x01, 0x9d }
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_vt_reg_init_10 = {
+ { 0, 0, 0 },
+
+ { 0x0030026a, 0x00300169, 0x00300568 },
+ { 0x03050200, 0x03070300, 0x03090600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x00630083, 0x02570273, 0x00040258, 0x19000000,
+ { 0x02, 0xfb }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_vt_reg_init_6 = {
+ { 0, 0, 0 },
+
+ { 0x00280259, 0x00280158, 0x00280557 },
+ { 0x03050200, 0x03070300, 0x030a0600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x004f006b, 0x01df020c, 0x002301e2, 0x14000000,
+ { 0x02, 0xbe }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_vt_reg_init_5 = {
+ { 0, 0, 0 },
+
+ { 0x002c0253, 0x002c0152, 0x002c0551 },
+ { 0x03050200, 0x03070300, 0x03090600 },
+ { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 },
+
+ 0x004f0063, 0x01df020c, 0x002201e9, 0x14000000,
+ { 0x02, 0x9e }
+};
+ /* 8 bit 15 bit 32 bit */
+static int vt_mem_cntl[3][3] = { { 0x0A00CB21, 0x0B00CB21, 0x0E00CB21 }, /* 1 MB VRAM */
+ { 0x0A00CB22, 0x0B00CB22, 0x0E00CB22 }, /* 2 MB VRAM */
+ { 0x0200053B, 0x0300053B, 0x0600053B } /* 4 M B VRAM */
+ };
+
diff --git a/drivers/video/aty.h b/drivers/video/aty.h
new file mode 100644
index 000000000..7c9b00ad7
--- /dev/null
+++ b/drivers/video/aty.h
@@ -0,0 +1,923 @@
+/*
+ * Exported procedures for the ATI/mach64 display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ * written with much help from Jon Howell
+ *
+ * Updated for 3D RAGE PRO by Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+/*
+ * most of the rest of this file comes from ATI sample code
+ */
+#ifndef REGMACH64_H
+#define REGMACH64_H
+
+/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
+
+#define CRTC_H_TOTAL_DISP 0x0000 /* Dword offset 0_00 */
+#define CRTC_H_SYNC_STRT_WID 0x0004 /* Dword offset 0_01 */
+#define CRTC_H_SYNC_STRT 0x0004
+#define CRTC_H_SYNC_DLY 0x0005
+#define CRTC_H_SYNC_WID 0x0006
+
+#define CRTC_V_TOTAL_DISP 0x0008 /* Dword offset 0_02 */
+#define CRTC_V_TOTAL 0x0008
+#define CRTC_V_DISP 0x000A
+#define CRTC_V_SYNC_STRT_WID 0x000C /* Dword offset 0_03 */
+#define CRTC_V_SYNC_STRT 0x000C
+#define CRTC_V_SYNC_WID 0x000E
+
+#define CRTC_VLINE_CRNT_VLINE 0x0010 /* Dword offset 0_04 */
+#define CRTC_OFF_PITCH 0x0014 /* Dword offset 0_05 */
+#define CRTC_OFFSET 0x0014
+#define CRTC_PITCH 0x0016
+
+#define CRTC_INT_CNTL 0x0018 /* Dword offset 0_06 */
+#define CRTC_GEN_CNTL 0x001C /* Dword offset 0_07 */
+#define CRTC_PIX_WIDTH 0x001D
+#define CRTC_FIFO 0x001E
+#define CRTC_EXT_DISP 0x001F
+
+#define DSP_CONFIG 0x0020 /* Dword offset 0_08 */
+#define DSP_ON_OFF 0x0024 /* Dword offset 0_09 */
+#define TIMER_CONFIG 0x0028 /* Dword offset 0_0A */
+#define MEM_BUF_CNTL 0x002C /* Dword offset 0_0B */
+#define MEM_ADDR_CONFIG 0x0034 /* Dword offset 0_0D */
+
+#define CRT_TRAP 0x0038 /* Dword offset 0_0E */
+
+#define I2C_CNTL_0 0x003C /* Dword offset 0_0F */
+
+#define OVR_CLR 0x0040 /* Dword offset 0_10 */
+#define OVR_WID_LEFT_RIGHT 0x0044 /* Dword offset 0_11 */
+#define OVR_WID_TOP_BOTTOM 0x0048 /* Dword offset 0_12 */
+
+#define VGA_DSP_CONFIG 0x004C /* Dword offset 0_13 */
+#define VGA_DSP_ON_OFF 0x0050 /* Dword offset 0_14 */
+
+#define CUR_CLR0 0x0060 /* Dword offset 0_18 */
+#define CUR_CLR1 0x0064 /* Dword offset 0_19 */
+#define CUR_OFFSET 0x0068 /* Dword offset 0_1A */
+#define CUR_HORZ_VERT_POSN 0x006C /* Dword offset 0_1B */
+#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */
+
+#define GP_IO 0x0078 /* Dword offset 0_1E */
+
+#define HW_DEBUG 0x007C /* Dword offset 0_1F */
+
+#define SCRATCH_REG0 0x0080 /* Dword offset 0_20 */
+#define SCRATCH_REG1 0x0084 /* Dword offset 0_21 */
+
+#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */
+#define CLOCK_SEL_CNTL 0x0090 /* Dword offset 0_24 */
+
+#define CONFIG_STAT1 0x0094 /* Dword offset 0_25 */
+#define CONFIG_STAT2 0x0098 /* Dword offset 0_26 */
+
+#define BUS_CNTL 0x00A0 /* Dword offset 0_28 */
+
+#define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */
+#define MEM_CNTL 0x00B0 /* Dword offset 0_2C */
+
+#define MEM_VGA_WP_SEL 0x00B4 /* Dword offset 0_2D */
+#define MEM_VGA_RP_SEL 0x00B8 /* Dword offset 0_2E */
+
+#define DAC_REGS 0x00C0 /* Dword offset 0_30 */
+#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */
+#define DAC_DATA 0x00C1 /* Dword offset 0_30 */
+#define DAC_MASK 0x00C2 /* Dword offset 0_30 */
+#define DAC_R_INDEX 0x00C3 /* Dword offset 0_30 */
+#define DAC_CNTL 0x00C4 /* Dword offset 0_31 */
+
+#define EXT_DAC_REGS 0x00C8 /* Dword offset 0_32 */
+
+#define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */
+
+#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */
+
+#define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */
+#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */
+#define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */
+#define CRC_SIG 0x00E8 /* Dword offset 0_3A */
+
+
+/* GUI MEMORY MAPPED Registers */
+
+#define DST_OFF_PITCH 0x0100 /* Dword offset 0_40 */
+#define DST_X 0x0104 /* Dword offset 0_41 */
+#define DST_Y 0x0108 /* Dword offset 0_42 */
+#define DST_Y_X 0x010C /* Dword offset 0_43 */
+#define DST_WIDTH 0x0110 /* Dword offset 0_44 */
+#define DST_HEIGHT 0x0114 /* Dword offset 0_45 */
+#define DST_HEIGHT_WIDTH 0x0118 /* Dword offset 0_46 */
+#define DST_X_WIDTH 0x011C /* Dword offset 0_47 */
+#define DST_BRES_LNTH 0x0120 /* Dword offset 0_48 */
+#define DST_BRES_ERR 0x0124 /* Dword offset 0_49 */
+#define DST_BRES_INC 0x0128 /* Dword offset 0_4A */
+#define DST_BRES_DEC 0x012C /* Dword offset 0_4B */
+#define DST_CNTL 0x0130 /* Dword offset 0_4C */
+#define DST_Y_X__ALIAS__ 0x0134 /* Dword offset 0_4D */
+#define TRAIL_BRES_ERR 0x0138 /* Dword offset 0_4E */
+#define TRAIL_BRES_INC 0x013C /* Dword offset 0_4F */
+#define TRAIL_BRES_DEC 0x0140 /* Dword offset 0_50 */
+#define LEAD_BRES_LNTH 0x0144 /* Dword offset 0_51 */
+#define Z_OFF_PITCH 0x0148 /* Dword offset 0_52 */
+#define Z_CNTL 0x014C /* Dword offset 0_53 */
+#define ALPHA_TST_CNTL 0x0150 /* Dword offset 0_54 */
+#define SECONDARY_STW_EXP 0x0158 /* Dword offset 0_56 */
+#define SECONDARY_S_X_INC 0x015C /* Dword offset 0_57 */
+#define SECONDARY_S_Y_INC 0x0160 /* Dword offset 0_58 */
+#define SECONDARY_S_START 0x0164 /* Dword offset 0_59 */
+#define SECONDARY_W_X_INC 0x0168 /* Dword offset 0_5A */
+#define SECONDARY_W_Y_INC 0x016C /* Dword offset 0_5B */
+#define SECONDARY_W_START 0x0170 /* Dword offset 0_5C */
+#define SECONDARY_T_X_INC 0x0174 /* Dword offset 0_5D */
+#define SECONDARY_T_Y_INC 0x0178 /* Dword offset 0_5E */
+#define SECONDARY_T_START 0x017C /* Dword offset 0_5F */
+
+#define SRC_OFF_PITCH 0x0180 /* Dword offset 0_60 */
+#define SRC_X 0x0184 /* Dword offset 0_61 */
+#define SRC_Y 0x0188 /* Dword offset 0_62 */
+#define SRC_Y_X 0x018C /* Dword offset 0_63 */
+#define SRC_WIDTH1 0x0190 /* Dword offset 0_64 */
+#define SRC_HEIGHT1 0x0194 /* Dword offset 0_65 */
+#define SRC_HEIGHT1_WIDTH1 0x0198 /* Dword offset 0_66 */
+#define SRC_X_START 0x019C /* Dword offset 0_67 */
+#define SRC_Y_START 0x01A0 /* Dword offset 0_68 */
+#define SRC_Y_X_START 0x01A4 /* Dword offset 0_69 */
+#define SRC_WIDTH2 0x01A8 /* Dword offset 0_6A */
+#define SRC_HEIGHT2 0x01AC /* Dword offset 0_6B */
+#define SRC_HEIGHT2_WIDTH2 0x01B0 /* Dword offset 0_6C */
+#define SRC_CNTL 0x01B4 /* Dword offset 0_6D */
+
+#define SCALE_OFF 0x01C0 /* Dword offset 0_70 */
+#define SECONDARY_SCALE_OFF 0x01C4 /* Dword offset 0_71 */
+
+#define TEX_0_OFF 0x01C0 /* Dword offset 0_70 */
+#define TEX_1_OFF 0x01C4 /* Dword offset 0_71 */
+#define TEX_2_OFF 0x01C8 /* Dword offset 0_72 */
+#define TEX_3_OFF 0x01CC /* Dword offset 0_73 */
+#define TEX_4_OFF 0x01D0 /* Dword offset 0_74 */
+#define TEX_5_OFF 0x01D4 /* Dword offset 0_75 */
+#define TEX_6_OFF 0x01D8 /* Dword offset 0_76 */
+#define TEX_7_OFF 0x01DC /* Dword offset 0_77 */
+
+#define SCALE_WIDTH 0x01DC /* Dword offset 0_77 */
+#define SCALE_HEIGHT 0x01E0 /* Dword offset 0_78 */
+
+#define TEX_8_OFF 0x01E0 /* Dword offset 0_78 */
+#define TEX_9_OFF 0x01E4 /* Dword offset 0_79 */
+#define TEX_10_OFF 0x01E8 /* Dword offset 0_7A */
+#define S_Y_INC 0x01EC /* Dword offset 0_7B */
+
+#define SCALE_PITCH 0x01EC /* Dword offset 0_7B */
+#define SCALE_X_INC 0x01F0 /* Dword offset 0_7C */
+
+#define RED_X_INC 0x01F0 /* Dword offset 0_7C */
+#define GREEN_X_INC 0x01F4 /* Dword offset 0_7D */
+
+#define SCALE_Y_INC 0x01F4 /* Dword offset 0_7D */
+#define SCALE_VACC 0x01F8 /* Dword offset 0_7E */
+#define SCALE_3D_CNTL 0x01FC /* Dword offset 0_7F */
+
+#define HOST_DATA0 0x0200 /* Dword offset 0_80 */
+#define HOST_DATA1 0x0204 /* Dword offset 0_81 */
+#define HOST_DATA2 0x0208 /* Dword offset 0_82 */
+#define HOST_DATA3 0x020C /* Dword offset 0_83 */
+#define HOST_DATA4 0x0210 /* Dword offset 0_84 */
+#define HOST_DATA5 0x0214 /* Dword offset 0_85 */
+#define HOST_DATA6 0x0218 /* Dword offset 0_86 */
+#define HOST_DATA7 0x021C /* Dword offset 0_87 */
+#define HOST_DATA8 0x0220 /* Dword offset 0_88 */
+#define HOST_DATA9 0x0224 /* Dword offset 0_89 */
+#define HOST_DATAA 0x0228 /* Dword offset 0_8A */
+#define HOST_DATAB 0x022C /* Dword offset 0_8B */
+#define HOST_DATAC 0x0230 /* Dword offset 0_8C */
+#define HOST_DATAD 0x0234 /* Dword offset 0_8D */
+#define HOST_DATAE 0x0238 /* Dword offset 0_8E */
+#define HOST_DATAF 0x023C /* Dword offset 0_8F */
+#define HOST_CNTL 0x0240 /* Dword offset 0_90 */
+
+#define BM_HOSTDATA 0x0244 /* Dword offset 0_91 */
+#define BM_ADDR 0x0248 /* Dword offset 0_92 */
+#define BM_DATA 0x0248 /* Dword offset 0_92 */
+#define BM_GUI_TABLE_CMD 0x024C /* Dword offset 0_93 */
+
+#define PAT_REG0 0x0280 /* Dword offset 0_A0 */
+#define PAT_REG1 0x0284 /* Dword offset 0_A1 */
+#define PAT_CNTL 0x0288 /* Dword offset 0_A2 */
+
+#define SC_LEFT 0x02A0 /* Dword offset 0_A8 */
+#define SC_RIGHT 0x02A4 /* Dword offset 0_A9 */
+#define SC_LEFT_RIGHT 0x02A8 /* Dword offset 0_AA */
+#define SC_TOP 0x02AC /* Dword offset 0_AB */
+#define SC_BOTTOM 0x02B0 /* Dword offset 0_AC */
+#define SC_TOP_BOTTOM 0x02B4 /* Dword offset 0_AD */
+
+#define DP_BKGD_CLR 0x02C0 /* Dword offset 0_B0 */
+#define DP_FOG_CLR 0x02C4 /* Dword offset 0_B1 */
+#define DP_FRGD_CLR 0x02C4 /* Dword offset 0_B1 */
+#define DP_WRITE_MSK 0x02C8 /* Dword offset 0_B2 */
+#define DP_CHAIN_MSK 0x02CC /* Dword offset 0_B3 */
+#define DP_PIX_WIDTH 0x02D0 /* Dword offset 0_B4 */
+#define DP_MIX 0x02D4 /* Dword offset 0_B5 */
+#define DP_SRC 0x02D8 /* Dword offset 0_B6 */
+#define DP_FRGD_CLR_MIX 0x02DC /* Dword offset 0_B7 */
+#define DP_FRGD_BLGD_CLR 0x02E0 /* Dword offset 0_B8 */
+
+#define DST_X_Y 0x02E8 /* Dword offset 0_BA */
+#define DST_WIDTH_HEIGHT 0x02EC /* Dword offset 0_BB */
+#define USR_DST_PICTH 0x02F0 /* Dword offset 0_BC */
+#define DP_SET_GUI_ENGINE2 0x02F8 /* Dword offset 0_BE */
+#define DP_SET_GUI_ENGINE 0x02FC /* Dword offset 0_BF */
+
+#define CLR_CMP_CLR 0x0300 /* Dword offset 0_C0 */
+#define CLR_CMP_MSK 0x0304 /* Dword offset 0_C1 */
+#define CLR_CMP_CNTL 0x0308 /* Dword offset 0_C2 */
+
+#define FIFO_STAT 0x0310 /* Dword offset 0_C4 */
+
+#define CONTEXT_MASK 0x0320 /* Dword offset 0_C8 */
+#define CONTEXT_LOAD_CNTL 0x032C /* Dword offset 0_CB */
+
+#define GUI_TRAJ_CNTL 0x0330 /* Dword offset 0_CC */
+#define GUI_STAT 0x0338 /* Dword offset 0_CE */
+
+#define TEX_PALETTE_INDEX 0x0340 /* Dword offset 0_D0 */
+#define STW_EXP 0x0344 /* Dword offset 0_D1 */
+#define LOG_MAX_INC 0x0348 /* Dword offset 0_D2 */
+#define S_X_INC 0x034C /* Dword offset 0_D3 */
+#define S_Y_INC__ALIAS__ 0x0350 /* Dword offset 0_D4 */
+
+#define SCALE_PITCH__ALIAS__ 0x0350 /* Dword offset 0_D4 */
+
+#define S_START 0x0354 /* Dword offset 0_D5 */
+#define W_X_INC 0x0358 /* Dword offset 0_D6 */
+#define W_Y_INC 0x035C /* Dword offset 0_D7 */
+#define W_START 0x0360 /* Dword offset 0_D8 */
+#define T_X_INC 0x0364 /* Dword offset 0_D9 */
+#define T_Y_INC 0x0368 /* Dword offset 0_DA */
+
+#define SECONDARY_SCALE_PITCH 0x0368 /* Dword offset 0_DA */
+
+#define T_START 0x036C /* Dword offset 0_DB */
+#define TEX_SIZE_PITCH 0x0370 /* Dword offset 0_DC */
+#define TEX_CNTL 0x0374 /* Dword offset 0_DD */
+#define SECONDARY_TEX_OFFSET 0x0378 /* Dword offset 0_DE */
+#define TEX_PALETTE 0x037C /* Dword offset 0_DF */
+
+#define SCALE_PITCH_BOTH 0x0380 /* Dword offset 0_E0 */
+#define SECONDARY_SCALE_OFF_ACC 0x0384 /* Dword offset 0_E1 */
+#define SCALE_OFF_ACC 0x0388 /* Dword offset 0_E2 */
+#define SCALE_DST_Y_X 0x038C /* Dword offset 0_E3 */
+
+#define COMPOSITE_SHADOW_ID 0x0398 /* Dword offset 0_E6 */
+
+#define SECONDARY_SCALE_X_INC 0x039C /* Dword offset 0_E7 */
+
+#define SPECULAR_RED_X_INC 0x039C /* Dword offset 0_E7 */
+#define SPECULAR_RED_Y_INC 0x03A0 /* Dword offset 0_E8 */
+#define SPECULAR_RED_START 0x03A4 /* Dword offset 0_E9 */
+
+#define SECONDARY_SCALE_HACC 0x03A4 /* Dword offset 0_E9 */
+
+#define SPECULAR_GREEN_X_INC 0x03A8 /* Dword offset 0_EA */
+#define SPECULAR_GREEN_Y_INC 0x03AC /* Dword offset 0_EB */
+#define SPECULAR_GREEN_START 0x03B0 /* Dword offset 0_EC */
+#define SPECULAR_BLUE_X_INC 0x03B4 /* Dword offset 0_ED */
+#define SPECULAR_BLUE_Y_INC 0x03B8 /* Dword offset 0_EE */
+#define SPECULAR_BLUE_START 0x03BC /* Dword offset 0_EF */
+
+#define SCALE_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */
+
+#define RED_X_INC__ALIAS__ 0x03C0 /* Dword offset 0_F0 */
+#define RED_Y_INC 0x03C4 /* Dword offset 0_F1 */
+#define RED_START 0x03C8 /* Dword offset 0_F2 */
+
+#define SCALE_HACC 0x03C8 /* Dword offset 0_F2 */
+#define SCALE_Y_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */
+
+#define GREEN_X_INC__ALIAS__ 0x03CC /* Dword offset 0_F3 */
+#define GREEN_Y_INC 0x03D0 /* Dword offset 0_F4 */
+
+#define SECONDARY_SCALE_Y_INC 0x03D0 /* Dword offset 0_F4 */
+#define SECONDARY_SCALE_VACC 0x03D4 /* Dword offset 0_F5 */
+
+#define GREEN_START 0x03D4 /* Dword offset 0_F5 */
+#define BLUE_X_INC 0x03D8 /* Dword offset 0_F6 */
+#define BLUE_Y_INC 0x03DC /* Dword offset 0_F7 */
+#define BLUE_START 0x03E0 /* Dword offset 0_F8 */
+#define Z_X_INC 0x03E4 /* Dword offset 0_F9 */
+#define Z_Y_INC 0x03E8 /* Dword offset 0_FA */
+#define Z_START 0x03EC /* Dword offset 0_FB */
+#define ALPHA_X_INC 0x03F0 /* Dword offset 0_FC */
+#define FOG_X_INC 0x03F0 /* Dword offset 0_FC */
+#define ALPHA_Y_INC 0x03F4 /* Dword offset 0_FD */
+#define FOG_Y_INC 0x03F4 /* Dword offset 0_FD */
+#define ALPHA_START 0x03F8 /* Dword offset 0_FE */
+#define FOG_START 0x03F8 /* Dword offset 0_FE */
+
+#define OVERLAY_Y_X_START 0x0400 /* Dword offset 1_00 */
+#define OVERLAY_Y_X_END 0x0404 /* Dword offset 1_01 */
+#define OVERLAY_VIDEO_KEY_CLR 0x0408 /* Dword offset 1_02 */
+#define OVERLAY_VIDEO_KEY_MSK 0x040C /* Dword offset 1_03 */
+#define OVERLAY_GRAPHICS_KEY_CLR 0x0410 /* Dword offset 1_04 */
+#define OVERLAY_GRAPHICS_KEY_MSK 0x0414 /* Dword offset 1_05 */
+#define OVERLAY_KEY_CNTL 0x0418 /* Dword offset 1_06 */
+
+#define OVERLAY_SCALE_INC 0x0420 /* Dword offset 1_08 */
+#define OVERLAY_SCALE_CNTL 0x0424 /* Dword offset 1_09 */
+#define SCALER_HEIGHT_WIDTH 0x0428 /* Dword offset 1_0A */
+#define SCALER_TEST 0x042C /* Dword offset 1_0B */
+#define SCALER_BUF0_OFFSET 0x0434 /* Dword offset 1_0D */
+#define SCALER_BUF1_OFFSET 0x0438 /* Dword offset 1_0E */
+#define SCALE_BUF_PITCH 0x043C /* Dword offset 1_0F */
+
+#define CAPTURE_START_END 0x0440 /* Dword offset 1_10 */
+#define CAPTURE_X_WIDTH 0x0444 /* Dword offset 1_11 */
+#define VIDEO_FORMAT 0x0448 /* Dword offset 1_12 */
+#define VBI_START_END 0x044C /* Dword offset 1_13 */
+#define CAPTURE_CONFIG 0x0450 /* Dword offset 1_14 */
+#define TRIG_CNTL 0x0454 /* Dword offset 1_15 */
+
+#define OVERLAY_EXCLUSIVE_HORZ 0x0458 /* Dword offset 1_16 */
+#define OVERLAY_EXCLUSIVE_VERT 0x045C /* Dword offset 1_17 */
+
+#define VAL_WIDTH 0x0460 /* Dword offset 1_18 */
+#define CAPTURE_DEBUG 0x0464 /* Dword offset 1_19 */
+#define VIDEO_SYNC_TEST 0x0468 /* Dword offset 1_1A */
+
+#define SNAPSHOT_VH_COUNTS 0x0470 /* Dword offset 1_1C */
+#define SNAPSHOT_F_COUNT 0x0474 /* Dword offset 1_1D */
+#define N_VIF_COUNT 0x0478 /* Dword offset 1_1E */
+#define SNAPSHOT_VIF_COUNT 0x047C /* Dword offset 1_1F */
+
+#define CAPTURE_BUF0_OFFSET 0x0480 /* Dword offset 1_20 */
+#define CAPTURE_BUF1_OFFSET 0x0484 /* Dword offset 1_21 */
+#define CAPTURE_BUF_PITCH 0x0488 /* Dword offset 1_22 */
+
+#define MPP_CONFIG 0x04C0 /* Dword offset 1_30 */
+#define MPP_STROBE_SEQ 0x04C4 /* Dword offset 1_31 */
+#define MPP_ADDR 0x04C8 /* Dword offset 1_32 */
+#define MPP_DATA 0x04CC /* Dword offset 1_33 */
+#define TVO_CNTL 0x0500 /* Dword offset 1_40 */
+
+#define CRT_HORZ_VERT_LOAD 0x0544 /* Dword offset 1_51 */
+
+#define AGP_BASE 0x0548 /* Dword offset 1_52 */
+#define AGP_CNTL 0x054C /* Dword offset 1_53 */
+
+#define SCALER_COLOUR_CNTL 0x0550 /* Dword offset 1_54 */
+#define SCALER_H_COEFF0 0x0554 /* Dword offset 1_55 */
+#define SCALER_H_COEFF1 0x0558 /* Dword offset 1_56 */
+#define SCALER_H_COEFF2 0x055C /* Dword offset 1_57 */
+#define SCALER_H_COEFF3 0x0560 /* Dword offset 1_58 */
+#define SCALER_H_COEFF4 0x0564 /* Dword offset 1_59 */
+
+#define GUI_CNTL 0x0578 /* Dword offset 1_5E */
+
+#define BM_FRAME_BUF_OFFSET 0x0580 /* Dword offset 1_60 */
+#define BM_SYSTEM_MEM_ADDR 0x0584 /* Dword offset 1_61 */
+#define BM_COMMAND 0x0588 /* Dword offset 1_62 */
+#define BM_STATUS 0x058C /* Dword offset 1_63 */
+#define BM_GUI_TABLE 0x05B8 /* Dword offset 1_6E */
+#define BM_SYSTEM_TABLE 0x05BC /* Dword offset 1_6F */
+
+#define SCALER_BUF0_OFFSET_U 0x05D4 /* Dword offset 1_75 */
+#define SCALER_BUF0_OFFSET_V 0x05D8 /* Dword offset 1_76 */
+#define SCALER_BUF1_OFFSET_U 0x05DC /* Dword offset 1_77 */
+#define SCALER_BUF1_OFFSET_V 0x05E0 /* Dword offset 1_78 */
+
+#define VERTEX_1_S 0x0640 /* Dword offset 1_90 */
+#define VERTEX_1_T 0x0644 /* Dword offset 1_91 */
+#define VERTEX_1_W 0x0648 /* Dword offset 1_92 */
+#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_93 */
+#define VERTEX_1_Z 0x0650 /* Dword offset 1_94 */
+#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_95 */
+#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_96 */
+#define ONE_OVER_AREA 0x065C /* Dword offset 1_97 */
+#define VERTEX_2_S 0x0660 /* Dword offset 1_98 */
+#define VERTEX_2_T 0x0664 /* Dword offset 1_99 */
+#define VERTEX_2_W 0x0668 /* Dword offset 1_9A */
+#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_9B */
+#define VERTEX_2_Z 0x0670 /* Dword offset 1_9C */
+#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_9D */
+#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_9E */
+#define ONE_OVER_AREA 0x065C /* Dword offset 1_9F */
+#define VERTEX_3_S 0x0680 /* Dword offset 1_A0 */
+#define VERTEX_3_T 0x0684 /* Dword offset 1_A1 */
+#define VERTEX_3_W 0x0688 /* Dword offset 1_A2 */
+#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_A3 */
+#define VERTEX_3_Z 0x0690 /* Dword offset 1_A4 */
+#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_A5 */
+#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_A6 */
+#define ONE_OVER_AREA 0x065C /* Dword offset 1_A7 */
+#define VERTEX_1_S 0x0640 /* Dword offset 1_AB */
+#define VERTEX_1_T 0x0644 /* Dword offset 1_AC */
+#define VERTEX_1_W 0x0648 /* Dword offset 1_AD */
+#define VERTEX_2_S 0x0660 /* Dword offset 1_AE */
+#define VERTEX_2_T 0x0664 /* Dword offset 1_AF */
+#define VERTEX_2_W 0x0668 /* Dword offset 1_B0 */
+#define VERTEX_3_SECONDARY_S 0x06C0 /* Dword offset 1_B0 */
+#define VERTEX_3_S 0x0680 /* Dword offset 1_B1 */
+#define VERTEX_3_SECONDARY_T 0x06C4 /* Dword offset 1_B1 */
+#define VERTEX_3_T 0x0684 /* Dword offset 1_B2 */
+#define VERTEX_3_SECONDARY_W 0x06C8 /* Dword offset 1_B2 */
+#define VERTEX_3_W 0x0688 /* Dword offset 1_B3 */
+#define VERTEX_1_SPEC_ARGB 0x064C /* Dword offset 1_B4 */
+#define VERTEX_2_SPEC_ARGB 0x066C /* Dword offset 1_B5 */
+#define VERTEX_3_SPEC_ARGB 0x068C /* Dword offset 1_B6 */
+#define VERTEX_1_Z 0x0650 /* Dword offset 1_B7 */
+#define VERTEX_2_Z 0x0670 /* Dword offset 1_B8 */
+#define VERTEX_3_Z 0x0690 /* Dword offset 1_B9 */
+#define VERTEX_1_ARGB 0x0654 /* Dword offset 1_BA */
+#define VERTEX_2_ARGB 0x0674 /* Dword offset 1_BB */
+#define VERTEX_3_ARGB 0x0694 /* Dword offset 1_BC */
+#define VERTEX_1_X_Y 0x0658 /* Dword offset 1_BD */
+#define VERTEX_2_X_Y 0x0678 /* Dword offset 1_BE */
+#define VERTEX_3_X_Y 0x0698 /* Dword offset 1_BF */
+#define ONE_OVER_AREA_UC 0x0700 /* Dword offset 1_C0 */
+#define SETUP_CNTL 0x0704 /* Dword offset 1_C1 */
+#define VERTEX_1_SECONDARY_S 0x0728 /* Dword offset 1_CA */
+#define VERTEX_1_SECONDARY_T 0x072C /* Dword offset 1_CB */
+#define VERTEX_1_SECONDARY_W 0x0730 /* Dword offset 1_CC */
+#define VERTEX_2_SECONDARY_S 0x0734 /* Dword offset 1_CD */
+#define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */
+#define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */
+
+
+/* CRTC control values (mostly CRTC_GEN_CNTL) */
+
+#define CRTC_H_SYNC_NEG 0x00200000
+#define CRTC_V_SYNC_NEG 0x00200000
+
+#define CRTC_DBL_SCAN_EN 0x00000001
+#define CRTC_INTERLACE_EN 0x00000002
+#define CRTC_HSYNC_DIS 0x00000004
+#define CRTC_VSYNC_DIS 0x00000008
+#define CRTC_CSYNC_EN 0x00000010
+#define CRTC_PIX_BY_2_EN 0x00000020 /* unused on RAGE */
+#define CRTC_DISPLAY_DIS 0x00000040
+#define CRTC_VGA_XOVERSCAN 0x00000040
+
+#define CRTC_PIX_WIDTH_MASK 0x00000700
+#define CRTC_PIX_WIDTH_4BPP 0x00000100
+#define CRTC_PIX_WIDTH_8BPP 0x00000200
+#define CRTC_PIX_WIDTH_15BPP 0x00000300
+#define CRTC_PIX_WIDTH_16BPP 0x00000400
+#define CRTC_PIX_WIDTH_24BPP 0x00000500
+#define CRTC_PIX_WIDTH_32BPP 0x00000600
+
+#define CRTC_BYTE_PIX_ORDER 0x00000800
+#define CRTC_PIX_ORDER_MSN_LSN 0x00000000
+#define CRTC_PIX_ORDER_LSN_MSN 0x00000800
+
+#define CRTC_FIFO_LWM 0x000f0000
+
+#define VGA_128KAP_PAGING 0x00100000
+#define VFC_SYNC_TRISTATE 0x00200000
+#define CRTC_LOCK_REGS 0x00400000
+#define CRTC_SYNC_TRISTATE 0x00800000
+
+#define CRTC_EXT_DISP_EN 0x01000000
+#define CRTC_ENABLE 0x02000000
+#define CRTC_DISP_REQ_ENB 0x04000000
+#define VGA_ATI_LINEAR 0x08000000
+#define CRTC_VSYNC_FALL_EDGE 0x10000000
+#define VGA_TEXT_132 0x20000000
+#define VGA_XCRT_CNT_EN 0x40000000
+#define VGA_CUR_B_TEST 0x80000000
+
+#define CRTC_CRNT_VLINE 0x07f00000
+#define CRTC_VBLANK 0x00000001
+
+
+/* DAC control values */
+
+#define DAC_EXT_SEL_RS2 0x01
+#define DAC_EXT_SEL_RS3 0x02
+#define DAC_8BIT_EN 0x00000100
+#define DAC_PIX_DLY_MASK 0x00000600
+#define DAC_PIX_DLY_0NS 0x00000000
+#define DAC_PIX_DLY_2NS 0x00000200
+#define DAC_PIX_DLY_4NS 0x00000400
+#define DAC_BLANK_ADJ_MASK 0x00001800
+#define DAC_BLANK_ADJ_0 0x00000000
+#define DAC_BLANK_ADJ_1 0x00000800
+#define DAC_BLANK_ADJ_2 0x00001000
+
+
+/* Mix control values */
+
+#define MIX_NOT_DST 0x0000
+#define MIX_0 0x0001
+#define MIX_1 0x0002
+#define MIX_DST 0x0003
+#define MIX_NOT_SRC 0x0004
+#define MIX_XOR 0x0005
+#define MIX_XNOR 0x0006
+#define MIX_SRC 0x0007
+#define MIX_NAND 0x0008
+#define MIX_NOT_SRC_OR_DST 0x0009
+#define MIX_SRC_OR_NOT_DST 0x000a
+#define MIX_OR 0x000b
+#define MIX_AND 0x000c
+#define MIX_SRC_AND_NOT_DST 0x000d
+#define MIX_NOT_SRC_AND_DST 0x000e
+#define MIX_NOR 0x000f
+
+/* Maximum engine dimensions */
+#define ENGINE_MIN_X 0
+#define ENGINE_MIN_Y 0
+#define ENGINE_MAX_X 4095
+#define ENGINE_MAX_Y 16383
+
+/* Mach64 engine bit constants - these are typically ORed together */
+
+/* BUS_CNTL register constants */
+#define BUS_FIFO_ERR_ACK 0x00200000
+#define BUS_HOST_ERR_ACK 0x00800000
+
+/* GEN_TEST_CNTL register constants */
+#define GEN_OVR_OUTPUT_EN 0x20
+#define HWCURSOR_ENABLE 0x80
+#define GUI_ENGINE_ENABLE 0x100
+#define BLOCK_WRITE_ENABLE 0x200
+
+/* DSP_CONFIG register constants */
+#define DSP_XCLKS_PER_QW 0x00003fff
+#define DSP_LOOP_LATENCY 0x000f0000
+#define DSP_PRECISION 0x00700000
+
+/* DSP_ON_OFF register constants */
+#define DSP_OFF 0x000007ff
+#define DSP_ON 0x07ff0000
+
+/* CLOCK_CNTL register constants */
+#define CLOCK_SEL 0x0f
+#define CLOCK_DIV 0x30
+#define CLOCK_DIV1 0x00
+#define CLOCK_DIV2 0x10
+#define CLOCK_DIV4 0x20
+#define CLOCK_STROBE 0x40
+#define PLL_WR_EN 0x02
+
+/* PLL registers */
+#define PLL_MACRO_CNTL 0x01
+#define PLL_REF_DIV 0x02
+#define PLL_GEN_CNTL 0x03
+#define MCLK_FB_DIV 0x04
+#define PLL_VCLK_CNTL 0x05
+#define VCLK_POST_DIV 0x06
+#define VCLK0_FB_DIV 0x07
+#define VCLK1_FB_DIV 0x08
+#define VCLK2_FB_DIV 0x09
+#define VCLK3_FB_DIV 0x0A
+#define PLL_XCLK_CNTL 0x0B
+#define PLL_TEST_CTRL 0x0E
+#define PLL_TEST_COUNT 0x0F
+
+/* Fields in PLL registers */
+#define PLL_PC_GAIN 0x07
+#define PLL_VC_GAIN 0x18
+#define PLL_DUTY_CYC 0xE0
+#define PLL_OVERRIDE 0x01
+#define PLL_MCLK_RST 0x02
+#define OSC_EN 0x04
+#define EXT_CLK_EN 0x08
+#define MCLK_SRC_SEL 0x70
+#define EXT_CLK_CNTL 0x80
+#define VCLK_SRC_SEL 0x03
+#define PLL_VCLK_RST 0x04
+#define VCLK_INVERT 0x08
+#define VCLK0_POST 0x03
+#define VCLK1_POST 0x0C
+#define VCLK2_POST 0x30
+#define VCLK3_POST 0xC0
+
+/* CONFIG_CNTL register constants */
+#define APERTURE_4M_ENABLE 1
+#define APERTURE_8M_ENABLE 2
+#define VGA_APERTURE_ENABLE 4
+
+/* CONFIG_STAT0 register constants (GX, CX) */
+#define CFG_BUS_TYPE 0x00000007
+#define CFG_MEM_TYPE 0x00000038
+#define CFG_INIT_DAC_TYPE 0x00000e00
+
+/* CONFIG_STAT0 register constants (CT, ET, VT) */
+#define CFG_MEM_TYPE_xT 0x00000007
+
+#define ISA 0
+#define EISA 1
+#define LOCAL_BUS 6
+#define PCI 7
+
+/* Memory types for GX, CX */
+#define DRAMx4 0
+#define VRAMx16 1
+#define VRAMx16ssr 2
+#define DRAMx16 3
+#define GraphicsDRAMx16 4
+#define EnhancedVRAMx16 5
+#define EnhancedVRAMx16ssr 6
+
+/* Memory types for CT, ET, VT, GT */
+#define DRAM 1
+#define EDO 2
+#define PSEUDO_EDO 3
+#define SDRAM 4
+#define SGRAM 5
+#define WRAM 6
+
+#define DAC_INTERNAL 0x00
+#define DAC_IBMRGB514 0x01
+#define DAC_ATI68875 0x02
+#define DAC_TVP3026_A 0x72
+#define DAC_BT476 0x03
+#define DAC_BT481 0x04
+#define DAC_ATT20C491 0x14
+#define DAC_SC15026 0x24
+#define DAC_MU9C1880 0x34
+#define DAC_IMSG174 0x44
+#define DAC_ATI68860_B 0x05
+#define DAC_ATI68860_C 0x15
+#define DAC_TVP3026_B 0x75
+#define DAC_STG1700 0x06
+#define DAC_ATT498 0x16
+#define DAC_STG1702 0x07
+#define DAC_SC15021 0x17
+#define DAC_ATT21C498 0x27
+#define DAC_STG1703 0x37
+#define DAC_CH8398 0x47
+#define DAC_ATT20C408 0x57
+
+#define CLK_ATI18818_0 0
+#define CLK_ATI18818_1 1
+#define CLK_STG1703 2
+#define CLK_CH8398 3
+#define CLK_INTERNAL 4
+#define CLK_ATT20C408 5
+#define CLK_IBMRGB514 6
+
+/* MEM_CNTL register constants */
+#define MEM_SIZE_ALIAS 0x00000007
+#define MEM_SIZE_512K 0x00000000
+#define MEM_SIZE_1M 0x00000001
+#define MEM_SIZE_2M 0x00000002
+#define MEM_SIZE_4M 0x00000003
+#define MEM_SIZE_6M 0x00000004
+#define MEM_SIZE_8M 0x00000005
+#define MEM_SIZE_ALIAS_GTB 0x0000000F
+#define MEM_SIZE_2M_GTB 0x00000003
+#define MEM_SIZE_4M_GTB 0x00000007
+#define MEM_SIZE_6M_GTB 0x00000009
+#define MEM_SIZE_8M_GTB 0x0000000B
+#define MEM_BNDRY 0x00030000
+#define MEM_BNDRY_0K 0x00000000
+#define MEM_BNDRY_256K 0x00010000
+#define MEM_BNDRY_512K 0x00020000
+#define MEM_BNDRY_1M 0x00030000
+#define MEM_BNDRY_EN 0x00040000
+
+/* ATI PCI constants */
+#define PCI_ATI_VENDOR_ID 0x1002
+#define PCI_MACH64_GX 0x4758
+#define PCI_MACH64_CX 0x4358
+#define PCI_MACH64_CT 0x4354
+#define PCI_MACH64_ET 0x4554
+#define PCI_MACH64_VT 0x5654
+#define PCI_MACH64_GT 0x4754
+
+/* CONFIG_CHIP_ID register constants */
+#define CFG_CHIP_TYPE 0x0000FFFF
+#define CFG_CHIP_CLASS 0x00FF0000
+#define CFG_CHIP_REV 0xFF000000
+#define CFG_CHIP_VERSION 0x07000000
+#define CFG_CHIP_FOUNDRY 0x38000000
+#define CFG_CHIP_REVISION 0xC0000000
+
+/* Chip IDs read from CONFIG_CHIP_ID */
+#define MACH64_GX_ID 0xD7
+#define MACH64_CX_ID 0x57
+#define MACH64_CT_ID 0x4354
+#define MACH64_ET_ID 0x4554
+#define MACH64_VT_ID 0x5654
+#define MACH64_GT_ID 0x4754
+
+/* Mach64 chip types */
+#define MACH64_UNKNOWN 0
+#define MACH64_GX 1
+#define MACH64_CX 2
+#define MACH64_CT 3
+#define MACH64_ET 4
+#define MACH64_VT 5
+#define MACH64_GT 6
+
+/* DST_CNTL register constants */
+#define DST_X_RIGHT_TO_LEFT 0
+#define DST_X_LEFT_TO_RIGHT 1
+#define DST_Y_BOTTOM_TO_TOP 0
+#define DST_Y_TOP_TO_BOTTOM 2
+#define DST_X_MAJOR 0
+#define DST_Y_MAJOR 4
+#define DST_X_TILE 8
+#define DST_Y_TILE 0x10
+#define DST_LAST_PEL 0x20
+#define DST_POLYGON_ENABLE 0x40
+#define DST_24_ROTATION_ENABLE 0x80
+
+/* SRC_CNTL register constants */
+#define SRC_PATTERN_ENABLE 1
+#define SRC_ROTATION_ENABLE 2
+#define SRC_LINEAR_ENABLE 4
+#define SRC_BYTE_ALIGN 8
+#define SRC_LINE_X_RIGHT_TO_LEFT 0
+#define SRC_LINE_X_LEFT_TO_RIGHT 0x10
+
+/* HOST_CNTL register constants */
+#define HOST_BYTE_ALIGN 1
+
+/* GUI_TRAJ_CNTL register constants */
+#define PAT_MONO_8x8_ENABLE 0x01000000
+#define PAT_CLR_4x2_ENABLE 0x02000000
+#define PAT_CLR_8x1_ENABLE 0x04000000
+
+/* DP_CHAIN_MASK register constants */
+#define DP_CHAIN_4BPP 0x8888
+#define DP_CHAIN_7BPP 0xD2D2
+#define DP_CHAIN_8BPP 0x8080
+#define DP_CHAIN_8BPP_RGB 0x9292
+#define DP_CHAIN_15BPP 0x4210
+#define DP_CHAIN_16BPP 0x8410
+#define DP_CHAIN_24BPP 0x8080
+#define DP_CHAIN_32BPP 0x8080
+
+/* DP_PIX_WIDTH register constants */
+#define DST_1BPP 0
+#define DST_4BPP 1
+#define DST_8BPP 2
+#define DST_15BPP 3
+#define DST_16BPP 4
+#define DST_32BPP 6
+#define SRC_1BPP 0
+#define SRC_4BPP 0x100
+#define SRC_8BPP 0x200
+#define SRC_15BPP 0x300
+#define SRC_16BPP 0x400
+#define SRC_32BPP 0x600
+#define HOST_1BPP 0
+#define HOST_4BPP 0x10000
+#define HOST_8BPP 0x20000
+#define HOST_15BPP 0x30000
+#define HOST_16BPP 0x40000
+#define HOST_32BPP 0x60000
+#define BYTE_ORDER_MSB_TO_LSB 0
+#define BYTE_ORDER_LSB_TO_MSB 0x1000000
+
+/* DP_MIX register constants */
+#define BKGD_MIX_NOT_D 0
+#define BKGD_MIX_ZERO 1
+#define BKGD_MIX_ONE 2
+#define BKGD_MIX_D 3
+#define BKGD_MIX_NOT_S 4
+#define BKGD_MIX_D_XOR_S 5
+#define BKGD_MIX_NOT_D_XOR_S 6
+#define BKGD_MIX_S 7
+#define BKGD_MIX_NOT_D_OR_NOT_S 8
+#define BKGD_MIX_D_OR_NOT_S 9
+#define BKGD_MIX_NOT_D_OR_S 10
+#define BKGD_MIX_D_OR_S 11
+#define BKGD_MIX_D_AND_S 12
+#define BKGD_MIX_NOT_D_AND_S 13
+#define BKGD_MIX_D_AND_NOT_S 14
+#define BKGD_MIX_NOT_D_AND_NOT_S 15
+#define BKGD_MIX_D_PLUS_S_DIV2 0x17
+#define FRGD_MIX_NOT_D 0
+#define FRGD_MIX_ZERO 0x10000
+#define FRGD_MIX_ONE 0x20000
+#define FRGD_MIX_D 0x30000
+#define FRGD_MIX_NOT_S 0x40000
+#define FRGD_MIX_D_XOR_S 0x50000
+#define FRGD_MIX_NOT_D_XOR_S 0x60000
+#define FRGD_MIX_S 0x70000
+#define FRGD_MIX_NOT_D_OR_NOT_S 0x80000
+#define FRGD_MIX_D_OR_NOT_S 0x90000
+#define FRGD_MIX_NOT_D_OR_S 0xa0000
+#define FRGD_MIX_D_OR_S 0xb0000
+#define FRGD_MIX_D_AND_S 0xc0000
+#define FRGD_MIX_NOT_D_AND_S 0xd0000
+#define FRGD_MIX_D_AND_NOT_S 0xe0000
+#define FRGD_MIX_NOT_D_AND_NOT_S 0xf0000
+#define FRGD_MIX_D_PLUS_S_DIV2 0x170000
+
+/* DP_SRC register constants */
+#define BKGD_SRC_BKGD_CLR 0
+#define BKGD_SRC_FRGD_CLR 1
+#define BKGD_SRC_HOST 2
+#define BKGD_SRC_BLIT 3
+#define BKGD_SRC_PATTERN 4
+#define FRGD_SRC_BKGD_CLR 0
+#define FRGD_SRC_FRGD_CLR 0x100
+#define FRGD_SRC_HOST 0x200
+#define FRGD_SRC_BLIT 0x300
+#define FRGD_SRC_PATTERN 0x400
+#define MONO_SRC_ONE 0
+#define MONO_SRC_PATTERN 0x10000
+#define MONO_SRC_HOST 0x20000
+#define MONO_SRC_BLIT 0x30000
+
+/* CLR_CMP_CNTL register constants */
+#define COMPARE_FALSE 0
+#define COMPARE_TRUE 1
+#define COMPARE_NOT_EQUAL 4
+#define COMPARE_EQUAL 5
+#define COMPARE_DESTINATION 0
+#define COMPARE_SOURCE 0x1000000
+
+/* FIFO_STAT register constants */
+#define FIFO_ERR 0x80000000
+
+/* CONTEXT_LOAD_CNTL constants */
+#define CONTEXT_NO_LOAD 0
+#define CONTEXT_LOAD 0x10000
+#define CONTEXT_LOAD_AND_DO_FILL 0x20000
+#define CONTEXT_LOAD_AND_DO_LINE 0x30000
+#define CONTEXT_EXECUTE 0
+#define CONTEXT_CMD_DISABLE 0x80000000
+
+/* GUI_STAT register constants */
+#define ENGINE_IDLE 0
+#define ENGINE_BUSY 1
+#define SCISSOR_LEFT_FLAG 0x10
+#define SCISSOR_RIGHT_FLAG 0x20
+#define SCISSOR_TOP_FLAG 0x40
+#define SCISSOR_BOTTOM_FLAG 0x80
+
+/* ATI VGA Extended Regsiters */
+#define sioATIEXT 0x1ce
+#define bioATIEXT 0x3ce
+
+#define ATI2E 0xae
+#define ATI32 0xb2
+#define ATI36 0xb6
+
+/* VGA Graphics Controller Registers */
+#define VGAGRA 0x3ce
+#define GRA06 0x06
+
+/* VGA Seququencer Registers */
+#define VGASEQ 0x3c4
+#define SEQ02 0x02
+#define SEQ04 0x04
+
+#define MACH64_MAX_X ENGINE_MAX_X
+#define MACH64_MAX_Y ENGINE_MAX_Y
+
+#define INC_X 0x0020
+#define INC_Y 0x0080
+
+#define RGB16_555 0x0000
+#define RGB16_565 0x0040
+#define RGB16_655 0x0080
+#define RGB16_664 0x00c0
+
+#define POLY_TEXT_TYPE 0x0001
+#define IMAGE_TEXT_TYPE 0x0002
+#define TEXT_TYPE_8_BIT 0x0004
+#define TEXT_TYPE_16_BIT 0x0008
+#define POLY_TEXT_TYPE_8 (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define IMAGE_TEXT_TYPE_8 (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define POLY_TEXT_TYPE_16 (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
+#define IMAGE_TEXT_TYPE_16 (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
+
+#define MACH64_NUM_CLOCKS 16
+#define MACH64_NUM_FREQS 50
+
+/* Wait until "v" queue entries are free */
+#define aty_WaitQueue(v) { while ((aty_ld_le32(FIFO_STAT) & 0xffff) > \
+ ((unsigned short)(0x8000 >> (v)))); }
+
+/* Wait until GP is idle and queue is empty */
+#define aty_WaitIdleEmpty() { aty_WaitQueue(16); \
+ while ((aty_ld_le32(GUI_STAT) & 1) != 0); }
+
+#define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5))
+
+#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \
+{ \
+ aty_WaitQueue(5); \
+ aty_st_le32(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \
+ aty_st_le32(SRC_WIDTH1, (_w)); \
+ aty_st_le32(DST_CNTL, (_dir)); \
+ aty_st_le32(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \
+ aty_st_le32(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \
+}
+#endif /* REGMACH64_H */
+
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
new file mode 100644
index 000000000..e1f8b3ef4
--- /dev/null
+++ b/drivers/video/atyfb.c
@@ -0,0 +1,1685 @@
+/*
+ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI/Open Firmware
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * This driver is partly based on the PowerMac console driver:
+ *
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * and on the PowerMac ATI/mach64 display driver:
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *
+ * with work by Jon Howell
+ * Harry AC Eaton
+ * Anthony Tong <atong@uiuc.edu>
+ *
+ * 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>
+#include <linux/vc_ioctl.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#include "aty.h"
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+
+static int currcon = 0;
+static struct display fb_disp;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[256];
+
+static char atyfb_name[16] = "ATY Mach64";
+
+struct atyfb_par {
+ int vmode;
+ int cmode;
+ u_int vxres; /* virtual screen size */
+ u_int vyres;
+ int xoffset; /* virtual screen position */
+ int yoffset;
+};
+
+
+/*
+ * 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 */
+
+/*
+ * 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 */
+
+
+static int default_video_mode = VMODE_NVRAM;
+static int default_color_mode = CMODE_NVRAM;
+
+static struct atyfb_par default_par;
+static struct atyfb_par current_par;
+
+
+/*
+ * Addresses in NVRAM where video mode and pixel size are stored.
+ */
+#define NV_VMODE 0x140f
+#define NV_CMODE 0x1410
+
+/*
+ * Horizontal and vertical resolution information.
+ */
+extern struct vmode_attr {
+ int hres;
+ int vres;
+ int vfreq;
+ int interlaced;
+} vmode_attrs[VMODE_MAX];
+
+
+/*
+ * Horizontal and vertical resolution for each mode.
+ */
+static 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}
+};
+
+
+/*
+ * 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" */
+ {-1, VMODE_640_480_60}, /* catch-all, must be last */
+};
+
+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;
+}
+
+struct aty_cmap_regs {
+ unsigned char windex;
+ unsigned char lut;
+ unsigned char mask;
+ unsigned char rindex;
+ unsigned char cntl;
+};
+
+typedef struct aty_regvals {
+ int offset[3]; /* first pixel address */
+
+ int crtc_h_sync_strt_wid[3]; /* depth dependant */
+ int crtc_gen_cntl[3];
+ int mem_cntl[3];
+
+ int crtc_h_tot_disp; /* mode dependant */
+ int crtc_v_tot_disp;
+ int crtc_v_sync_strt_wid;
+ int crtc_off_pitch;
+
+ unsigned char clock_val[2]; /* vals for 20 and 21 */
+} aty_regvals;
+
+struct rage_regvals {
+ int h_total, h_sync_start, h_sync_width;
+ int v_total, v_sync_start, v_sync_width;
+ int h_sync_neg, v_sync_neg;
+};
+
+static int aty_vram_reqd(const struct atyfb_par *par);
+static struct aty_regvals *get_aty_struct(int vmode);
+
+static unsigned long frame_buffer;
+
+static int total_vram; /* total amount of video memory, bytes */
+static int chip_type; /* what chip type was detected */
+
+static unsigned long ati_regbase;
+static struct aty_cmap_regs *aty_cmap_regs;
+
+#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
+};
+
+ /*
+ * Interface used by the world
+ */
+
+unsigned long atyfb_init(unsigned long mem_start);
+void atyfb_setup(char *options, int *ints);
+
+static int atyfb_open(struct fb_info *info);
+static int atyfb_release(struct fb_info *info);
+static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+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,
+ struct fb_info *info);
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+
+ /*
+ * 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);
+
+
+ /*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static struct display_switch fbcon_aty8;
+#endif
+
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+ struct fb_info *);
+static int atyfb_console_setmode(struct vc_mode *, int);
+#endif
+
+
+ /*
+ * Internal routines
+ */
+
+static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+static int atyfb_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);
+
+
+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, NULL, atyfb_ioctl
+};
+
+
+static inline int aty_vram_reqd(const struct atyfb_par *par)
+{
+ return (par->vxres*par->vyres) << par->cmode;
+}
+
+extern inline unsigned aty_ld_le32(volatile unsigned long addr)
+{
+ register unsigned long temp = ati_regbase,val;
+
+ asm("lwbrx %0,%1,%2": "=r"(val):"r"(addr), "r"(temp));
+ return val;
+}
+
+extern inline void aty_st_le32(volatile unsigned long addr, unsigned val)
+{
+ register unsigned long temp = ati_regbase;
+
+ asm("stwbrx %0,%1,%2": : "r"(val), "r"(addr), "r"(temp):"memory");
+}
+
+extern inline unsigned char aty_ld_8(volatile unsigned long addr)
+{
+ return *(char *) ((long) addr + (long) ati_regbase);
+}
+
+extern inline void aty_st_8(volatile unsigned long addr, unsigned char val)
+{
+ *(unsigned char *) (addr + (unsigned long) ati_regbase) = val;
+}
+
+static void aty_st_514(int offset, char val)
+{
+ aty_WaitQueue(5);
+ aty_st_8(DAC_CNTL, 1);
+ aty_st_8(DAC_W_INDEX, offset & 0xff); /* right addr byte */
+ aty_st_8(DAC_DATA, (offset >> 8) & 0xff); /* left addr byte */
+ eieio();
+ aty_st_8(DAC_MASK, val);
+ eieio();
+ aty_st_8(DAC_CNTL, 0);
+}
+
+static void aty_st_pll(int offset, char val)
+{
+ aty_WaitQueue(3);
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN); /* write addr byte */
+ eieio();
+ aty_st_8(CLOCK_CNTL + 2, val); /* write the register value */
+ eieio();
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+}
+
+static struct aty_regvals *get_aty_struct(int vmode)
+{
+ int v = vmode - 1;
+
+ switch (chip_type) {
+ case MACH64_GT_ID:
+ return aty_gt_reg_init[v];
+ break;
+ case MACH64_VT_ID:
+ return aty_vt_reg_init[v];
+ break;
+ default: /* default to MACH64_GX_ID */
+ return aty_gx_reg_init[v];
+ break;
+ }
+}
+
+static int read_aty_sense(void)
+{
+ int sense, i;
+
+ aty_st_le32(GP_IO, 0x31003100); /* drive outputs high */
+ __delay(200);
+ aty_st_le32(GP_IO, 0); /* turn off outputs */
+ __delay(2000);
+ i = aty_ld_le32(GP_IO); /* get primary sense value */
+ sense = ((i & 0x3000) >> 3) | (i & 0x100);
+
+ /* drive each sense line low in turn and collect the other 2 */
+ aty_st_le32(GP_IO, 0x20000000); /* drive A low */
+ __delay(2000);
+ i = aty_ld_le32(GP_IO);
+ sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
+ aty_st_le32(GP_IO, 0x20002000); /* drive A high again */
+ __delay(200);
+
+ aty_st_le32(GP_IO, 0x10000000); /* drive B low */
+ __delay(2000);
+ i = aty_ld_le32(GP_IO);
+ sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
+ aty_st_le32(GP_IO, 0x10001000); /* drive B high again */
+ __delay(200);
+
+ aty_st_le32(GP_IO, 0x01000000); /* drive C low */
+ __delay(2000);
+ sense |= (aty_ld_le32(GP_IO) & 0x3000) >> 12;
+ aty_st_le32(GP_IO, 0); /* turn off outputs */
+
+ return sense;
+}
+
+static void RGB514_Program(int cmode)
+{
+ typedef struct {
+ char pixel_dly;
+ char misc2_cntl;
+ char pixel_rep;
+ char pixel_cntl_index;
+ char 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);
+ aty_st_514(0x04, pDacProgTab->pixel_dly);
+ aty_st_514(0x05, 0x00);
+
+ aty_st_514(0x2, 0x1);
+ aty_st_514(0x71, pDacProgTab->misc2_cntl);
+ aty_st_514(0x0a, pDacProgTab->pixel_rep);
+
+ aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+}
+
+static void set_off_pitch(const struct atyfb_par *par)
+{
+ u32 pitch, offset;
+
+ pitch = par->vxres>>3;
+ offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->cmode;
+ aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset);
+ if (chip_type == MACH64_GT_ID) {
+ /* Is this OK for other chips? */
+ aty_st_le32(DST_OFF_PITCH, pitch<<22 | offset);
+ aty_st_le32(SRC_OFF_PITCH, pitch<<22 | offset);
+ }
+}
+
+static void atyfb_set_par(struct atyfb_par *par)
+{
+ int i, hres;
+ struct aty_regvals *init = get_aty_struct(par->vmode);
+ int vram_type = aty_ld_le32(CONFIG_STAT0) & 7;
+
+ if (init == 0) /* paranoia, shouldn't get here */
+ panic("aty: display mode %d not supported", par->vmode);
+
+ current_par = *par;
+ hres = vmode_attrs[par->vmode-1].hres;
+
+ /* clear FIFO errors */
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_HOST_ERR_ACK
+ | BUS_FIFO_ERR_ACK);
+
+ /* Reset engine */
+ i = aty_ld_le32(GEN_TEST_CNTL);
+ aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+ eieio();
+ aty_WaitIdleEmpty();
+ aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
+ aty_WaitIdleEmpty();
+
+ if ( chip_type != MACH64_GT_ID ) {
+ i = aty_ld_le32(CRTC_GEN_CNTL);
+ aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN);
+ }
+
+ if ( chip_type == MACH64_GX_ID ) {
+ i = aty_ld_le32(GEN_TEST_CNTL);
+ aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+ }
+
+ switch (chip_type) {
+ case MACH64_VT_ID:
+ aty_st_pll(PLL_MACRO_CNTL, 0xb5);
+ aty_st_pll(PLL_REF_DIV, 0x2d);
+ aty_st_pll(PLL_GEN_CNTL, 0x14);
+ aty_st_pll(MCLK_FB_DIV, 0xbd);
+ aty_st_pll(PLL_VCLK_CNTL, 0x0b);
+ aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
+ aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
+ aty_st_pll(VCLK1_FB_DIV, 0xd6);
+ aty_st_pll(VCLK2_FB_DIV, 0xee);
+ aty_st_pll(VCLK3_FB_DIV, 0xf8);
+ aty_st_pll(PLL_XCLK_CNTL, 0x0);
+ aty_st_pll(PLL_TEST_CTRL, 0x0);
+ aty_st_pll(PLL_TEST_COUNT, 0x0);
+ break;
+ case MACH64_GT_ID:
+ if (vram_type == 5) {
+ aty_st_pll(0, 0xcd);
+ aty_st_pll(PLL_MACRO_CNTL,
+ par->vmode >= VMODE_1024_768_60 ? 0xd3: 0xd5);
+ aty_st_pll(PLL_REF_DIV, 0x21);
+ aty_st_pll(PLL_GEN_CNTL, 0x44);
+ aty_st_pll(MCLK_FB_DIV, 0xe8);
+ aty_st_pll(PLL_VCLK_CNTL, 0x03);
+ aty_st_pll(VCLK_POST_DIV, init->offset[0]);
+ aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
+ aty_st_pll(VCLK1_FB_DIV, 0x8e);
+ aty_st_pll(VCLK2_FB_DIV, 0x9e);
+ aty_st_pll(VCLK3_FB_DIV, 0xc6);
+ aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
+ aty_st_pll(12, 0xa6);
+ aty_st_pll(13, 0x1b);
+ } else {
+ aty_st_pll(PLL_MACRO_CNTL, 0xd5);
+ aty_st_pll(PLL_REF_DIV, 0x21);
+ aty_st_pll(PLL_GEN_CNTL, 0xc4);
+ aty_st_pll(MCLK_FB_DIV, 0xda);
+ aty_st_pll(PLL_VCLK_CNTL, 0x03);
+ /* offset actually holds clock values */
+ aty_st_pll(VCLK_POST_DIV, init->offset[0]);
+ aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
+ aty_st_pll(VCLK1_FB_DIV, 0x8e);
+ aty_st_pll(VCLK2_FB_DIV, 0x9e);
+ aty_st_pll(VCLK3_FB_DIV, 0xc6);
+ aty_st_pll(PLL_TEST_CTRL, 0x0);
+ aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
+ aty_st_pll(12, 0xa0);
+ aty_st_pll(13, 0x1b);
+ }
+ break;
+ default:
+ RGB514_Program(par->cmode);
+ aty_WaitIdleEmpty();
+ aty_st_514(0x06, 0x02);
+ aty_st_514(0x10, 0x01);
+ aty_st_514(0x70, 0x01);
+ aty_st_514(0x8f, 0x1f);
+ aty_st_514(0x03, 0x00);
+ aty_st_514(0x05, 0x00);
+ aty_st_514(0x20, init->clock_val[0]);
+ aty_st_514(0x21, init->clock_val[1]);
+ break;
+ }
+
+ aty_ld_8(DAC_REGS); /* clear counter */
+ aty_WaitIdleEmpty();
+
+ aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
+ aty_st_le32(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[par->cmode]);
+ aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
+ aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+
+ aty_st_8(CLOCK_CNTL, 0);
+ aty_st_8(CLOCK_CNTL, CLOCK_STROBE);
+
+ aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0);
+
+ set_off_pitch(par);
+
+ if (chip_type == MACH64_GT_ID) {
+ aty_st_le32(BUS_CNTL, 0x7b23a040);
+
+ /* need to set DSP values !! assume sdram */
+ i = init->crtc_gen_cntl[0] - (0x100000 * par->cmode);
+ if ( vram_type == 5 )
+ i = init->crtc_gen_cntl[1] - (0x100000 * par->cmode);
+ aty_st_le32(DSP_CONFIG, i);
+
+ i = aty_ld_le32(MEM_CNTL) & MEM_SIZE_ALIAS;
+ if ( vram_type == 5 ) {
+ i |= ((1 * par->cmode) << 26) | 0x4215b0;
+ aty_st_le32(DSP_ON_OFF,sgram_dsp[par->vmode-1][par->cmode]);
+
+ //aty_st_le32(CLOCK_CNTL,8192);
+ } else {
+ i |= ((1 * par->cmode) << 26) | 0x300090;
+ aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->cmode]);
+ }
+
+ aty_st_le32(MEM_CNTL, i);
+ aty_st_le32(EXT_MEM_CNTL, 0x5000001);
+
+ /* if (total_vram > 0x400000)
+ i |= 0x538; this not been verified on > 4Megs!! */
+ } else {
+
+/* 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 see if
+* we can gain some speed by fooling with the wait states etc.
+*/
+ if (chip_type == MACH64_VT_ID)
+ aty_st_le32(BUS_CNTL, 0x680000f9);
+ else
+ aty_st_le32(BUS_CNTL, 0x590e10ff);
+
+ switch (total_vram) {
+ case 0x00100000:
+ aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->cmode]);
+ break;
+ case 0x00200000:
+ aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->cmode]);
+ break;
+ case 0x00400000:
+ aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->cmode]);
+ break;
+ default:
+ i = aty_ld_le32(MEM_CNTL) & 0x000F;
+ aty_st_le32(MEM_CNTL,
+ (init->mem_cntl[par->cmode] & 0xFFFFFFF0) | i);
+ }
+ }
+/* These magic constants 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
+*/
+ switch (chip_type) {
+ case MACH64_GT_ID:
+ i = 0x86010102;
+ break;
+ case MACH64_VT_ID:
+ i = 0x87010184;
+ break;
+ default:
+ i = 0x47012100;
+ break;
+ }
+
+ aty_st_le32(DAC_CNTL, i);
+ aty_st_8(DAC_MASK, 0xff);
+
+ switch (par->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;
+ }
+
+ if (chip_type != MACH64_GT_ID) {
+ aty_st_le32(CRTC_INT_CNTL, 0x00000002);
+ aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE); /* gui_en block_en */
+ i |= init->crtc_gen_cntl[par->cmode];
+ }
+ /* Gentlemen, start your crtc engine */
+ aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ display_info.height = vmode_attrs[par->vmode-1].vres;
+ display_info.width = vmode_attrs[par->vmode-1].hres;
+ display_info.depth = 8<<par->cmode;
+ display_info.pitch = par->vxres<<par->cmode;
+ display_info.mode = par->vmode;
+ strcpy(display_info.name, atyfb_name);
+ display_info.fb_address =
+ iopa(((chip_type != MACH64_GT_ID) ?
+ frame_buffer + init->offset[par->cmode] : frame_buffer));
+ display_info.cmap_adr_address = iopa((unsigned long)&aty_cmap_regs->windex);
+ display_info.cmap_data_address = iopa((unsigned long)&aty_cmap_regs->lut);
+ display_info.disp_reg_address = iopa(ati_regbase);
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
+}
+
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int atyfb_open(struct fb_info *info)
+
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int atyfb_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+
+static int encode_fix(struct fb_fix_screeninfo *fix,
+ const struct atyfb_par *par)
+{
+ struct aty_regvals *init;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, atyfb_name);
+ init = get_aty_struct(par->vmode);
+ /*
+ * FIXME: This will cause problems on non-GT chips, because the frame
+ * buffer must be aligned to a page
+ */
+ fix->smem_start = (char *)((chip_type != MACH64_GT_ID)
+ ? frame_buffer + init->offset[par->cmode] : frame_buffer);
+ fix->smem_len = (u32)total_vram;
+ if (fix->smem_len > 0x7ff000)
+ fix->smem_len = 0x7ff000; /* last page is MMIO */
+ fix->mmio_start = (char *)(ati_regbase & ~0xfff);
+ fix->mmio_len = 4096;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = par->vxres<<par->cmode;
+ fix->visual = par->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)
+{
+ 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->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 = 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;
+
+ 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 (aty_vram_reqd(par) > total_vram)
+ return -EINVAL;
+
+ /* Check if we know about the wanted video mode */
+ init = get_aty_struct(par->vmode);
+ if (init == NULL || init->crtc_h_sync_strt_wid[par->cmode] == 0 ||
+ (chip_type != MACH64_GT_ID &&
+ init->crtc_gen_cntl[par->cmode] == 0) ||
+ (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5 &&
+ init->crtc_gen_cntl[1] == 0))
+ return -EINVAL;
+
+#if 0
+ if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+ return -EINVAL;
+#endif
+
+ return 0;
+}
+
+static int encode_var(struct fb_var_screeninfo *var,
+ const struct atyfb_par *par)
+{
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+ var->xres = vmode_attrs[par->vmode-1].hres;
+ var->yres = vmode_attrs[par->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 (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->accel = /* FB_ACCEL_ATY */ 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->left_margin = var->right_margin = 64; /* guesses */
+ var->upper_margin = var->lower_margin = 32;
+ var->hsync_len = 64;
+ var->vsync_len = 2;
+
+ /* 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);
+ var->sync = 0;
+
+ return 0;
+}
+
+
+static void init_par(struct atyfb_par *par, int vmode, int cmode)
+{
+ par->vmode = vmode;
+ par->cmode = cmode;
+ par->vxres = vmode_attrs[vmode-1].hres;
+ par->vyres = vmode_attrs[vmode-1].vres;
+ par->xoffset = 0;
+ par->yoffset = 0;
+}
+
+
+ /*
+ * Get the Fixed Part of the Display
+ */
+
+static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct atyfb_par par;
+
+ if (con == -1)
+ par = default_par;
+ else
+ decode_var(&fb_display[con].var, &par);
+ encode_fix(fix, &par);
+ return 0;
+}
+
+
+ /*
+ * Get the User Defined Part of the Display
+ */
+
+static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (con == -1)
+ encode_var(var, &default_par);
+ else
+ *var=fb_display[con].var;
+ return 0;
+}
+
+
+ /*
+ * Set the User Defined Part of the Display
+ */
+
+static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct atyfb_par par;
+ struct display *display;
+ int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+ int err;
+ int activate = var->activate;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &fb_disp; /* used during initialization */
+
+ if ((err = decode_var(var, &par)))
+ return err;
+
+ encode_var(var, &par);
+
+ if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ oldxres = display->var.xres;
+ oldyres = display->var.yres;
+ oldvxres = display->var.xres_virtual;
+ oldvyres = display->var.yres_virtual;
+ oldbpp = display->var.bits_per_pixel;
+ display->var = *var;
+ if (oldxres != var->xres || oldyres != var->yres ||
+ oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel) {
+ struct fb_fix_screeninfo fix;
+
+ encode_fix(&fix, &par);
+ display->screen_base = (u_char *)fix.smem_start;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+ switch (par.cmode) {
+ case CMODE_8:
+#if 1
+ display->dispsw = &fbcon_cfb8;
+#else
+ display->dispsw = &fbcon_aty8;
+#endif
+ break;
+ case CMODE_16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+ case CMODE_32:
+ display->dispsw = &fbcon_cfb32;
+ break;
+ default:
+ display->dispsw = NULL;
+ break;
+ }
+ if (fb_info.changevar)
+ (*fb_info.changevar)(con);
+ }
+ if (con == currcon)
+ atyfb_set_par(&par);
+ if (oldbpp != var->bits_per_pixel) {
+ if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+ return err;
+ do_install_cmap(con, info);
+ }
+ }
+
+ return 0;
+}
+
+
+ /*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+
+static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ u32 xres, yres, xoffset, yoffset;
+ struct atyfb_par *par = &current_par;
+
+ xres = vmode_attrs[par->vmode-1].hres;
+ yres = vmode_attrs[par->vmode-1].vres;
+ xoffset = (var->xoffset+7) & ~7;
+ yoffset = var->yoffset;
+ if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
+ return -EINVAL;
+ par->xoffset = xoffset;
+ par->yoffset = yoffset;
+ set_off_pitch(par);
+ return 0;
+}
+
+ /*
+ * Get the Colormap
+ */
+
+static int atyfb_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, atyfb_getcolreg,
+ info);
+ 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);
+ return 0;
+}
+
+ /*
+ * Set the Colormap
+ */
+
+static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ 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)))
+ return err;
+ }
+ if (con == currcon) /* current console? */
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, atyfb_setcolreg,
+ info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+
+ /*
+ * Initialisation
+ */
+
+__initfunc(unsigned long atyfb_init(unsigned long mem_start))
+{
+#ifdef __powerpc__
+ /* We don't want to be called like this. */
+ /* We rely on Open Firmware (offb) instead. */
+ return mem_start;
+#else /* !__powerpc__ */
+ /* To be merged with Bernd's mach64fb */
+ return mem_start;
+#endif /* !__powerpc__ */
+}
+
+
+unsigned long atyfb_of_init(unsigned long mem_start, struct device_node *dp)
+{
+ int i, err, sense;
+ struct fb_var_screeninfo var;
+ struct aty_regvals *init;
+ unsigned long addr;
+ unsigned char bus, devfn;
+ unsigned short cmd;
+
+ if (dp->next)
+ printk("Warning: only using first ATI card detected\n");
+ if (dp->n_addrs != 1 && dp->n_addrs != 3)
+ printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
+ dp->n_addrs);
+
+ ati_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+ aty_cmap_regs = (struct aty_cmap_regs *)(ati_regbase + 0xC0);
+
+ /* enable memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ if (cmd != 0xffff) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+ chip_type = (aty_ld_le32(CONFIG_CHIP_ID) & CFG_CHIP_TYPE);
+
+ i = aty_ld_le32(MEM_CNTL);
+ if (chip_type != MACH64_GT_ID)
+ switch (i & MEM_SIZE_ALIAS) {
+ case MEM_SIZE_512K:
+ total_vram = 0x80000;
+ break;
+ case MEM_SIZE_1M:
+ total_vram = 0x100000;
+ break;
+ case MEM_SIZE_2M:
+ total_vram = 0x200000;
+ break;
+ case MEM_SIZE_4M:
+ total_vram = 0x400000;
+ break;
+ case MEM_SIZE_6M:
+ total_vram = 0x600000;
+ break;
+ case MEM_SIZE_8M:
+ total_vram = 0x800000;
+ break;
+ default:
+ total_vram = 0x80000;
+ }
+ else
+ switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+ case MEM_SIZE_512K:
+ total_vram = 0x80000;
+ break;
+ case MEM_SIZE_1M:
+ total_vram = 0x100000;
+ break;
+ case MEM_SIZE_2M_GTB:
+ total_vram = 0x200000;
+ break;
+ case MEM_SIZE_4M_GTB:
+ total_vram = 0x400000;
+ break;
+ case MEM_SIZE_6M_GTB:
+ total_vram = 0x600000;
+ break;
+ case MEM_SIZE_8M_GTB:
+ total_vram = 0x800000;
+ break;
+ default:
+ total_vram = 0x80000;
+ }
+
+#if 1
+ printk("aty_display_init: node = %p, addrs = ", dp->node);
+ printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
+ printk(", intrs =");
+ for (i = 0; i < dp->n_intrs; ++i)
+ printk(" %x", dp->intrs[i].line);
+ printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %p\n",
+ (int)ati_regbase, bus, devfn, total_vram, aty_cmap_regs);
+#endif
+
+ /* Map in frame buffer */
+ addr = dp->addrs[0].address;
+
+ /* use the big-endian aperture (??) */
+ addr += 0x800000;
+ frame_buffer = (unsigned long)__ioremap(addr, 0x800000, _PAGE_WRITETHRU);
+
+ if (default_video_mode != -1) {
+ sense = read_aty_sense();
+ printk("monitor sense = %x\n", sense);
+ if (default_video_mode == VMODE_NVRAM) {
+ default_video_mode = nvram_read_byte(NV_VMODE);
+ init = get_aty_struct(default_video_mode);
+ if (default_video_mode <= 0 ||
+ default_video_mode > VMODE_MAX || init == 0)
+ default_video_mode = VMODE_CHOOSE;
+ }
+ if (default_video_mode == VMODE_CHOOSE)
+ default_video_mode = map_monitor_sense(sense);
+
+ init = get_aty_struct(default_video_mode);
+ if (!init)
+ default_video_mode = VMODE_640_480_60;
+ }
+
+ /*
+ * Reduce the pixel size if we don't have enough VRAM.
+ */
+
+ if (default_color_mode == CMODE_NVRAM)
+ default_color_mode = nvram_read_byte(NV_CMODE);
+ if (default_color_mode < CMODE_8 ||
+ default_color_mode > CMODE_32)
+ default_color_mode = CMODE_8;
+
+ init_par(&default_par, default_video_mode, default_color_mode);
+ while (aty_vram_reqd(&default_par) > total_vram) {
+ while (default_color_mode > CMODE_8 &&
+ aty_vram_reqd(&default_par) > total_vram) {
+ --default_color_mode;
+ init_par(&default_par, default_video_mode, default_color_mode);
+ }
+ /*
+ * adjust the video mode smaller if there still is not enough VRAM
+ */
+ if (aty_vram_reqd(&default_par) > total_vram)
+ do {
+ default_video_mode--;
+ init_par(&default_par, default_video_mode, default_color_mode);
+ init = get_aty_struct(default_video_mode);
+ } while ((init == 0) &&
+ (default_video_mode > VMODE_640_480_60));
+ }
+
+ if (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5
+ && init->crtc_gen_cntl[1] == 0) {
+ default_video_mode = VMODE_640_480_67;
+ default_color_mode = CMODE_8;
+ init_par(&default_par, default_video_mode, default_color_mode);
+ }
+
+ switch (chip_type) {
+ case MACH64_GX_ID:
+ strcat(atyfb_name, "GX");
+ break;
+ case MACH64_VT_ID:
+ strcat(atyfb_name, "VT");
+ break;
+ case MACH64_GT_ID:
+ strcat(atyfb_name, "GT");
+ break;
+ default:
+ break;
+ }
+ strcpy(fb_info.modename, atyfb_name);
+ fb_info.node = -1;
+ fb_info.fbops = &atyfb_ops;
+ fb_info.disp = &fb_disp;
+ fb_info.fontname[0] = '\0';
+ fb_info.changevar = NULL;
+ fb_info.switch_con = &atyfbcon_switch;
+ fb_info.updatevar = &atyfbcon_updatevar;
+ fb_info.blank = &atyfbcon_blank;
+
+ err = register_framebuffer(&fb_info);
+ if (err < 0)
+ return mem_start;
+
+ for (i = 0; i < 16; i++) {
+ int j = color_table[i];
+ palette[i].red = default_red[j];
+ palette[i].green = default_grn[j];
+ palette[i].blue = default_blu[j];
+ }
+ atyfb_set_par(&default_par);
+ encode_var(&var, &default_par);
+ atyfb_set_var(&var, -1, &fb_info);
+
+ printk("fb%d: %s frame buffer device on %s\n", GET_FB_IDX(fb_info.node),
+ atyfb_name, dp->full_name);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info) {
+ console_fb_info = &fb_info;
+ console_setmode_ptr = atyfb_console_setmode;
+ console_set_cmap_ptr = atyfb_set_cmap;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
+
+ return mem_start;
+}
+
+
+/* XXX: doesn't work yet */
+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, "vmode:", 6)) {
+ vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX)
+ default_video_mode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ depth = simple_strtoul(this_opt+6, NULL, 0);
+ switch (depth) {
+ case 8:
+ default_color_mode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_color_mode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_color_mode = CMODE_32;
+ break;
+ };
+ }
+ }
+}
+
+
+static int atyfbcon_switch(int con, struct fb_info *info)
+{
+ 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);
+ currcon = con;
+ decode_var(&fb_display[con].var, &par);
+ atyfb_set_par(&par);
+ /* Install new colormap */
+ do_install_cmap(con, info);
+ return 0;
+}
+
+ /*
+ * Update the `var' structure (called by fbcon.c)
+ */
+
+static int atyfbcon_updatevar(int con, struct fb_info *info)
+{
+ current_par.yoffset = fb_display[con].var.yoffset;
+ set_off_pitch(&current_par);
+ return 0;
+}
+
+ /*
+ * Blank the display.
+ */
+
+static void atyfbcon_blank(int blank, struct fb_info *info)
+{
+ char gen_cntl;
+
+ gen_cntl = aty_ld_8(CRTC_GEN_CNTL);
+ if (blank & VESA_VSYNC_SUSPEND)
+ gen_cntl |= 0x8;
+ if (blank & VESA_HSYNC_SUSPEND)
+ gen_cntl |= 0x4;
+ if ((blank & VESA_POWERDOWN) == VESA_POWERDOWN)
+ gen_cntl |= 0x40;
+ if (blank == VESA_NO_BLANKING)
+ gen_cntl &= ~(0x4c);
+ aty_st_8(CRTC_GEN_CNTL, gen_cntl);
+}
+
+
+ /*
+ * Read a single color register and split it into
+ * colors/transparent. Return != 0 for invalid regno.
+ */
+
+static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info)
+{
+ if (regno > 255)
+ return 1;
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ return 0;
+}
+
+
+ /*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ int i, scale;
+
+ if (regno > 255)
+ return 1;
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+ aty_WaitQueue(2);
+ i = aty_ld_8(DAC_CNTL) & 0xfc;
+ if (chip_type == MACH64_GT_ID)
+ i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
+ aty_st_8(DAC_CNTL, i);
+ aty_st_8(DAC_REGS + DAC_MASK, 0xff);
+ eieio();
+ scale = ((chip_type != MACH64_GX_ID) &&
+ (current_par.cmode == CMODE_16)) ? 3 : 0;
+ aty_WaitQueue(4);
+ aty_cmap_regs->windex = regno << scale;
+ eieio();
+ aty_cmap_regs->lut = red << scale;
+ eieio();
+ aty_cmap_regs->lut = green << scale;
+ eieio();
+ aty_cmap_regs->lut = blue << scale;
+ eieio();
+ if (regno < 16) {
+#ifdef CONFIG_FBCON_CFB16
+ fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) |
+ (regno << 8) | regno;
+#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,
+ atyfb_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, atyfb_setcolreg,
+ info);
+}
+
+
+ /*
+ * Accelerated functions
+ */
+
+void aty_waitblit(void)
+{
+ aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
+}
+
+void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width,
+ u_int height)
+{
+ u_int direction = 0;
+
+ if (srcy < dsty) {
+ dsty += height - 1;
+ srcy += height - 1;
+ } else
+ direction |= DST_Y_TOP_TO_BOTTOM;
+
+ if (srcx < dstx) {
+ dstx += width - 1;
+ srcx += width - 1;
+ } else
+ direction |= DST_X_LEFT_TO_RIGHT;
+
+ aty_WaitQueue(4);
+ aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
+ aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST);
+ aty_st_le32(DP_SRC, FRGD_SRC_BLIT);
+
+ aty_WaitQueue(5);
+ aty_st_le32(SRC_Y_X, (srcx << 16) | (srcy & 0x0000ffff));
+ aty_st_le32(SRC_WIDTH1, width);
+ aty_st_le32(DST_CNTL, direction);
+ aty_st_le32(DST_Y_X, (dstx << 16) | (dsty & 0x0000ffff));
+ aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | (height & 0x0000ffff));
+
+ aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
+
+ /*
+ * Make sure that the destination trajectory is correctly set
+ * for subsequent calls. MACH64_BIT_BLT is the only function that
+ * currently changes the destination trajectory from L->R and T->B.
+ */
+ aty_st_le32(DST_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
+}
+
+void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color)
+{
+ if (!width || !height)
+ return;
+
+ aty_WaitQueue(5);
+ aty_st_le32(DP_FRGD_CLR, color /* pGC->fgPixel */ );
+ aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
+ aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST);
+ aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR);
+
+ aty_st_le32(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+
+ aty_WaitQueue(2);
+ aty_st_le32(DST_Y_X, (((u_int)dstx << 16) | ((u_int)dsty & 0x0000ffff)));
+ aty_st_le32(DST_HEIGHT_WIDTH, (((u_int)width << 16) | height));
+
+ aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
+}
+
+
+ /*
+ * Text console acceleration
+ */
+
+static void fbcon_aty8_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;
+
+ aty_rectcopy(sx, sy, dx, dy, width, height);
+}
+
+static void fbcon_aty8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
+{
+ u32 bgx = attr_bgcol_ec(p, conp);
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+
+ sx *= p->fontwidth;
+ sy *= p->fontheight;
+ width *= p->fontwidth;
+ height *= p->fontheight;
+
+ aty_rectfill(sx, sy, width, height, bgx);
+}
+
+static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+ aty_waitblit();
+ fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
+{
+ aty_waitblit();
+ fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty8 = {
+ fbcon_cfb8_setup, fbcon_aty8_bmove, fbcon_aty8_clear, fbcon_aty8_putc,
+ fbcon_aty8_putcs, fbcon_cfb8_revc
+};
+
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+
+ /*
+ * Backward compatibility mode for Xpmac
+ */
+
+static int atyfb_console_setmode(struct vc_mode *mode, int doit)
+{
+ int err;
+ struct fb_var_screeninfo var;
+ struct atyfb_par par;
+ int vmode, cmode;
+
+ if (mode->mode <= 0 || mode->mode > VMODE_MAX )
+ return -EINVAL;
+ vmode = mode->mode;
+
+ switch (mode->depth) {
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 8:
+ case 0: /* (default) */
+ cmode = CMODE_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ init_par(&par, vmode, cmode);
+ encode_var(&var, &par);
+ if ((err = decode_var(&var, &par)))
+ return err;
+ if (doit)
+ atyfb_set_var(&var, currcon, 0);
+ return 0;
+}
+
+#endif /* CONFIG_FB_COMPAT_XPMAC */
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index ccd83bb01..2eaacb57d 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -36,18 +36,34 @@
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+
#include "s3blit.h"
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+
+#ifdef CYBERFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-struct Cyber_fb_par {
+
+#define wb_64(reg,dat) (*((unsigned char volatile *)CyberRegs + reg) = dat)
+
+
+
+struct cyberfb_par {
int xres;
int yres;
int bpp;
};
-static struct Cyber_fb_par current_par;
+static struct cyberfb_par current_par;
static int current_par_valid = 0;
static int currcon = 0;
@@ -68,13 +84,13 @@ static struct fb_hwswitch {
/* Display Control */
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct Cyber_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
+ int (*encode_fix)(struct fb_fix_screeninfo *fix, struct cyberfb_par *par);
+ int (*decode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
+ int (*encode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
+ u_int transp, struct fb_info *info);
void (*blank)(int blank);
} *fbhw;
@@ -83,7 +99,7 @@ static struct fb_hwswitch {
* Frame Buffer Name
*/
-static char Cyber_fb_name[16] = "Cybervision";
+static char cyberfb_name[16] = "Cybervision";
/*
@@ -106,105 +122,67 @@ static unsigned char Cyber_colour_table [256][4];
static unsigned long CyberMem;
static unsigned long CyberSize;
static volatile char *CyberRegs;
-
-
-/*
- * Predefined Video Mode Names
- */
-
-static char *Cyber_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "cyber8", /* Cybervision 8 bpp */
- "cyber16", /* Cybervision 16 bpp */
- "800x600x8",
- "640x480x8",
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
+
/*
- * Predefined Video Mode Definitions
+ * Predefined Video Modes
*/
-static struct fb_var_screeninfo cyber_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- {
- /* Cybervision 8 bpp */
- CYBER8_WIDTH, CYBER8_HEIGHT, CYBER8_WIDTH, CYBER8_HEIGHT, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
- /* Cybervision 16 bpp */
- 800, 600, 800, 600, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
- /* Cybervision 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
- /* Cybervision 8 bpp */
- 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, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+static struct fb_videomode cyberfb_predefined[] __initdata = {
+ {
+ "640x480-8", { /* Cybervision 8 bpp */
+ 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, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "800x600-8", { /* Cybervision 8 bpp */
+ 800, 600, 800, 600, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1024x768-8", { /* Cybervision 8 bpp */
+ 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, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1152x886-8", { /* Cybervision 8 bpp */
+ 1152, 886, 1152, 886, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1280x1024-8", { /* Cybervision 8 bpp */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1600x1200-8", { /* Cybervision 8 bpp */
+ 1600, 1200, 1600, 1200, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "800x600-16", { /* Cybervision 16 bpp */
+ 800, 600, 800, 600, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }
};
-#define NUM_TOTAL_MODES arraysize(cyber_fb_predefined)
-#define NUM_PREDEF_MODES (5)
+#define NUM_TOTAL_MODES arraysize(cyberfb_predefined)
static int Cyberfb_inverse = 0;
@@ -212,57 +190,72 @@ static int Cyberfb_inverse = 0;
static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */
static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */
#endif
-static int Cyberfb_mode = 0;
-
/*
* Some default modes
*/
-#define CYBER8_DEFMODE (1)
-#define CYBER16_DEFMODE (2)
+#define CYBER8_DEFMODE (0)
+#define CYBER16_DEFMODE (6)
+
+static struct fb_var_screeninfo cyberfb_default;
/*
* Interface used by the world
*/
-void Cyber_video_setup(char *options, int *ints);
-
-static int Cyber_fb_open(int fbidx);
-static int Cyber_fb_release(int fbidx);
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
+void cyberfb_setup(char *options, int *ints);
+
+static int cyberfb_open(struct fb_info *info);
+static int cyberfb_release(struct fb_info *info);
+static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct
+fb_info *info);
+static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, struct
+fb_info *info);
+static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, struct
+fb_info *info);
+static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int cyberfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
/*
* Interface to the low level console driver
*/
-unsigned long Cyber_fb_init(unsigned long mem_start);
-static int Cyberfb_switch(int con);
-static int Cyberfb_updatevar(int con);
-static void Cyberfb_blank(int blank);
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con);
+unsigned long cyberfb_init(unsigned long mem_start);
+static int Cyberfb_switch(int con, struct fb_info *info);
+static int Cyberfb_updatevar(int con, struct fb_info *info);
+static void Cyberfb_blank(int blank, struct fb_info *info);
+
+
+/*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static struct display_switch fbcon_cyber8;
+#endif
/*
* Accelerated Functions used by the low level console driver
*/
-void Cyber_WaitQueue(u_short fifo);
-void Cyber_WaitBlit(void);
-void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short mode);
-void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color);
-void Cyber_MoveCursor(u_short x, u_short y);
+static void Cyber_WaitQueue(u_short fifo);
+static void Cyber_WaitBlit(void);
+static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
+ u_short desty, u_short width, u_short height,
+ u_short mode);
+static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
+ u_short mode, u_short color);
+static void Cyber_MoveCursor(u_short x, u_short y);
/*
@@ -271,15 +264,15 @@ void Cyber_MoveCursor(u_short x, u_short y);
static int Cyber_init(void);
static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct Cyber_fb_par *par);
+ struct cyberfb_par *par);
static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par);
+ struct cyberfb_par *par);
static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par);
+ struct cyberfb_par *par);
static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
+ u_int transp, struct fb_info *info);
static void Cyber_blank(int blank);
@@ -287,11 +280,11 @@ static void Cyber_blank(int blank);
* Internal routines
*/
-static void Cyber_fb_get_par(struct Cyber_fb_par *par);
-static void Cyber_fb_set_par(struct Cyber_fb_par *par);
+static void cyberfb_get_par(struct cyberfb_par *par);
+static void cyberfb_set_par(struct cyberfb_par *par);
static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static void do_install_cmap(int con);
-static void Cyber_fb_set_disp(int con);
+static void do_install_cmap(int con, struct fb_info *info);
+static void cyberfb_set_disp(int con, struct fb_info *info);
static int get_video_mode(const char *name);
@@ -311,41 +304,32 @@ static int Cyber_init(void)
char size;
volatile u_long *CursorBase;
-#if 0
- if (Cyberfb_mode == -1)
+ for (i = 0; i < 256; i++)
{
- if (Cyberfb_Cyber8)
- Cyberfb_mode = CYBER8_DEFMODE;
- else
- Cyberfb_mode = CYBER16_DEFMODE;
+ Cyber_colour_table [i][0] = i;
+ Cyber_colour_table [i][1] = i;
+ Cyber_colour_table [i][2] = i;
+ Cyber_colour_table [i][3] = 0;
}
-#endif
-
- for (i = 0; i < 256; i++)
-
- for (i = 0; i < 256; i++)
- {
- Cyber_colour_table [i][0] = i;
- Cyber_colour_table [i][1] = i;
- Cyber_colour_table [i][2] = i;
- Cyber_colour_table [i][3] = 0;
- }
/*
* Just clear the thing for the biggest mode.
+ *
+ * ++Andre, TODO: determine size first, then clear all memory
+ * (the 3D penguin might need texture memory :-) )
*/
- memset ((char*)CyberMem, 0, CYBER8_WIDTH * CYBER8_HEIGHT);
+ memset ((char*)CyberMem, 0, 1600 * 1200);
/* Disable hardware cursor */
- *(CyberRegs + S3_CRTC_ADR) = S3_REG_LOCK2;
- *(CyberRegs + S3_CRTC_DATA) = 0xa0;
- *(CyberRegs + S3_CRTC_ADR) = S3_HGC_MODE;
- *(CyberRegs + S3_CRTC_DATA) = 0x00;
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DX;
- *(CyberRegs + S3_CRTC_DATA) = 0x00;
- *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DY;
- *(CyberRegs + S3_CRTC_DATA) = 0x00;
+ wb_64(S3_CRTC_ADR, S3_REG_LOCK2);
+ wb_64(S3_CRTC_DATA, 0xa0);
+ wb_64(S3_CRTC_ADR, S3_HGC_MODE);
+ wb_64(S3_CRTC_DATA, 0x00);
+ wb_64(S3_CRTC_ADR, S3_HWGC_DX);
+ wb_64(S3_CRTC_DATA, 0x00);
+ wb_64(S3_CRTC_ADR, S3_HWGC_DY);
+ wb_64(S3_CRTC_DATA, 0x00);
/* Get memory size (if not 2MB it is 4MB) */
*(CyberRegs + S3_CRTC_ADR) = S3_LAW_CTL;
@@ -372,8 +356,8 @@ static int Cyber_init(void)
*(CursorBase+3+(i*4)) = 0xffff0000;
}
- Cyber_setcolreg (255, 56, 100, 160, 0);
- Cyber_setcolreg (254, 0, 0, 0, 0);
+ Cyber_setcolreg (255, 56, 100, 160, 0, NULL /* unused */);
+ Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
return 0;
}
@@ -385,11 +369,11 @@ static int Cyber_init(void)
*/
static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct Cyber_fb_par *par)
+ struct cyberfb_par *par)
{
int i;
- strcpy(fix->id, Cyber_fb_name);
+ strcpy(fix->id, cyberfb_name);
fix->smem_start = (caddr_t)CyberMem;
fix->smem_len = CyberSize;
fix->mmio_start = (unsigned char *)CyberRegs;
@@ -420,7 +404,7 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
*/
static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par)
+ struct cyberfb_par *par)
{
#if 1
par->xres = var->xres;
@@ -447,7 +431,7 @@ static int Cyber_decode_var(struct fb_var_screeninfo *var,
*/
static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par)
+ struct cyberfb_par *par)
{
int i;
@@ -486,7 +470,10 @@ static int Cyber_encode_var(struct fb_var_screeninfo *var,
var->height = -1;
var->width = -1;
+
var->accel = FB_ACCEL_CYBERVISION;
+ DPRINTK("accel CV64\n");
+
var->vmode = FB_VMODE_NONINTERLACED;
/* Dummy values */
@@ -517,20 +504,22 @@ static int Cyber_encode_var(struct fb_var_screeninfo *var,
*/
static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
+ u_int transp, struct fb_info *info)
{
if (regno > 255)
+ {
return (1);
+ }
- *(CyberRegs + 0x3c8) = (char)regno;
+ wb_64(0x3c8, (unsigned char) regno);
Cyber_colour_table [regno][0] = red & 0xff;
Cyber_colour_table [regno][1] = green & 0xff;
Cyber_colour_table [regno][2] = blue & 0xff;
Cyber_colour_table [regno][3] = transp;
- *(CyberRegs + 0x3c9) = (red & 0xff) >> 2;
- *(CyberRegs + 0x3c9) = (green & 0xff) >> 2;
- *(CyberRegs + 0x3c9) = (blue & 0xff) >> 2;
+ wb_64(0x3c9, (red & 0xff) >> 2);
+ wb_64(0x3c9, (green & 0xff) >> 2);
+ wb_64(0x3c9, (blue & 0xff) >> 2);
return (0);
}
@@ -542,13 +531,13 @@ static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
*/
static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
+ u_int *transp, struct fb_info *info)
{
if (regno >= 256)
return (1);
- *red = Cyber_colour_table [regno][0];
- *green = Cyber_colour_table [regno][1];
- *blue = Cyber_colour_table [regno][2];
+ *red = Cyber_colour_table [regno][0];
+ *green = Cyber_colour_table [regno][1];
+ *blue = Cyber_colour_table [regno][2];
*transp = Cyber_colour_table [regno][3];
return (0);
}
@@ -563,28 +552,32 @@ void Cyber_blank(int blank)
int i;
if (blank)
+ {
for (i = 0; i < 256; i++)
{
- *(CyberRegs + 0x3c8) = i;
- *(CyberRegs + 0x3c9) = 0;
- *(CyberRegs + 0x3c9) = 0;
- *(CyberRegs + 0x3c9) = 0;
+ wb_64(0x3c8, (unsigned char) i);
+ wb_64(0x3c9, 0);
+ wb_64(0x3c9, 0);
+ wb_64(0x3c9, 0);
}
+ }
else
+ {
for (i = 0; i < 256; i++)
{
- *(CyberRegs + 0x3c8) = i;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][0] >> 2;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][1] >> 2;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][2] >> 2;
+ wb_64(0x3c8, (unsigned char) i);
+ wb_64(0x3c9, Cyber_colour_table[i][0] >> 2);
+ wb_64(0x3c9, Cyber_colour_table[i][1] >> 2);
+ wb_64(0x3c9, Cyber_colour_table[i][2] >> 2);
}
+ }
}
/**************************************************************
* We are waiting for "fifo" FIFO-slots empty
*/
-void Cyber_WaitQueue (u_short fifo)
+static void Cyber_WaitQueue (u_short fifo)
{
u_short status;
@@ -598,7 +591,7 @@ void Cyber_WaitQueue (u_short fifo)
/**************************************************************
* We are waiting for Hardware (Graphics Engine) not busy
*/
-void Cyber_WaitBlit (void)
+static void Cyber_WaitBlit (void)
{
u_short status;
@@ -612,8 +605,9 @@ void Cyber_WaitBlit (void)
/**************************************************************
* BitBLT - Through the Plane
*/
-void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short mode)
+static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx,
+ u_short desty, u_short width, u_short height,
+ u_short mode)
{
u_short blitcmd = S3_BITBLT;
@@ -655,8 +649,8 @@ void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
/**************************************************************
* Rectangle Fill Solid
*/
-void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color)
+static void Cyber_RectFill (u_short x, u_short y, u_short width,
+ u_short height, u_short mode, u_short color)
{
u_short blitcmd = S3_FILLEDRECT;
@@ -677,11 +671,10 @@ void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
}
-
/**************************************************************
* Move cursor to x, y
*/
-void Cyber_MoveCursor (u_short x, u_short y)
+static void Cyber_MoveCursor (u_short x, u_short y)
{
*(CyberRegs + S3_CRTC_ADR) = 0x39;
*(CyberRegs + S3_CRTC_DATA) = 0xa0;
@@ -714,16 +707,20 @@ static struct fb_hwswitch Cyber_switch = {
* Fill the hardware's `par' structure.
*/
-static void Cyber_fb_get_par(struct Cyber_fb_par *par)
+static void cyberfb_get_par(struct cyberfb_par *par)
{
if (current_par_valid)
+ {
*par = current_par;
+ }
else
- fbhw->decode_var(&cyber_fb_predefined[Cyberfb_mode], par);
+ {
+ fbhw->decode_var(&cyberfb_default, par);
+ }
}
-static void Cyber_fb_set_par(struct Cyber_fb_par *par)
+static void cyberfb_set_par(struct cyberfb_par *par)
{
current_par = *par;
current_par_valid = 1;
@@ -733,6 +730,7 @@ static void Cyber_fb_set_par(struct Cyber_fb_par *par)
static void cyber_set_video(struct fb_var_screeninfo *var)
{
/* Set clipping rectangle to current screen size */
+
*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x1000;
*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x2000;
@@ -744,13 +742,13 @@ static void cyber_set_video(struct fb_var_screeninfo *var)
static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
{
int err, activate;
- struct Cyber_fb_par par;
+ struct cyberfb_par par;
if ((err = fbhw->decode_var(var, &par)))
return(err);
activate = var->activate;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- Cyber_fb_set_par(&par);
+ cyberfb_set_par(&par);
fbhw->encode_var(var, &par);
var->activate = activate;
@@ -759,16 +757,16 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
}
-static void do_install_cmap(int con)
+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,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, fbhw->setcolreg);
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, fbhw->setcolreg, info);
}
@@ -776,7 +774,7 @@ static void do_install_cmap(int con)
* Open/Release the frame buffer device
*/
-static int Cyber_fb_open(int fbidx)
+static int cyberfb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -786,7 +784,7 @@ static int Cyber_fb_open(int fbidx)
return(0);
}
-static int Cyber_fb_release(int fbidx)
+static int cyberfb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
@@ -797,13 +795,14 @@ static int Cyber_fb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
- struct Cyber_fb_par par;
+ struct cyberfb_par par;
int error = 0;
if (con == -1)
- Cyber_fb_get_par(&par);
+ cyberfb_get_par(&par);
else
error = fbhw->decode_var(&fb_display[con].var, &par);
return(error ? error : fbhw->encode_fix(fix, &par));
@@ -814,21 +813,28 @@ static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con)
+static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
- struct Cyber_fb_par par;
+ struct cyberfb_par par;
int error = 0;
- if (con == -1) {
- Cyber_fb_get_par(&par);
+ if (con == -1)
+ {
+ cyberfb_get_par(&par);
error = fbhw->encode_var(var, &par);
- } else
+ disp.var = *var; /* ++Andre: don't know if this is the right place */
+ }
+ else
+ {
*var = fb_display[con].var;
+ }
+
return(error);
}
-static void Cyber_fb_set_disp(int con)
+static void cyberfb_set_disp(int con, struct fb_info *info)
{
struct fb_fix_screeninfo fix;
struct display *display;
@@ -838,7 +844,7 @@ static void Cyber_fb_set_disp(int con)
else
display = &disp; /* used during initialization */
- Cyber_fb_get_fix(&fix, con);
+ cyberfb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
display->screen_base = (u_char *)fix.smem_start;
@@ -849,6 +855,21 @@ static void Cyber_fb_set_disp(int con)
display->ywrapstep = fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = Cyberfb_inverse;
+ switch (display->var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_cyber8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
}
@@ -856,7 +877,8 @@ static void Cyber_fb_set_disp(int con)
* Set the User Defined Part of the Display
*/
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
+static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
@@ -873,10 +895,10 @@ static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
oldvxres != var->xres_virtual ||
oldvyres != var->yres_virtual ||
oldbpp != var->bits_per_pixel) {
- Cyber_fb_set_disp(con);
+ cyberfb_set_disp(con, info);
(*fb_info.changevar)(con);
fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
}
var->activate = 0;
@@ -888,15 +910,16 @@ static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int cyberfb_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, fbhw->getcolreg));
+ kspc, fbhw->getcolreg, info));
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return(0);
}
@@ -906,7 +929,8 @@ static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
int err;
@@ -915,9 +939,9 @@ static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
1<<fb_display[con].var.bits_per_pixel, 0)))
return(err);
}
- if (con == currcon) /* current console? */
+ if (con == currcon) /* current console? */
return(fb_set_cmap(cmap, &fb_display[con].var,
- kspc, fbhw->setcolreg));
+ kspc, fbhw->setcolreg, info));
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return(0);
@@ -930,31 +954,32 @@ static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
return(-EINVAL);
}
/*
- * Cybervision Frame Buffer Specific ioctls
+ * Cybervision Frame Buffer Specific ioctls
*/
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg, int con)
+static int cyberfb_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg, int con, struct fb_info *info)
{
return(-EINVAL);
}
-static struct fb_ops Cyber_fb_ops = {
- Cyber_fb_open, Cyber_fb_release, Cyber_fb_get_fix, Cyber_fb_get_var,
- Cyber_fb_set_var, Cyber_fb_get_cmap, Cyber_fb_set_cmap,
- Cyber_fb_pan_display, Cyber_fb_ioctl
+static struct fb_ops cyberfb_ops = {
+ cyberfb_open, cyberfb_release, cyberfb_get_fix, cyberfb_get_var,
+ cyberfb_set_var, cyberfb_get_cmap, cyberfb_set_cmap,
+ cyberfb_pan_display, NULL, cyberfb_ioctl
};
-__initfunc(void Cyber_video_setup(char *options, int *ints))
+__initfunc(void cyberfb_setup(char *options, int *ints))
{
char *this_opt;
@@ -969,14 +994,18 @@ __initfunc(void Cyber_video_setup(char *options, int *ints))
fb_invert_cmaps();
} else if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
-#if 0
- else if (!strcmp (this_opt, "cyber8"))
- Cyberfb_Cyber8 = 1;
- else if (!strcmp (this_opt, "cyber16"))
- Cyberfb_Cyber16 = 1;
-#endif
+ else if (!strcmp (this_opt, "cyber8")){
+ cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+ }
+ else if (!strcmp (this_opt, "cyber16")){
+ cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
+ }
else
- Cyberfb_mode = get_video_mode(this_opt);
+ get_video_mode(this_opt);
+
+ DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",cyberfb_default.xres,
+ cyberfb_default.yres,
+ cyberfb_default.bits_per_pixel);
}
@@ -984,10 +1013,10 @@ __initfunc(void Cyber_video_setup(char *options, int *ints))
* Initialization
*/
-__initfunc(unsigned long Cyber_fb_init(unsigned long mem_start))
+__initfunc(unsigned long cyberfb_init(unsigned long mem_start))
{
int err;
- struct Cyber_fb_par par;
+ struct cyberfb_par par;
unsigned long board_addr;
const struct ConfigDev *cd;
@@ -1005,33 +1034,30 @@ __initfunc(unsigned long Cyber_fb_init(unsigned long mem_start))
fbhw = &Cyber_switch;
- strcpy(fb_info.modename, Cyber_fb_name);
+ strcpy(fb_info.modename, cyberfb_name);
fb_info.changevar = NULL;
fb_info.node = -1;
- fb_info.fbops = &Cyber_fb_ops;
- fb_info.fbvar_num = NUM_TOTAL_MODES;
- fb_info.fbvar = cyber_fb_predefined;
+ fb_info.fbops = &cyberfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &Cyberfb_switch;
fb_info.updatevar = &Cyberfb_updatevar;
fb_info.blank = &Cyberfb_blank;
- fb_info.setcmap = &Cyberfb_setcmap;
err = register_framebuffer(&fb_info);
if (err < 0)
return mem_start;
fbhw->init();
- fbhw->decode_var(&cyber_fb_predefined[Cyberfb_mode], &par);
- fbhw->encode_var(&cyber_fb_predefined[0], &par);
+ fbhw->decode_var(&cyberfb_default, &par);
+ fbhw->encode_var(&cyberfb_default, &par);
- do_fb_set_var(&cyber_fb_predefined[0], 1);
- Cyber_fb_get_var(&fb_display[0].var, -1);
- Cyber_fb_set_disp(-1);
- do_install_cmap(0);
+ do_fb_set_var(&cyberfb_default, 1);
+ cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
+ cyberfb_set_disp(-1, &fb_info);
+ do_install_cmap(0, &fb_info);
- printk("%s frame buffer device, using %ldK of video memory\n",
- fb_info.modename, CyberSize>>10);
+ printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
/* TODO: This driver cannot be unloaded yet */
MOD_INC_USE_COUNT;
@@ -1040,17 +1066,17 @@ __initfunc(unsigned long Cyber_fb_init(unsigned long mem_start))
}
-static int Cyberfb_switch(int con)
+static int Cyberfb_switch(int con, struct fb_info *info)
{
/* 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,
- fbhw->getcolreg);
+ fbhw->getcolreg, info);
do_fb_set_var(&fb_display[con].var, 1);
currcon = con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return(0);
}
@@ -1062,7 +1088,7 @@ static int Cyberfb_switch(int con)
* Since it's called by a kernel driver, no range checking is done.
*/
-static int Cyberfb_updatevar(int con)
+static int Cyberfb_updatevar(int con, struct fb_info *info)
{
return(0);
}
@@ -1072,42 +1098,92 @@ static int Cyberfb_updatevar(int con)
* Blank the display.
*/
-static void Cyberfb_blank(int blank)
+static void Cyberfb_blank(int blank, struct fb_info *info)
{
fbhw->blank(blank);
}
/*
- * Set the colormap
+ * Get a Video Mode
*/
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con)
+__initfunc(static int get_video_mode(const char *name))
{
- return(Cyber_fb_set_cmap(cmap, 1, con));
+ int i;
+
+ for (i = 0; i < NUM_TOTAL_MODES; i++) {
+ if (!strcmp(name, cyberfb_predefined[i].name)) {
+ cyberfb_default = cyberfb_predefined[i].var;
+ return(i);
+ }
+ }
+ /* ++Andre: set cyberfb default mode */
+ cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+ return(0);
}
/*
- * Get a Video Mode
+ * Text console acceleration
*/
-static int get_video_mode(const char *name)
+#ifdef CONFIG_FBCON_CFB8
+static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width)
{
- int i;
+ sx *= 8; dx *= 8; width *= 8;
+ Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
+ (u_short)(dy*p->fontheight), (u_short)width,
+ (u_short)(height*p->fontheight), (u_short)S3_NEW);
+}
- for (i = 1; i < NUM_PREDEF_MODES; i++)
- if (!strcmp(name, Cyber_fb_modenames[i]))
- cyber_fb_predefined[0] = cyber_fb_predefined[i];
- return(i);
- return(0);
+static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
+{
+ unsigned char bg;
+
+ sx *= 8; width *= 8;
+ bg = attr_bgcol_ec(p,conp);
+ Cyber_RectFill((u_short)sx,
+ (u_short)(sy*p->fontheight),
+ (u_short)width,
+ (u_short)(height*p->fontheight),
+ (u_short)S3_NEW,
+ (u_short)bg);
+}
+
+static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+ Cyber_WaitBlit();
+ fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
+{
+ Cyber_WaitBlit();
+ fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
}
+static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
+{
+ Cyber_WaitBlit();
+ fbcon_cfb8_revc(p, xx, yy);
+}
+
+static struct display_switch fbcon_cyber8 = {
+ fbcon_cfb8_setup, fbcon_cyber8_bmove, fbcon_cyber8_clear, fbcon_cyber8_putc,
+ fbcon_cyber8_putcs, fbcon_cyber8_revc
+};
+#endif
+
#ifdef MODULE
int init_module(void)
{
- return(Cyber_fb_init(NULL));
+ return(cyberfb_init(NULL));
}
void cleanup_module(void)
@@ -1118,12 +1194,3 @@ void cleanup_module(void)
/* TODO: clean up ... */
}
#endif /* MODULE */
-
-
-/*
- * Visible symbols for modules
- */
-
-EXPORT_SYMBOL(Cyber_BitBLT);
-EXPORT_SYMBOL(Cyber_RectFill);
-EXPORT_SYMBOL(Cyber_WaitBlit);
diff --git a/drivers/video/dn_fb.c b/drivers/video/dnfb.c
index 8c5aeb099..db0a6172f 100644
--- a/drivers/video/dn_fb.c
+++ b/drivers/video/dnfb.c
@@ -5,6 +5,7 @@
#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>
@@ -14,6 +15,9 @@
#include <linux/fb.h>
#include <linux/module.h>
+#include "fbcon-mfb.h"
+
+
/* apollo video HW definitions */
/*
@@ -108,46 +112,44 @@
#endif
-void dn_video_setup(char *options, int *ints);
-
/* frame buffer operations */
-static int dn_fb_open(int fbidx);
-static int dn_fb_release(int fbidx);
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con);
-static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con);
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg, int con);
-
-static int dnfbcon_switch(int con);
-static int dnfbcon_updatevar(int con);
-static void dnfbcon_blank(int blank);
-
-static void dn_fb_set_disp(int con);
+static int dnfb_open(struct fb_info *info);
+static int dnfb_release(struct fb_info *info);
+static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dnfb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dnfb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dnfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+static int dnfbcon_switch(int con, struct fb_info *info);
+static int dnfbcon_updatevar(int con, struct fb_info *info);
+static void dnfbcon_blank(int blank, struct fb_info *info);
+
+static void dnfb_set_disp(int con, struct fb_info *info);
static struct display disp[MAX_NR_CONSOLES];
static struct fb_info fb_info;
-static struct fb_ops dn_fb_ops = {
- dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
- dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
+static struct fb_ops dnfb_ops = {
+ dnfb_open,dnfb_release, dnfb_get_fix, dnfb_get_var, dnfb_set_var,
+ dnfb_get_cmap, dnfb_set_cmap, dnfb_pan_display, NULL, dnfb_ioctl
};
static int currcon=0;
-#define NUM_TOTAL_MODES 1
-struct fb_var_screeninfo dn_fb_predefined[] = {
-
- { 0, },
+static char dnfb_name[]="Apollo";
-};
-
-static char dn_fb_name[]="Apollo ";
-
-static int dn_fb_open(int fbidx)
+static int dnfb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -157,14 +159,15 @@ static int dn_fb_open(int fbidx)
return(0);
}
-static int dn_fb_release(int fbidx)
+static int dnfb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
}
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con) {
-
+static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id,"Apollo Mono");
fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE);
@@ -181,8 +184,9 @@ static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con) {
}
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con) {
-
+static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
var->xres=1280;
var->yres=1024;
var->xres_virtual=2048;
@@ -208,9 +212,9 @@ static int dn_fb_get_var(struct fb_var_screeninfo *var, int con) {
}
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive) {
-
- printk("fb_set_var\n");
+static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
if(var->xres!=1280)
return -EINVAL;
if(var->yres!=1024)
@@ -252,48 +256,48 @@ static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive) {
}
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con) {
-
+static int dnfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
printk("get cmap not supported\n");
return -EINVAL;
}
-static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con) {
-
+static int dnfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
printk("set cmap not supported\n");
return -EINVAL;
}
-static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con) {
-
+static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
printk("panning not supported\n");
return -EINVAL;
}
-static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg, int con) {
-
- printk("no IOCTLs as of yet.\n");
-
+static int dnfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
return -EINVAL;
-
}
-static void dn_fb_set_disp(int con) {
-
+static void dnfb_set_disp(int con, struct fb_info *info)
+{
struct fb_fix_screeninfo fix;
- dn_fb_get_fix(&fix,con);
+ dnfb_get_fix(&fix, con, info);
if(con==-1)
con=0;
disp[con].screen_base = (u_char *)fix.smem_start;
-printk("screenbase: %p\n",fix.smem_start);
disp[con].visual = fix.visual;
disp[con].type = fix.type;
disp[con].type_aux = fix.type_aux;
@@ -302,27 +306,27 @@ printk("screenbase: %p\n",fix.smem_start);
disp[con].can_soft_blank = 1;
disp[con].inverse = 0;
disp[con].line_length = fix.line_length;
+#ifdef CONFIG_FBCON_MFB
+ disp[con].dispsw = &fbcon_mfb;
+#else
+ disp[con].dispsw = NULL;
+#endif
}
-unsigned long dn_fb_init(unsigned long mem_start) {
-
+unsigned long dnfb_init(unsigned long mem_start)
+{
int err;
-printk("dn_fb_init\n");
-
fb_info.changevar=NULL;
- strcpy(&fb_info.modename[0],dn_fb_name);
+ strcpy(&fb_info.modename[0],dnfb_name);
fb_info.fontname[0]=0;
fb_info.disp=disp;
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.blank=&dnfbcon_blank;
fb_info.node = -1;
- fb_info.fbops = &dn_fb_ops;
- fb_info.fbvar = dn_fb_predefined;
- fb_info.fbvar_num = NUM_TOTAL_MODES;
+ fb_info.fbops = &dnfb_ops;
-printk("dn_fb_init: register\n");
err=register_framebuffer(&fb_info);
if(err < 0) {
panic("unable to register apollo frame buffer\n");
@@ -337,35 +341,34 @@ printk("dn_fb_init: register\n");
outb(S_DATA_PLN, AP_CONTROL_2);
outw(SWAP(0x3),AP_ROP_1);
- printk("apollo frame buffer alive and kicking !\n");
+ printk("fb%d: apollo frame buffer alive and kicking !\n",
+ GET_FB_IDX(fb_info.node));
- dn_fb_get_var(&disp[0].var,0);
+ dnfb_get_var(&disp[0].var, 0, &fb_info);
- dn_fb_set_disp(-1);
+ dnfb_set_disp(-1, &fb_info);
return mem_start;
}
-static int dnfbcon_switch(int con) {
-
+static int dnfbcon_switch(int con, struct fb_info *info)
+{
currcon=con;
return 0;
}
-static int dnfbcon_updatevar(int con) {
-
+static int dnfbcon_updatevar(int con, struct fb_info *info)
+{
return 0;
-
}
-static void dnfbcon_blank(int blank) {
-
- printk("dnfbcon_blank: %d\n",blank);
+static void dnfbcon_blank(int blank, struct fb_info *info)
+{
if(blank) {
outb(0, AP_CONTROL_3A);
outb((AD_BLT | DST_EQ_SRC | NORM_CREG1) & ~ENAB_DISP,
@@ -375,14 +378,4 @@ static void dnfbcon_blank(int blank) {
outb(1, AP_CONTROL_3A);
outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
}
-
- return ;
-
}
-
-void dn_video_setup(char *options, int *ints) {
-
- return;
-
-}
-
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 9f3c586c7..bbf06d89b 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -35,45 +35,45 @@ static void memcpy_fs(int fsfromto, void *to, void *from, int len)
#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
((1<<(width))-1)) : 0))
-static u_short red2[] = {
+static u16 red2[] = {
0x0000, 0xaaaa
};
-static u_short green2[] = {
+static u16 green2[] = {
0x0000, 0xaaaa
};
-static u_short blue2[] = {
+static u16 blue2[] = {
0x0000, 0xaaaa
-};
-
-static u_short red4[] = {
+};
+
+static u16 red4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u_short green4[] = {
+static u16 green4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u_short blue4[] = {
+static u16 blue4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-
-static u_short red8[] = {
+
+static u16 red8[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
};
-static u_short green8[] = {
+static u16 green8[] = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa
};
-static u_short blue8[] = {
+static u16 blue8[] = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
};
-
-static u_short red16[] = {
+
+static u16 red16[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
};
-static u_short green16[] = {
+static u16 green16[] = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa,
0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
};
-static u_short blue16[] = {
+static u16 blue16[] = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
};
@@ -83,10 +83,10 @@ static struct fb_cmap default_2_colors = {
};
static struct fb_cmap default_8_colors = {
0, 8, red8, green8, blue8, NULL
-};
+};
static struct fb_cmap default_4_colors = {
0, 4, red4, green4, blue4, NULL
-};
+};
static struct fb_cmap default_16_colors = {
0, 16, red16, green16, blue16, NULL
};
@@ -98,32 +98,32 @@ static struct fb_cmap default_16_colors = {
int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
{
- int size = len*sizeof(u_short);
-
+ int size = len*sizeof(u16);
+
if (cmap->len != len) {
- if (cmap->red)
+ if (cmap->red)
kfree(cmap->red);
if (cmap->green)
kfree(cmap->green);
if (cmap->blue)
kfree(cmap->blue);
if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return 0;
+ kfree(cmap->transp);
+ cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
+ cmap->len = 0;
+ if (!len)
+ return 0;
if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
return -1;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
+ if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
return -1;
if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
+ return -1;
+ if (transp) {
if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return -1;
- } else
- cmap->transp = NULL;
+ return -1;
+ } else
+ cmap->transp = NULL;
}
cmap->start = 0;
cmap->len = len;
@@ -150,12 +150,12 @@ void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
size = from->len-fromoff;
if (size < 0)
return;
- size *= sizeof(u_short);
+ size *= sizeof(u16);
memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
+ memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
}
@@ -164,10 +164,11 @@ void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
*/
int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
- int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *))
+ int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *,
+ struct fb_info *), struct fb_info *info)
{
int i, start;
- u_short *red, *green, *blue, *transp;
+ u16 *red, *green, *blue, *transp;
u_int hred, hgreen, hblue, htransp;
red = cmap->red;
@@ -178,7 +179,7 @@ int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
if (start < 0)
return -EINVAL;
for (i = 0; i < cmap->len; i++) {
- if (getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
+ if (getcolreg(start++, &hred, &hgreen, &hblue, &htransp, info))
return 0;
hred = CNVT_FROMHW(hred, var->red.length);
hgreen = CNVT_FROMHW(hgreen, var->green.length);
@@ -212,10 +213,11 @@ int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
*/
int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
- int (*setcolreg)(u_int, u_int, u_int, u_int, u_int))
+ int (*setcolreg)(u_int, u_int, u_int, u_int, u_int,
+ struct fb_info *), struct fb_info *info)
{
int i, start;
- u_short *red, *green, *blue, *transp;
+ u16 *red, *green, *blue, *transp;
u_int hred, hgreen, hblue, htransp;
red = cmap->red;
@@ -250,7 +252,7 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
blue++;
if (transp)
transp++;
- if (setcolreg(start++, hred, hgreen, hblue, htransp))
+ if (setcolreg(start++, hred, hgreen, hblue, htransp, info))
return 0;
}
return 0;
@@ -261,22 +263,15 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc,
* Get the default colormap for a specific screen depth
*/
-struct fb_cmap *fb_default_cmap(int bpp)
+struct fb_cmap *fb_default_cmap(int len)
{
- switch (bpp) {
- case 1:
- return &default_2_colors;
- break;
- case 2:
- return &default_4_colors;
- break;
- case 3:
- return &default_8_colors;
- break;
- default:
- return &default_16_colors;
- break;
- }
+ if (len <= 2)
+ return &default_2_colors;
+ if (len <= 4)
+ return &default_4_colors;
+ if (len <= 8)
+ return &default_8_colors;
+ return &default_16_colors;
}
diff --git a/drivers/video/fbcon-afb.c b/drivers/video/fbcon-afb.c
index a56323041..66132809a 100644
--- a/drivers/video/fbcon-afb.c
+++ b/drivers/video/fbcon-afb.c
@@ -13,132 +13,242 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
+#include "fbcon-afb.h"
/*
- * Prototypes
- */
-
-static int open_afb(struct display *p);
-static void release_afb(void);
-static void bmove_afb(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_afb(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_afb(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_afb(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
+ * Bitplanes ŕ la Amiga
*/
-static struct display_switch dispsw_afb = {
- open_afb, release_afb, bmove_afb, clear_afb, putc_afb, putcs_afb,
- rev_char_afb
+static u8 expand_table[1024] = {
+ /* bg = fg = 0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* bg = 0, fg = 1 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ /* bg = 1, fg = 0 */
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
+ 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
+ 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
+ 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
+ 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
+ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
+ 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
+ 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
+ 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
+ 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+ 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
+ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
+ 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
+ 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
+ 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+ 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
+ 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
+ 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
+ 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
+ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
+ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ /* bg = fg = 1 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
- /*
- * Bitplanes ŕ la Amiga
- */
-
-static int open_afb(struct display *p)
+void fbcon_afb_setup(struct display *p)
{
- if (p->type != FB_TYPE_PLANES)
- return -EINVAL;
-
if (p->line_length)
p->next_line = p->line_length;
else
p->next_line = p->var.xres_virtual>>3;
p->next_plane = p->var.yres_virtual*p->next_line;
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_afb(void)
+void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_afb(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- u_char *src, *dest, *src0, *dest0;
- u_int i, rows;
+ u8 *src, *dest, *src0, *dest0;
+ u_short i, j;
if (sx == 0 && dx == 0 && width == p->next_line) {
src = p->screen_base+sy*p->fontheight*width;
dest = p->screen_base+dy*p->fontheight*width;
- for (i = p->var.bits_per_pixel; i--;) {
+ i = p->var.bits_per_pixel;
+ do {
mymemmove(dest, src, height*p->fontheight*width);
src += p->next_plane;
dest += p->next_plane;
- }
+ } while (--i);
} else if (dy <= sy) {
src0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel; i--;) {
+ i = p->var.bits_per_pixel;
+ do {
src = src0;
dest = dest0;
- for (rows = height*p->fontheight; rows--;) {
+ j = height*p->fontheight;
+ do {
mymemmove(dest, src, width);
src += p->next_line;
dest += p->next_line;
- }
+ } while (--j);
src0 += p->next_plane;
dest0 += p->next_plane;
- }
+ } while (--i);
} else {
src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel; i--;) {
+ i = p->var.bits_per_pixel;
+ do {
src = src0;
dest = dest0;
- for (rows = height*p->fontheight; rows--;) {
+ j = height*p->fontheight;
+ do {
src -= p->next_line;
dest -= p->next_line;
mymemmove(dest, src, width);
- }
+ } while (--j);
src0 += p->next_plane;
dest0 += p->next_plane;
- }
+ } while (--i);
}
}
-static void clear_afb(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
+void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
{
- u_char *dest, *dest0;
- u_int i, rows;
+ u8 *dest, *dest0;
+ u_short i, j;
int bg;
dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
bg = attr_bgcol_ec(p,conp);
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
+ i = p->var.bits_per_pixel;
+ do {
dest = dest0;
- for (rows = height*p->fontheight; rows--; dest += p->next_line)
+ j = height*p->fontheight;
+ do {
if (bg & 1)
mymemset(dest, width);
else
mymemclear(dest, width);
+ dest += p->next_line;
+ } while (--j);
bg >>= 1;
- }
+ dest0 += p->next_plane;
+ } while (--i);
}
-static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
+void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
{
- u_char *dest, *dest0, *cdat, *cdat0;
- u_int rows, i;
- u_char d;
+ u8 *dest, *dest0, *cdat, *cdat0, *expand;
+ u_short i, j;
int fg, bg;
c &= 0xff;
@@ -148,25 +258,24 @@ static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy,
fg = attr_fgcol(p,conp);
bg = attr_bgcol(p,conp);
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
+ i = p->var.bits_per_pixel;
+ do {
dest = dest0;
cdat = cdat0;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- }
+ expand = expand_table;
+ if (bg & 1)
+ expand += 512;
+ if (fg & 1)
+ expand += 256;
+ j = p->fontheight;
+ do {
+ *dest = expand[*cdat++];
+ dest += p->next_line;
+ } while (--j);
bg >>= 1;
fg >>= 1;
- }
+ dest0 += p->next_plane;
+ } while (--i);
}
/*
@@ -174,14 +283,13 @@ static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy,
* (cfr. fbcon_putcs_ilbm())
*/
-static void putcs_afb(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
+void fbcon_afb_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
{
- u_char *dest, *dest0, *dest1;
- u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
- u_int rows, i;
- u_char c1, c2, c3, c4;
- u_long d;
+ u8 *dest, *dest0, *dest1, *expand;
+ u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
+ u_short i, j;
+ u8 c1, c2, c3, c4;
int fg0, bg0, fg, bg;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -198,26 +306,25 @@ static void putcs_afb(struct vc_data *conp, struct display *p, const char *s,
fg = fg0;
bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
+ i = p->var.bits_per_pixel;
+ do {
dest = dest1;
cdat1 = cdat10;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat1++;
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- }
+ expand = expand_table;
+ if (bg & 1)
+ expand += 512;
+ if (fg & 1)
+ expand += 256;
+ j = p->fontheight;
+ do {
+ *dest = expand[*cdat1++];
+ dest += p->next_line;
+ } while (--j);
bg >>= 1;
fg >>= 1;
- }
- } else { /* Fast version */
+ dest1 += p->next_plane;
+ } while (--i);
+ } else { /* Fast version */
c1 = s[0];
c2 = s[1];
c3 = s[2];
@@ -231,28 +338,39 @@ static void putcs_afb(struct vc_data *conp, struct display *p, const char *s,
fg = fg0;
bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
+ i = p->var.bits_per_pixel;
+ do {
dest = dest1;
cdat1 = cdat10;
cdat2 = cdat20;
cdat3 = cdat30;
cdat4 = cdat40;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
- if (bg & 1)
- if (fg & 1)
- *(u_long *)dest = 0xffffffff;
- else
- *(u_long *)dest = ~d;
- else
- if (fg & 1)
- *(u_long *)dest = d;
- else
- *(u_long *)dest = 0x00000000;
- }
+ expand = expand_table;
+ if (bg & 1)
+ expand += 512;
+ if (fg & 1)
+ expand += 256;
+ j = p->fontheight;
+ do {
+#if defined(__BIG_ENDIAN)
+ *(u32 *)dest = expand[*cdat1++]<<24 |
+ expand[*cdat2++]<<16 |
+ expand[*cdat3++]<<8 |
+ expand[*cdat4++];
+#elif defined(__LITTLE_ENDIAN)
+ *(u32 *)dest = expand[*cdat1++] |
+ expand[*cdat2++]<<8 |
+ expand[*cdat3++]<<16 |
+ expand[*cdat4++]<<24;
+#else
+#error FIXME: No endianness??
+#endif
+ dest += p->next_line;
+ } while (--j);
bg >>= 1;
fg >>= 1;
- }
+ dest1 += p->next_plane;
+ } while (--i);
s += 4;
dest0 += 4;
xx += 4;
@@ -260,10 +378,10 @@ static void putcs_afb(struct vc_data *conp, struct display *p, const char *s,
}
}
-static void rev_char_afb(struct display *p, int xx, int yy)
+void fbcon_afb_revc(struct display *p, int xx, int yy)
{
- u_char *dest, *dest0;
- u_int rows, i;
+ u8 *dest, *dest0;
+ u_short i, j;
int mask;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -275,29 +393,40 @@ static void rev_char_afb(struct display *p, int xx, int yy)
* inverting.
*/
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
+ i = p->var.bits_per_pixel;
+ do {
if (mask & 1) {
dest = dest0;
- for (rows = p->fontheight; rows--; dest += p->next_line)
+ j = p->fontheight;
+ do {
*dest = ~*dest;
+ dest += p->next_line;
+ } while (--j);
}
mask >>= 1;
- }
+ dest0 += p->next_plane;
+ } while (--i);
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_afb(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_afb, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_afb);
-}
-#endif /* MODULE */
+struct display_switch fbcon_afb = {
+ fbcon_afb_setup, fbcon_afb_bmove, fbcon_afb_clear, fbcon_afb_putc,
+ fbcon_afb_putcs, fbcon_afb_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_afb);
+EXPORT_SYMBOL(fbcon_afb_setup);
+EXPORT_SYMBOL(fbcon_afb_bmove);
+EXPORT_SYMBOL(fbcon_afb_clear);
+EXPORT_SYMBOL(fbcon_afb_putc);
+EXPORT_SYMBOL(fbcon_afb_putcs);
+EXPORT_SYMBOL(fbcon_afb_revc);
diff --git a/drivers/video/fbcon-afb.h b/drivers/video/fbcon-afb.h
new file mode 100644
index 000000000..537b3bdd7
--- /dev/null
+++ b/drivers/video/fbcon-afb.h
@@ -0,0 +1,15 @@
+ /*
+ * Amiga bitplanes (afb)
+ */
+
+extern struct display_switch fbcon_afb;
+extern void fbcon_afb_setup(struct display *p);
+extern void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_afb_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_afb_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c
index 8bd58ce8a..b27683c95 100644
--- a/drivers/video/fbcon-cfb16.c
+++ b/drivers/video/fbcon-cfb16.c
@@ -1,6 +1,6 @@
/*
* linux/drivers/video/cfb16.c -- Low level frame buffer operations for 16 bpp
- * packed pixels
+ * truecolor packed pixels
*
* Created 5 Apr 1997 by Geert Uytterhoeven
*
@@ -13,69 +13,40 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
-
-
- /*
- * Prototypes
- */
-
-static int open_cfb16(struct display *p);
-static void release_cfb16(void);
-static void bmove_cfb16(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_cfb16(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_cfb16(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_cfb16(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_cfb16(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_cfb16 = {
- open_cfb16, release_cfb16, bmove_cfb16, clear_cfb16, putc_cfb16,
- putcs_cfb16, rev_char_cfb16
-};
+#include "fbcon-cfb16.h"
/*
* 16 bpp packed pixels
*/
-u_short packed16_cmap[16];
+u16 fbcon_cfb16_cmap[16];
-static u_long tab_cfb16[] = {
- 0x00000000,0x0000ffff,0xffff0000,0xffffffff
+static u32 tab_cfb16[] = {
+#if defined(__BIG_ENDIAN)
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
};
-static int open_cfb16(struct display *p)
+void fbcon_cfb16_setup(struct display *p)
{
- if (p->type != FB_TYPE_PACKED_PIXELS || p->var.bits_per_pixel != 16)
- return -EINVAL;
-
p->next_line = p->var.xres_virtual<<1;
p->next_plane = 0;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static void release_cfb16(void)
-{
- MOD_DEC_USE_COUNT;
}
-static void bmove_cfb16(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
- u_char *src,*dst;
+ u8 *src, *dst;
if (sx == 0 && dx == 0 && width * 16 == bytes)
mymemmove(p->screen_base + dy * linesize,
@@ -100,82 +71,78 @@ static void bmove_cfb16(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_cfb16(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
+void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
{
- u_char *dest0,*dest;
- int bytes=p->next_line,lines=height * p->fontheight, rows, i;
- u_long bgx;
+ u8 *dest0, *dest;
+ int bytes = p->next_line, lines = height * p->fontheight, rows, i;
+ u32 bgx;
dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
- bgx = attr_bgcol_ec(p,conp);
- bgx = packed16_cmap[bgx];
+ 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++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- ((u_long *)dest)[2]=bgx;
- ((u_long *)dest)[3]=bgx;
- dest+=16;
+ ((u32 *)dest)[0] = bgx;
+ ((u32 *)dest)[1] = bgx;
+ ((u32 *)dest)[2] = bgx;
+ ((u32 *)dest)[3] = bgx;
+ dest += 16;
}
else {
- dest0=dest;
+ dest0 = dest;
for (rows = lines; rows-- ; dest0 += bytes) {
- dest=dest0;
+ dest = dest0;
for (i = 0 ; i < width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- ((u_long *)dest)[2]=bgx;
- ((u_long *)dest)[3]=bgx;
- dest+=16;
+ ((u32 *)dest)[0] = bgx;
+ ((u32 *)dest)[1] = bgx;
+ ((u32 *)dest)[2] = bgx;
+ ((u32 *)dest)[3] = bgx;
+ dest += 16;
}
}
}
}
-static void putc_cfb16(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
+void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
{
- u_char *dest,*cdat;
- int bytes=p->next_line,rows;
- ulong eorx,fgx,bgx;
+ u8 *dest, *cdat;
+ int bytes = p->next_line, rows;
+ u32 eorx, fgx, bgx;
c &= 0xff;
dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
cdat = p->fontdata + c * p->fontheight;
- fgx = attr_fgcol(p,conp);
- fgx = packed16_cmap[fgx];
- bgx = attr_bgcol(p,conp);
- bgx = packed16_cmap[bgx];
+ fgx = fbcon_cfb16_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb16_cmap[attr_bgcol(p, conp)];
fgx |= (fgx << 16);
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]= (tab_cfb16[*cdat >> 6] & eorx) ^ bgx;
- ((u_long *)dest)[1]= (tab_cfb16[*cdat >> 4 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[2]= (tab_cfb16[*cdat >> 2 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[3]= (tab_cfb16[*cdat++ & 0x3] & eorx) ^ bgx;
+ 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;
}
}
-static void putcs_cfb16(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
+void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
{
- u_char *cdat, c, *dest, *dest0;
- int rows,bytes=p->next_line;
- u_long eorx, fgx, bgx;
+ u8 *cdat, c, *dest, *dest0;
+ int rows, bytes = p->next_line;
+ u32 eorx, fgx, bgx;
dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- fgx = attr_fgcol(p,conp);
- fgx = packed16_cmap[fgx];
- bgx = attr_bgcol(p,conp);
- bgx = packed16_cmap[bgx];
+ fgx = fbcon_cfb16_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb16_cmap[attr_bgcol(p, conp)];
fgx |= (fgx << 16);
bgx |= (bgx << 16);
eorx = fgx ^ bgx;
@@ -184,49 +151,50 @@ static void putcs_cfb16(struct vc_data *conp, struct display *p, const char *s,
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]= (tab_cfb16[*cdat >> 6] & eorx) ^ bgx;
- ((u_long *)dest)[1]= (tab_cfb16[*cdat >> 4 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[2]= (tab_cfb16[*cdat >> 2 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[3]= (tab_cfb16[*cdat++ & 0x3] & eorx) ^ bgx;
+ 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;
}
- dest0+=16;
+ dest0 += 16;
}
}
-static void rev_char_cfb16(struct display *p, int xx, int yy)
+void fbcon_cfb16_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
- int bytes=p->next_line, rows;
+ 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) {
- ((u_long *)dest)[0] ^= 0xffffffff;
- ((u_long *)dest)[1] ^= 0xffffffff;
- ((u_long *)dest)[2] ^= 0xffffffff;
- ((u_long *)dest)[3] ^= 0xffffffff;
+ ((u32 *)dest)[0] ^= 0xffffffff;
+ ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff;
+ ((u32 *)dest)[3] ^= 0xffffffff;
}
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_cfb16(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_cfb16, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_cfb16);
-}
-#endif /* MODULE */
+struct display_switch fbcon_cfb16 = {
+ fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
+ fbcon_cfb16_putcs, fbcon_cfb16_revc
+};
/*
* Visible symbols for modules
*/
-EXPORT_SYMBOL(packed16_cmap);
+EXPORT_SYMBOL(fbcon_cfb16);
+EXPORT_SYMBOL(fbcon_cfb16_setup);
+EXPORT_SYMBOL(fbcon_cfb16_bmove);
+EXPORT_SYMBOL(fbcon_cfb16_clear);
+EXPORT_SYMBOL(fbcon_cfb16_putc);
+EXPORT_SYMBOL(fbcon_cfb16_putcs);
+EXPORT_SYMBOL(fbcon_cfb16_revc);
+EXPORT_SYMBOL(fbcon_cfb16_cmap);
diff --git a/drivers/video/fbcon-cfb16.h b/drivers/video/fbcon-cfb16.h
new file mode 100644
index 000000000..905d6329a
--- /dev/null
+++ b/drivers/video/fbcon-cfb16.h
@@ -0,0 +1,16 @@
+ /*
+ * 16 bpp packed pixel (cfb16)
+ */
+
+extern struct display_switch fbcon_cfb16;
+extern u16 fbcon_cfb16_cmap[16];
+extern void fbcon_cfb16_setup(struct display *p);
+extern void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb16_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c
new file mode 100644
index 000000000..617c85235
--- /dev/null
+++ b/drivers/video/fbcon-cfb2.c
@@ -0,0 +1,205 @@
+/*
+ * linux/drivers/video/cfb2.c -- Low level frame buffer operations for 2 bpp
+ * packed pixels
+ *
+ * Created 26 Dec 1997 by Michael Schmitz
+ * Based on cfb4.c
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/fb.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb2.h"
+
+
+ /*
+ * 2 bpp packed pixels
+ */
+
+ /*
+ * IFF the font is even pixel aligned (that is to say each
+ * character start is a byte start in the pixel pairs). That
+ * avoids us having to mask bytes and means we won't be here
+ * all week. On a MacII that matters _lots_
+ */
+
+static u_char nibbletab_cfb2[]={
+ 0x00,0x03,0x0c,0x0f,
+ 0x30,0x33,0x3c,0x3f,
+ 0xc0,0xc3,0xcc,0xcf,
+ 0xf0,0xf3,0xfc,0xff
+};
+
+
+void fbcon_cfb2_setup(struct display *p)
+{
+ p->next_line = p->var.xres_virtual>>2;
+ p->next_plane = 0;
+}
+
+void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
+ u8 *src,*dst;
+
+ if (sx == 0 && dx == 0 && width * 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 * 2;
+ dst = p->screen_base + dy * linesize + dx * 2;
+ for (rows = height * p->fontheight ; rows-- ;) {
+ mymemmove(dst, src, width * 2);
+ src += bytes;
+ dst += bytes;
+ }
+ }
+ else {
+ src = p->screen_base + (sy+height) * linesize + sx * 2
+ - bytes;
+ dst = p->screen_base + (dy+height) * linesize + dx * 2
+ - bytes;
+ for (rows = height * p->fontheight ; rows-- ;) {
+ mymemmove(dst, src, width * 2);
+ src -= bytes;
+ dst -= bytes;
+ }
+ }
+ }
+}
+
+void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ u8 *dest0,*dest;
+ int bytes=p->next_line,lines=height * p->fontheight, rows, i;
+ u32 bgx;
+
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * 2;
+
+ bgx=attr_bgcol_ec(p,conp);
+ bgx |= (bgx << 2); /* expand the colour to 16 bits */
+ bgx |= (bgx << 4);
+ bgx |= (bgx << 8);
+
+ if (sx == 0 && width * 2 == bytes) {
+ for (i = 0 ; i < lines * width ; i++) {
+ ((u16 *)dest)[0]=bgx;
+ dest+=2;
+ }
+ } else {
+ dest0=dest;
+ for (rows = lines; rows-- ; dest0 += bytes) {
+ dest=dest0;
+ for (i = 0 ; i < width ; i++) {
+ /* memset ?? */
+ ((u16 *)dest)[0]=bgx;
+ dest+=2;
+ }
+ }
+ }
+}
+
+void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ u8 *dest,*cdat;
+ int bytes=p->next_line,rows;
+ u32 eorx,fgx,bgx;
+
+ c &= 0xff;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 2;
+ cdat = p->fontdata + c * p->fontheight;
+
+ fgx=3;/*attr_fgcol(p,conp)&0x0F;*/
+ bgx=attr_bgcol(p,conp)&0x0F;
+ fgx |= (fgx << 2); /* expand color to 8 bits */
+ fgx |= (fgx << 4);
+ bgx |= (bgx << 2);
+ bgx |= (bgx << 4);
+ eorx = fgx ^ bgx;
+
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u8 *)dest)[0]=
+ (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
+ ((u8 *)dest)[1]=
+ (nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+ }
+}
+
+void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u8 *cdat, c, *dest, *dest0;
+ int rows,bytes=p->next_line;
+ u32 eorx, fgx, bgx;
+
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 2;
+ fgx=3/*attr_fgcol(p,conp)*/;
+ bgx=attr_bgcol(p,conp);
+ fgx |= (fgx << 2);
+ fgx |= (fgx << 4);
+ bgx |= (bgx << 2);
+ bgx |= (bgx << 4);
+ eorx = fgx ^ bgx;
+ while (count--) {
+ c = *s++;
+ cdat = p->fontdata + c * p->fontheight;
+
+ for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
+ ((u8 *)dest)[0]=
+ (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
+ ((u8 *)dest)[1]=
+ (nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+ }
+ dest0+=2;
+ }
+}
+
+void fbcon_cfb2_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 * 2;
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u16 *)dest)[0] ^= 0xffff;
+ }
+}
+
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_cfb2 = {
+ fbcon_cfb2_setup, fbcon_cfb2_bmove, fbcon_cfb2_clear, fbcon_cfb2_putc,
+ fbcon_cfb2_putcs, fbcon_cfb2_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_cfb2);
+EXPORT_SYMBOL(fbcon_cfb2_setup);
+EXPORT_SYMBOL(fbcon_cfb2_bmove);
+EXPORT_SYMBOL(fbcon_cfb2_clear);
+EXPORT_SYMBOL(fbcon_cfb2_putc);
+EXPORT_SYMBOL(fbcon_cfb2_putcs);
+EXPORT_SYMBOL(fbcon_cfb2_revc);
diff --git a/drivers/video/fbcon-cfb2.h b/drivers/video/fbcon-cfb2.h
new file mode 100644
index 000000000..4fb3bb13a
--- /dev/null
+++ b/drivers/video/fbcon-cfb2.h
@@ -0,0 +1,15 @@
+ /*
+ * 2 bpp packed pixel (cfb2)
+ */
+
+extern struct display_switch fbcon_cfb2;
+extern void fbcon_cfb2_setup(struct display *p);
+extern void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb2_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c
new file mode 100644
index 000000000..65a4ad556
--- /dev/null
+++ b/drivers/video/fbcon-cfb24.c
@@ -0,0 +1,221 @@
+/*
+ * linux/drivers/video/cfb24.c -- Low level frame buffer operations for 24 bpp
+ * truecolor packed pixels
+ *
+ * Created 7 Mar 1998 by Geert Uytterhoeven
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/fb.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb24.h"
+
+
+#warning Remove this warning after the test cycle was finalized
+
+
+ /*
+ * 24 bpp packed pixels
+ */
+
+u32 fbcon_cfb24_cmap[16];
+
+void fbcon_cfb24_setup(struct display *p)
+{
+ p->next_line = p->line_length ? p->line_length : p->var.xres_virtual*3;
+ p->next_plane = 0;
+}
+
+void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
+ u8 *src, *dst;
+
+ if (sx == 0 && dx == 0 && width * 24 == 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);
+ 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 -= bytes;
+ dst -= bytes;
+ }
+ }
+}
+
+void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ u8 *dest0, *dest;
+ int bytes = p->next_line, lines = height * p->fontheight, rows, i;
+ u32 bgx;
+
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * 24;
+
+ 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;
+ }
+ else {
+ dest0 = dest;
+ 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;
+ }
+ }
+ }
+}
+
+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)
+#error Please add support for little endian byteorder
+#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;
+ int bytes = p->next_line, rows;
+ u32 eorx, fgx, bgx;
+
+ c &= 0xff;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+ cdat = p->fontdata + c * p->fontheight;
+
+ fgx = fbcon_cfb24_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb24_cmap[attr_bgcol(p, conp)];
+ eorx = fgx ^ bgx;
+
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ u8 bits = *cdat++;
+ u32 d1, d2, d3, d4;
+ 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);
+ 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));
+ }
+}
+
+void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u8 *cdat, c, *dest, *dest0;
+ int rows, bytes = p->next_line;
+ u32 eorx, fgx, bgx;
+
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+ fgx = fbcon_cfb24_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb24_cmap[attr_bgcol(p, conp)];
+ 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 d1, d2, d3, d4;
+ 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);
+ 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));
+ }
+ dest0 += 24;
+ }
+}
+
+void fbcon_cfb24_revc(struct display *p, int xx, int yy)
+{
+ u8 *dest;
+ int bytes = p->next_line, rows;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u32 *)dest)[0] ^= 0xffffffff;
+ ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff;
+ ((u32 *)dest)[3] ^= 0xffffffff;
+ ((u32 *)dest)[4] ^= 0xffffffff;
+ ((u32 *)dest)[5] ^= 0xffffffff;
+ }
+}
+
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_cfb24 = {
+ fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
+ fbcon_cfb24_putcs, fbcon_cfb24_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_cfb24);
+EXPORT_SYMBOL(fbcon_cfb24_setup);
+EXPORT_SYMBOL(fbcon_cfb24_bmove);
+EXPORT_SYMBOL(fbcon_cfb24_clear);
+EXPORT_SYMBOL(fbcon_cfb24_putc);
+EXPORT_SYMBOL(fbcon_cfb24_putcs);
+EXPORT_SYMBOL(fbcon_cfb24_revc);
+EXPORT_SYMBOL(fbcon_cfb24_cmap);
diff --git a/drivers/video/fbcon-cfb24.h b/drivers/video/fbcon-cfb24.h
new file mode 100644
index 000000000..bd672ab20
--- /dev/null
+++ b/drivers/video/fbcon-cfb24.h
@@ -0,0 +1,16 @@
+ /*
+ * 24 bpp packed pixel (cfb24)
+ */
+
+extern struct display_switch fbcon_cfb24;
+extern u32 fbcon_cfb24_cmap[16];
+extern void fbcon_cfb24_setup(struct display *p);
+extern void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb24_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c
new file mode 100644
index 000000000..8c3306458
--- /dev/null
+++ b/drivers/video/fbcon-cfb32.c
@@ -0,0 +1,205 @@
+/*
+ * linux/drivers/video/cfb32.c -- Low level frame buffer operations for 32 bpp
+ * truecolor packed pixels
+ *
+ * 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 COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/fb.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb32.h"
+
+
+ /*
+ * 32 bpp packed pixels
+ */
+
+u32 fbcon_cfb32_cmap[16];
+
+void fbcon_cfb32_setup(struct display *p)
+{
+ p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2;
+ p->next_plane = 0;
+}
+
+void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
+ u8 *src, *dst;
+
+ if (sx == 0 && dx == 0 && width * 32 == 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);
+ 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 -= bytes;
+ dst -= bytes;
+ }
+ }
+}
+
+void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ u8 *dest0, *dest;
+ int bytes = p->next_line, lines = height * p->fontheight, rows, i;
+ u32 bgx;
+
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * 32;
+
+ bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
+
+ if (sx == 0 && width * 32 == 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;
+ }
+ else {
+ dest0 = dest;
+ 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;
+ ((u32 *)dest)[6] = bgx;
+ ((u32 *)dest)[7] = bgx;
+ dest += 32;
+ }
+ }
+ }
+}
+
+void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ u8 *dest, *cdat;
+ int bytes = p->next_line, rows;
+ u32 eorx, fgx, bgx;
+
+ c &= 0xff;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+ cdat = p->fontdata + c * p->fontheight;
+
+ fgx = fbcon_cfb32_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb32_cmap[attr_bgcol(p, conp)];
+ eorx = fgx ^ bgx;
+
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ u8 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;
+ ((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;
+ }
+}
+
+void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u8 *cdat, c, *dest, *dest0;
+ int rows, bytes = p->next_line;
+ u32 eorx, fgx, bgx;
+
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+ fgx = fbcon_cfb32_cmap[attr_fgcol(p, conp)];
+ bgx = fbcon_cfb32_cmap[attr_bgcol(p, conp)];
+ 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] = (-(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;
+ ((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;
+ }
+ dest0 += 32;
+ }
+}
+
+void fbcon_cfb32_revc(struct display *p, int xx, int yy)
+{
+ u8 *dest;
+ int bytes = p->next_line, rows;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u32 *)dest)[0] ^= 0xffffffff;
+ ((u32 *)dest)[1] ^= 0xffffffff;
+ ((u32 *)dest)[2] ^= 0xffffffff;
+ ((u32 *)dest)[3] ^= 0xffffffff;
+ ((u32 *)dest)[4] ^= 0xffffffff;
+ ((u32 *)dest)[5] ^= 0xffffffff;
+ ((u32 *)dest)[6] ^= 0xffffffff;
+ ((u32 *)dest)[7] ^= 0xffffffff;
+ }
+}
+
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_cfb32 = {
+ fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
+ fbcon_cfb32_putcs, fbcon_cfb32_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_cfb32);
+EXPORT_SYMBOL(fbcon_cfb32_setup);
+EXPORT_SYMBOL(fbcon_cfb32_bmove);
+EXPORT_SYMBOL(fbcon_cfb32_clear);
+EXPORT_SYMBOL(fbcon_cfb32_putc);
+EXPORT_SYMBOL(fbcon_cfb32_putcs);
+EXPORT_SYMBOL(fbcon_cfb32_revc);
+EXPORT_SYMBOL(fbcon_cfb32_cmap);
diff --git a/drivers/video/fbcon-cfb32.h b/drivers/video/fbcon-cfb32.h
new file mode 100644
index 000000000..1f74141c2
--- /dev/null
+++ b/drivers/video/fbcon-cfb32.h
@@ -0,0 +1,16 @@
+ /*
+ * 32 bpp packed pixel (cfb32)
+ */
+
+extern struct display_switch fbcon_cfb32;
+extern u32 fbcon_cfb32_cmap[16];
+extern void fbcon_cfb32_setup(struct display *p);
+extern void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb32_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c
new file mode 100644
index 000000000..bcdfcc436
--- /dev/null
+++ b/drivers/video/fbcon-cfb4.c
@@ -0,0 +1,208 @@
+/*
+ * linux/drivers/video/cfb4.c -- Low level frame buffer operations for 4 bpp
+ * packed pixels
+ *
+ * Created 26 Dec 1997 by Michael Schmitz
+ * Based on the old macfb.c 4bpp code by Alan Cox
+ *
+ * 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/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/fb.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb4.h"
+
+
+ /*
+ * 4 bpp packed pixels
+ */
+
+ /*
+ * IFF the font is even pixel aligned (that is to say each
+ * character start is a byte start in the pixel pairs). That
+ * avoids us having to mask bytes and means we won't be here
+ * all week. On a MacII that matters _lots_
+ */
+
+static u16 nibbletab_cfb4[] = {
+ 0x0000,0x000f,0x00f0,0x00ff,
+ 0x0f00,0x0f0f,0x0ff0,0x0fff,
+ 0xf000,0xf00f,0xf0f0,0xf0ff,
+ 0xff00,0xff0f,0xfff0,0xffff
+};
+
+void fbcon_cfb4_setup(struct display *p)
+{
+ p->next_line = p->var.xres_virtual>>1;
+ p->next_plane = 0;
+}
+
+void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
+ u8 *src,*dst;
+
+ if (sx == 0 && dx == 0 && width * 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 * 4;
+ dst = p->screen_base + dy * linesize + dx * 4;
+ for (rows = height * p->fontheight ; rows-- ;) {
+ mymemmove(dst, src, width * 4);
+ src += bytes;
+ dst += bytes;
+ }
+ }
+ else {
+ src = p->screen_base + (sy+height) * linesize + sx * 4
+ - bytes;
+ dst = p->screen_base + (dy+height) * linesize + dx * 4
+ - bytes;
+ for (rows = height * p->fontheight ; rows-- ;) {
+ mymemmove(dst, src, width * 4);
+ src -= bytes;
+ dst -= bytes;
+ }
+ }
+ }
+}
+
+void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ u8 *dest0,*dest;
+ int bytes=p->next_line,lines=height * p->fontheight, rows, i;
+ u32 bgx;
+
+/* if(p->screen_base!=0xFDD00020)
+ mac_boom(1);*/
+ dest = p->screen_base + sy * p->fontheight * bytes + sx * 4;
+
+ bgx=attr_bgcol_ec(p,conp);
+ bgx |= (bgx << 4); /* expand the colour to 32bits */
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+
+ if (sx == 0 && width * 4 == bytes) {
+ for (i = 0 ; i < lines * width ; i++) {
+ ((u32 *)dest)[0]=bgx;
+ dest+=4;
+ }
+ } else {
+ dest0=dest;
+ for (rows = lines; rows-- ; dest0 += bytes) {
+ dest=dest0;
+ for (i = 0 ; i < width ; i++) {
+ /* memset ?? */
+ ((u32 *)dest)[0]=bgx;
+ dest+=4;
+ }
+ }
+ }
+}
+
+void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ u8 *dest,*cdat;
+ int bytes=p->next_line,rows;
+ u32 eorx,fgx,bgx;
+
+ c &= 0xff;
+
+ dest = p->screen_base + yy * p->fontheight * bytes + xx * 4;
+ cdat = p->fontdata + c * p->fontheight;
+
+ fgx=15;/*attr_fgcol(p,conp)&0x0F;*/
+ bgx=attr_bgcol(p,conp)&0x0F;
+ fgx |= (fgx << 4);
+ fgx |= (fgx << 8);
+ bgx |= (bgx << 4);
+ bgx |= (bgx << 8);
+ eorx = fgx ^ bgx;
+
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u16 *)dest)[0]=
+ (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
+ ((u16 *)dest)[1]=
+ (nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+ }
+}
+
+void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u8 *cdat, c, *dest, *dest0;
+ int rows,bytes=p->next_line;
+ u32 eorx, fgx, bgx;
+
+ dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 4;
+ fgx=15/*attr_fgcol(p,conp)*/;
+ bgx=attr_bgcol(p,conp);
+ fgx |= (fgx << 4);
+ fgx |= (fgx << 8);
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 4);
+ bgx |= (bgx << 8);
+ 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) {
+ ((u16 *)dest)[0]=
+ (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
+ ((u16 *)dest)[1]=
+ (nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+ }
+ dest0+=4;
+ }
+}
+
+void fbcon_cfb4_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 * 4;
+ for (rows = p->fontheight ; rows-- ; dest += bytes) {
+ ((u32 *)dest)[0] ^= 0x0f0f0f0f;
+ }
+}
+
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_cfb4 = {
+ fbcon_cfb4_setup, fbcon_cfb4_bmove, fbcon_cfb4_clear, fbcon_cfb4_putc,
+ fbcon_cfb4_putcs, fbcon_cfb4_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_cfb4);
+EXPORT_SYMBOL(fbcon_cfb4_setup);
+EXPORT_SYMBOL(fbcon_cfb4_bmove);
+EXPORT_SYMBOL(fbcon_cfb4_clear);
+EXPORT_SYMBOL(fbcon_cfb4_putc);
+EXPORT_SYMBOL(fbcon_cfb4_putcs);
+EXPORT_SYMBOL(fbcon_cfb4_revc);
diff --git a/drivers/video/fbcon-cfb4.h b/drivers/video/fbcon-cfb4.h
new file mode 100644
index 000000000..6fe3bc5a4
--- /dev/null
+++ b/drivers/video/fbcon-cfb4.h
@@ -0,0 +1,15 @@
+ /*
+ * 4 bpp packed pixel (cfb4)
+ */
+
+extern struct display_switch fbcon_cfb4;
+extern void fbcon_cfb4_setup(struct display *p);
+extern void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb4_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c
index 5fa339be1..c559f4025 100644
--- a/drivers/video/fbcon-cfb8.c
+++ b/drivers/video/fbcon-cfb8.c
@@ -13,70 +13,44 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
-
-
- /*
- * Prototypes
- */
-
-static int open_cfb8(struct display *p);
-static void release_cfb8(void);
-static void bmove_cfb8(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_cfb8(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_cfb8(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_cfb8(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_cfb8(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_cfb8 = {
- open_cfb8, release_cfb8, bmove_cfb8, clear_cfb8, putc_cfb8, putcs_cfb8,
- rev_char_cfb8
-};
+#include "fbcon-cfb8.h"
/*
* 8 bpp packed pixels
*/
-static u_long nibbletab_cfb8[] = {
+static u32 nibbletab_cfb8[] = {
+#if defined(__BIG_ENDIAN)
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000,0xff000000,0x00ff0000,0xffff0000,
+ 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+ 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+ 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
};
-static int open_cfb8(struct display *p)
+void fbcon_cfb8_setup(struct display *p)
{
- if (p->type != FB_TYPE_PACKED_PIXELS || p->var.bits_per_pixel != 8)
- return -EINVAL;
-
p->next_line = p->var.xres_virtual;
p->next_plane = 0;
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_cfb8(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_cfb8(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
- u_char *src,*dst;
+ u8 *src,*dst;
if (sx == 0 && dx == 0 && width * 8 == bytes)
mymemmove(p->screen_base + dy * linesize,
@@ -101,12 +75,12 @@ static void bmove_cfb8(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_cfb8(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
+void fbcon_cfb8_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
{
- u_char *dest0,*dest;
+ u8 *dest0,*dest;
int bytes=p->next_line,lines=height * p->fontheight, rows, i;
- u_long bgx;
+ u32 bgx;
dest = p->screen_base + sy * p->fontheight * bytes + sx * 8;
@@ -116,8 +90,8 @@ static void clear_cfb8(struct vc_data *conp, struct display *p, int sy, int sx,
if (sx == 0 && width * 8 == bytes)
for (i = 0 ; i < lines * width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
+ ((u32 *)dest)[0]=bgx;
+ ((u32 *)dest)[1]=bgx;
dest+=8;
}
else {
@@ -125,20 +99,20 @@ static void clear_cfb8(struct vc_data *conp, struct display *p, int sy, int sx,
for (rows = lines; rows-- ; dest0 += bytes) {
dest=dest0;
for (i = 0 ; i < width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
+ ((u32 *)dest)[0]=bgx;
+ ((u32 *)dest)[1]=bgx;
dest+=8;
}
}
}
}
-static void putc_cfb8(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
+void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
{
- u_char *dest,*cdat;
+ u8 *dest,*cdat;
int bytes=p->next_line,rows;
- ulong eorx,fgx,bgx;
+ u32 eorx,fgx,bgx;
c &= 0xff;
@@ -154,17 +128,17 @@ static void putc_cfb8(struct vc_data *conp, struct display *p, int c, int yy,
eorx = fgx ^ bgx;
for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u_long *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
+ ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
+ ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
}
}
-static void putcs_cfb8(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
+void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
{
- u_char *cdat, c, *dest, *dest0;
+ u8 *cdat, c, *dest, *dest0;
int rows,bytes=p->next_line;
- u_long eorx, fgx, bgx;
+ u32 eorx, fgx, bgx;
dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 8;
fgx=attr_fgcol(p,conp);
@@ -179,39 +153,44 @@ static void putcs_cfb8(struct vc_data *conp, struct display *p, const char *s,
cdat = p->fontdata + c * p->fontheight;
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u_long *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^
- bgx;
+ ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
+ ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
}
dest0+=8;
}
}
-static void rev_char_cfb8(struct display *p, int xx, int yy)
+void fbcon_cfb8_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
+ u8 *dest;
int bytes=p->next_line, rows;
dest = p->screen_base + yy * p->fontheight * bytes + xx * 8;
for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0] ^= 0x0f0f0f0f;
- ((u_long *)dest)[1] ^= 0x0f0f0f0f;
+ ((u32 *)dest)[0] ^= 0x0f0f0f0f;
+ ((u32 *)dest)[1] ^= 0x0f0f0f0f;
}
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_cfb8(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_cfb8, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_cfb8);
-}
-#endif /* MODULE */
+struct display_switch fbcon_cfb8 = {
+ fbcon_cfb8_setup, fbcon_cfb8_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
+ fbcon_cfb8_putcs, fbcon_cfb8_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_cfb8);
+EXPORT_SYMBOL(fbcon_cfb8_setup);
+EXPORT_SYMBOL(fbcon_cfb8_bmove);
+EXPORT_SYMBOL(fbcon_cfb8_clear);
+EXPORT_SYMBOL(fbcon_cfb8_putc);
+EXPORT_SYMBOL(fbcon_cfb8_putcs);
+EXPORT_SYMBOL(fbcon_cfb8_revc);
diff --git a/drivers/video/fbcon-cfb8.h b/drivers/video/fbcon-cfb8.h
new file mode 100644
index 000000000..4c0ffec99
--- /dev/null
+++ b/drivers/video/fbcon-cfb8.h
@@ -0,0 +1,15 @@
+ /*
+ * 8 bpp packed pixel (cfb8)
+ */
+
+extern struct display_switch fbcon_cfb8;
+extern void fbcon_cfb8_setup(struct display *p);
+extern void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_cfb8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_cfb8_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-cyber.c b/drivers/video/fbcon-cyber.c
deleted file mode 100644
index ee740516d..000000000
--- a/drivers/video/fbcon-cyber.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * linux/drivers/video/cyber.c -- Low level frame buffer operations for the
- * CyberVision64 (accelerated)
- *
- * Created 5 Apr 1997 by Geert Uytterhoeven
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-
-#include "fbcon.h"
-#include "s3blit.h"
-
-
- /*
- * Prototypes
- */
-
-static int open_cyber(struct display *p);
-static void release_cyber(void);
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_cyber(struct display *p, int xx, int yy);
-
-
- /*
- * Acceleration functions in cyberfb.c
- */
-
-extern void Cyber_WaitQueue(unsigned short fifo);
-extern void Cyber_WaitBlit(void);
-extern void Cyber_BitBLT(unsigned short curx, unsigned short cury,
- unsigned short destx, unsigned short desty,
- unsigned short width, unsigned short height,
- unsigned short mode);
-extern void Cyber_RectFill(unsigned short xx, unsigned short yy,
- unsigned short width, unsigned short height,
- unsigned short mode, unsigned short fillcolor);
-extern void Cyber_MoveCursor(unsigned short xx, unsigned short yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_cyber = {
- open_cyber, release_cyber, bmove_cyber, clear_cyber, putc_cyber,
- putcs_cyber, rev_char_cyber
-};
-
-
- /*
- * CyberVision64 (accelerated)
- */
-
-static int open_cyber(struct display *p)
-{
- if (p->type != FB_TYPE_PACKED_PIXELS ||
- p->var.accel != FB_ACCEL_CYBERVISION)
- return -EINVAL;
-
- p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
- p->next_plane = 0;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static void release_cyber(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- sx *= 8; dx *= 8; width *= 8;
- Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
- (u_short)(dy*p->fontheight), (u_short)width,
- (u_short)(height*p->fontheight), (u_short)S3_NEW);
-}
-
-static void clear_cyber(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- Cyber_RectFill((u_short)sx,
- (u_short)(sy*p->fontheight),
- (u_short)width,
- (u_short)(height*p->fontheight),
- (u_short)S3_NEW,
- (u_short)bg);
-}
-
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest, *cdat;
- u_long tmp;
- u_int rows, revs, underl;
- u_char d;
- u_char fg, bg;
-
- c &= 0xff;
-
- dest = p->screen_base+yy*p->fontheight*p->next_line+8*xx;
- cdat = p->fontdata+(c*p->fontheight);
- fg = p->fgcol;
- bg = p->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- Cyber_WaitBlit();
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((u_long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((u_long*) dest + 1) = tmp;
- }
-}
-
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
-{
- u_char *dest, *dest0, *cdat;
- u_long tmp;
- u_int rows, underl;
- u_char c, d;
- u_char fg, bg;
-
- dest0 = p->screen_base+yy*p->fontheight*p->next_line+8*xx;
- fg = p->fgcol;
- bg = p->bgcol;
- underl = conp->vc_underline;
-
- Cyber_WaitBlit();
- while (count--) {
- c = *s++;
- dest = dest0;
- dest0 += 8;
- cdat = p->fontdata+(c*p->fontheight);
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((u_long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((u_long*) dest + 1) = tmp;
- }
- }
-}
-
-
-static void rev_char_cyber(struct display *p, int xx, int yy)
-{
- unsigned char *dest;
- unsigned int rows;
- unsigned char fg, bg;
-
- fg = p->fgcol;
- bg = p->bgcol;
-
- dest = p->screen_base+yy*p->fontheight*p->next_line+8*xx;
- Cyber_WaitBlit();
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- *dest = (*dest == fg) ? bg : fg;
- *(dest+1) = (*(dest + 1) == fg) ? bg : fg;
- *(dest+2) = (*(dest + 2) == fg) ? bg : fg;
- *(dest+3) = (*(dest + 3) == fg) ? bg : fg;
- *(dest+4) = (*(dest + 4) == fg) ? bg : fg;
- *(dest+5) = (*(dest + 5) == fg) ? bg : fg;
- *(dest+6) = (*(dest + 6) == fg) ? bg : fg;
- *(dest+7) = (*(dest + 7) == fg) ? bg : fg;
- }
-}
-
-
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_cyber(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_cyber, 1));
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_cyber);
-}
-#endif /* MODULE */
diff --git a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c
index 33be946e2..82f9982f6 100644
--- a/drivers/video/fbcon-ilbm.c
+++ b/drivers/video/fbcon-ilbm.c
@@ -16,33 +16,7 @@
#include <linux/fb.h>
#include "fbcon.h"
-
-
- /*
- * Prototypes
- */
-
-static int open_ilbm(struct display *p);
-static void release_ilbm(void);
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_ilbm(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_ilbm = {
- open_ilbm, release_ilbm, bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm,
- rev_char_ilbm
-};
+#include "fbcon-ilbm.h"
/*
@@ -56,11 +30,8 @@ static struct display_switch dispsw_ilbm = {
* much performance loss?
*/
-static int open_ilbm(struct display *p)
+void fbcon_ilbm_setup(struct display *p)
{
- if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux == 2)
- return -EINVAL;
-
if (p->line_length) {
p->next_line = p->line_length*p->var.bits_per_pixel;
p->next_plane = p->line_length;
@@ -68,24 +39,17 @@ static int open_ilbm(struct display *p)
p->next_line = p->type_aux;
p->next_plane = p->type_aux/p->var.bits_per_pixel;
}
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_ilbm(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
if (sx == 0 && dx == 0 && width == p->next_plane)
mymemmove(p->screen_base+dy*p->fontheight*p->next_line,
p->screen_base+sy*p->fontheight*p->next_line,
height*p->fontheight*p->next_line);
else {
- u_char *src, *dest;
+ u8 *src, *dest;
u_int i;
if (dy <= sy) {
@@ -108,10 +72,10 @@ static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
+void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
{
- u_char *dest;
+ u8 *dest;
u_int i, rows;
int bg, bg0;
@@ -130,12 +94,12 @@ static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
}
}
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
+void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
{
- u_char *dest, *cdat;
+ u8 *dest, *cdat;
u_int rows, i;
- u_char d;
+ u8 d;
int fg0, bg0, fg, bg;
c &= 0xff;
@@ -150,16 +114,17 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
fg = fg0;
bg = bg0;
for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
+ if (bg & 1){
if (fg & 1)
*dest = 0xff;
else
*dest = ~d;
- else
+ }else{
if (fg & 1)
*dest = d;
else
*dest = 0x00;
+ }
bg >>= 1;
fg >>= 1;
}
@@ -181,13 +146,13 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
* -- Geert
*/
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
+void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
{
- u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
+ u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
u_int rows, i;
- u_char c1, c2, c3, c4;
- u_long d;
+ u8 c1, c2, c3, c4;
+ u32 d;
int fg0, bg0, fg, bg;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -206,16 +171,17 @@ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
fg = fg0;
bg = bg0;
for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
+ if (bg & 1){
if (fg & 1)
*dest = 0xff;
else
*dest = ~d;
- else
+ }else{
if (fg & 1)
*dest = d;
else
*dest = 0x00;
+ }
bg >>= 1;
fg >>= 1;
}
@@ -232,20 +198,27 @@ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
cdat3 = p->fontdata+c3*p->fontheight;
cdat4 = p->fontdata+c4*p->fontheight;
for (rows = p->fontheight; rows--;) {
+#if defined(__BIG_ENDIAN)
d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
+#elif defined(__LITTLE_ENDIAN)
+ d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<32);
+#else
+#error FIXME: No endianness??
+#endif
fg = fg0;
bg = bg0;
for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
+ if (bg & 1){
if (fg & 1)
- *(u_long *)dest = 0xffffffff;
+ *(u32 *)dest = 0xffffffff;
else
- *(u_long *)dest = ~d;
- else
+ *(u32 *)dest = ~d;
+ }else{
if (fg & 1)
- *(u_long *)dest = d;
+ *(u32 *)dest = d;
else
- *(u_long *)dest = 0x00000000;
+ *(u32 *)dest = 0x00000000;
+ }
bg >>= 1;
fg >>= 1;
}
@@ -257,9 +230,9 @@ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
}
}
-static void rev_char_ilbm(struct display *p, int xx, int yy)
+void fbcon_ilbm_revc(struct display *p, int xx, int yy)
{
- u_char *dest, *dest0;
+ u8 *dest, *dest0;
u_int rows, i;
int mask;
@@ -283,18 +256,24 @@ static void rev_char_ilbm(struct display *p, int xx, int yy)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_ilbm(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_ilbm, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_ilbm);
-}
-#endif /* MODULE */
+struct display_switch fbcon_ilbm = {
+ fbcon_ilbm_setup, fbcon_ilbm_bmove, fbcon_ilbm_clear, fbcon_ilbm_putc,
+ fbcon_ilbm_putcs, fbcon_ilbm_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_ilbm);
+EXPORT_SYMBOL(fbcon_ilbm_setup);
+EXPORT_SYMBOL(fbcon_ilbm_bmove);
+EXPORT_SYMBOL(fbcon_ilbm_clear);
+EXPORT_SYMBOL(fbcon_ilbm_putc);
+EXPORT_SYMBOL(fbcon_ilbm_putcs);
+EXPORT_SYMBOL(fbcon_ilbm_revc);
diff --git a/drivers/video/fbcon-ilbm.h b/drivers/video/fbcon-ilbm.h
new file mode 100644
index 000000000..e2434c7d1
--- /dev/null
+++ b/drivers/video/fbcon-ilbm.h
@@ -0,0 +1,15 @@
+ /*
+ * Amiga interleaved bitplanes (ilbm)
+ */
+
+extern struct display_switch fbcon_ilbm;
+extern void fbcon_ilbm_setup(struct display *p);
+extern void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_ilbm_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-iplan2p2.c b/drivers/video/fbcon-iplan2p2.c
index 3973a0013..adef5819d 100644
--- a/drivers/video/fbcon-iplan2p2.c
+++ b/drivers/video/fbcon-iplan2p2.c
@@ -14,41 +14,13 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
-#include "fbcon.h"
-
-
-#ifndef __mc68000__
-#error No support for non-m68k yet
-#endif
+#include <asm/byteorder.h>
-
- /*
- * Prototypes
- */
-
-static int open_iplan2p2(struct display *p);
-static void release_iplan2p2(void);
-static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_iplan2p2(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_iplan2p2(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_iplan2p2(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_iplan2p2(struct display *display, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_iplan2p2 = {
- open_iplan2p2, release_iplan2p2, bmove_iplan2p2, clear_iplan2p2,
- putc_iplan2p2, putcs_iplan2p2, rev_char_iplan2p2
-};
+#include "fbcon.h"
+#include "fbcon-iplan2p2.h"
/*
@@ -65,8 +37,19 @@ static struct display_switch dispsw_iplan2p2 = {
* The intensity bit (b3) is shifted into b1.
*/
-#define COLOR_2P(c) (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2)
+static const u8 color_2p[] = { 0, 0, 0, 1, 0, 1, 1, 1, 2, 2, 2, 3, 2, 3, 3, 3 };
+#define COLOR_2P(c) color_2p[c]
+/* Perform the m68k movepw operation. */
+static inline void movepw(u8 *d, u16 val)
+{
+#if defined __mc68000__ && !defined CONFIG_OPTIMIZE_060
+ asm volatile ("movepw %1,%0@(0)" : : "a" (d), "d" (val));
+#else
+ d[0] = (val >> 16) & 0xff;
+ d[2] = val & 0xff;
+#endif
+}
/* Sets the bytes in the visible column at d, height h, to the value
* val for a 2 plane screen. The the bis of the color in 'color' are
@@ -77,16 +60,13 @@ static struct display_switch dispsw_iplan2p2 = {
* *(d+2) = (color & 2) ? 0xff : 0;
*/
-static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr)
+static __inline__ void memclear_2p_col(void *d, size_t h, u16 val, int bpr)
{
-#ifdef __mc68000__
- __asm__ __volatile__ ("1: movepw %4,%0@(0)\n\t"
- "addal %5,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val), "r" (bpr));
-#else /* !m68k */
-#endif /* !m68k */
+ u8 *dd = d;
+ do {
+ movepw(dd, val);
+ dd += bpr;
+ } while (--h);
}
/* Sets a 2 plane region from 'd', length 'count' bytes, to the color
@@ -98,9 +78,9 @@ static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr)
* *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
*/
-static __inline__ void memset_even_2p(void *d, size_t count, u_long val)
+static __inline__ void memset_even_2p(void *d, size_t count, u32 val)
{
- u_long *dd = d;
+ u32 *dd = d;
count /= 4;
while (count--)
@@ -111,7 +91,7 @@ static __inline__ void memset_even_2p(void *d, size_t count, u_long val)
static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
{
- u_char *dd = d, *ss = s;
+ u8 *dd = d, *ss = s;
while (h--) {
dd[0] = ss[0];
@@ -124,81 +104,54 @@ static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
/* This expands a 2 bit color into a short for movepw (2 plane) operations. */
-static __inline__ u_short expand2w(u_char c)
+static const u16 two2byte[] = {
+ 0x0000, 0xff00, 0x00ff, 0xffff
+};
+
+static __inline__ u16 expand2w(u8 c)
{
- u_short rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c));
-#endif /* !m68k */
- return(rv);
+ return two2byte[c];
}
+
/* This expands a 2 bit color into one long for a movel operation
* (2 planes).
*/
-static __inline__ u_long expand2l(u_char c)
+static const u32 two2word[] = {
+#ifndef __LITTLE_ENDIAN
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#endif
+};
+
+static __inline__ u32 expand2l(u8 c)
{
- u_long rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "swap %0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c));
-#endif /* !m68k */
- return rv;
+ return two2word[c];
}
/* This duplicates a byte 2 times into a short. */
-static __inline__ u_short dup2w(u_char c)
+static __inline__ u16 dup2w(u8 c)
{
- ushort rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("moveb %1,%0\n\t"
- "lslw #8,%0\n\t"
- "moveb %1,%0\n\t"
- : "=&d" (rv)
- : "d" (c));
-#endif /* !m68k */
- return( rv );
+ u16 rv;
+
+ rv = c;
+ rv |= c << 8;
+ return rv;
}
-static int open_iplan2p2(struct display *p)
+void fbcon_iplan2p2_setup(struct display *p)
{
- if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 ||
- p->var.bits_per_pixel != 2)
- return -EINVAL;
-
p->next_line = p->var.xres_virtual>>2;
p->next_plane = 2;
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_iplan2p2(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
/* bmove() has to distinguish two major cases: If both, source and
* destination, start at even addresses or both are at odd
@@ -212,7 +165,7 @@ static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx,
* all movements by memmove_col().
*/
- if (sx == 0 && dx == 0 && width == p->next_line/2) {
+ if (sx == 0 && dx == 0 && width * 2 == p->next_line) {
/* Special (but often used) case: Moving whole lines can be
* done with memmove()
*/
@@ -221,8 +174,8 @@ static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx,
p->next_line * height * p->fontheight);
} else {
int rows, cols;
- u_char *src;
- u_char *dst;
+ u8 *src;
+ u8 *dst;
int bytes = p->next_line;
int linesize = bytes * p->fontheight;
u_int colsize = height * p->fontheight;
@@ -298,21 +251,21 @@ static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_iplan2p2(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
+void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
{
- ulong offset;
- u_char *start;
+ u32 offset;
+ u8 *start;
int rows;
int bytes = p->next_line;
int lines = height * p->fontheight;
- ulong size;
- u_long cval;
- u_short pcval;
+ u32 size;
+ u32 cval;
+ u16 pcval;
cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
- if (sx == 0 && width == bytes/2) {
+ if (sx == 0 && width * 2 == bytes) {
offset = sy * bytes * p->fontheight;
size = lines * bytes;
memset_even_2p(p->screen_base+offset, size, cval);
@@ -344,14 +297,14 @@ static void clear_iplan2p2(struct vc_data *conp, struct display *p, int sy,
}
}
-static void putc_iplan2p2(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
+void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
{
- u_char *dest;
- u_char *cdat;
+ u8 *dest;
+ u8 *cdat;
int rows;
int bytes = p->next_line;
- ulong eorx, fgx, bgx, fdx;
+ u16 eorx, fgx, bgx, fdx;
c &= 0xff;
@@ -364,22 +317,18 @@ static void putc_iplan2p2(struct vc_data *conp, struct display *p, int c,
for (rows = p->fontheight ; rows-- ; dest += bytes) {
fdx = dup2w(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepw %1,%0@(0)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-#endif /* !m68k */
+ movepw(dest, (fdx & eorx) ^ bgx);
}
}
-static void putcs_iplan2p2(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
+void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
{
- u_char *dest, *dest0;
- u_char *cdat, c;
+ u8 *dest, *dest0;
+ u8 *cdat, c;
int rows;
int bytes;
- ulong eorx, fgx, bgx, fdx;
+ u16 eorx, fgx, bgx, fdx;
bytes = p->next_line;
dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1);
@@ -393,19 +342,15 @@ static void putcs_iplan2p2(struct vc_data *conp, struct display *p,
for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
fdx = dup2w(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepw %1,%0@(0)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-#endif /* !m68k */
+ movepw(dest, (fdx & eorx) ^ bgx);
}
INC_2P(dest0);
}
}
-static void rev_char_iplan2p2(struct display *p, int xx, int yy)
+void fbcon_iplan2p2_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
+ u8 *dest;
int j;
int bytes;
@@ -425,18 +370,24 @@ static void rev_char_iplan2p2(struct display *p, int xx, int yy)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_iplan2p2(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_iplan2p2, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_iplan2p2);
-}
-#endif /* MODULE */
+struct display_switch fbcon_iplan2p2 = {
+ fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear,
+ fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_iplan2p2);
+EXPORT_SYMBOL(fbcon_iplan2p2_setup);
+EXPORT_SYMBOL(fbcon_iplan2p2_bmove);
+EXPORT_SYMBOL(fbcon_iplan2p2_clear);
+EXPORT_SYMBOL(fbcon_iplan2p2_putc);
+EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
+EXPORT_SYMBOL(fbcon_iplan2p2_revc);
diff --git a/drivers/video/fbcon-iplan2p2.h b/drivers/video/fbcon-iplan2p2.h
new file mode 100644
index 000000000..ae18a1b32
--- /dev/null
+++ b/drivers/video/fbcon-iplan2p2.h
@@ -0,0 +1,15 @@
+ /*
+ * Atari interleaved bitplanes (2 planes) (iplan2p2)
+ */
+
+extern struct display_switch fbcon_iplan2p2;
+extern void fbcon_iplan2p2_setup(struct display *p);
+extern void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width);
+extern void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_iplan2p2_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-iplan2p4.c b/drivers/video/fbcon-iplan2p4.c
index e3a10f0ea..b299701c4 100644
--- a/drivers/video/fbcon-iplan2p4.c
+++ b/drivers/video/fbcon-iplan2p4.c
@@ -14,41 +14,13 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
-#include "fbcon.h"
-
-
-#ifndef __mc68000__
-#error No support for non-m68k yet
-#endif
-
-
- /*
- * Prototypes
- */
-
-static int open_iplan2p4(struct display *p);
-static void release_iplan2p4(void);
-static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_iplan2p4(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_iplan2p4(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_iplan2p4(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_iplan2p4(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
+#include <asm/byteorder.h>
-static struct display_switch dispsw_iplan2p4 = {
- open_iplan2p4, release_iplan2p4, bmove_iplan2p4, clear_iplan2p4,
- putc_iplan2p4, putcs_iplan2p4, rev_char_iplan2p4
-};
+#include "fbcon.h"
+#include "fbcon-iplan2p4.h"
/*
@@ -60,6 +32,18 @@ static struct display_switch dispsw_iplan2p4 = {
#define INC_4P(p) do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
#define DEC_4P(p) do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
+/* Perform the m68k movepl operation. */
+static inline void movepl(u8 *d, u32 val)
+{
+#if defined __mc68000__ && !defined CONFIG_OPTIMIZE_060
+ asm volatile ("movepl %1,%0@(0)" : : "a" (d), "d" (val));
+#else
+ d[0] = (val >> 24) & 0xff;
+ d[2] = (val >> 16) & 0xff;
+ d[4] = (val >> 8) & 0xff;
+ d[6] = val & 0xff;
+#endif
+}
/* Sets the bytes in the visible column at d, height h, to the value
* val for a 4 plane screen. The the bis of the color in 'color' are
@@ -72,15 +56,13 @@ static struct display_switch dispsw_iplan2p4 = {
* *(d+6) = (color & 8) ? 0xff : 0;
*/
-static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr)
+static __inline__ void memclear_4p_col(void *d, size_t h, u32 val, int bpr)
{
-#ifdef __mc68000__
- __asm__ __volatile__ ("1: movepl %4,%0@(0)\n\t"
- "addal %5,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val), "r" (bpr));
-#endif /* !m68k */
+ u8 *dd = d;
+ do {
+ movepl(dd, val);
+ dd += bpr;
+ } while (--h);
}
/* Sets a 4 plane region from 'd', length 'count' bytes, to the color
@@ -94,10 +76,10 @@ static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr)
* *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
*/
-static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
- u_long val2)
+static __inline__ void memset_even_4p(void *d, size_t count, u32 val1,
+ u32 val2)
{
- u_long *dd = d;
+ u32 *dd = d;
count /= 8;
while (count--) {
@@ -110,7 +92,7 @@ static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
{
- u_char *dd = d, *ss = s;
+ u8 *dd = d, *ss = s;
while (h--) {
dd[0] = ss[0];
@@ -125,99 +107,59 @@ static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
/* This expands a 4 bit color into a long for movepl (4 plane) operations. */
-static __inline__ u_long expand4l(u_char c)
+static const u32 four2byte[] = {
+ 0x00000000, 0xff000000, 0x00ff0000, 0xffff0000,
+ 0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00,
+ 0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff,
+ 0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff
+};
+
+static __inline__ u32 expand4l(u8 c)
{
- u_long rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c));
-#endif /* !m68k */
- return(rv);
+ return four2byte[c];
}
+
/* This expands a 4 bit color into two longs for two movel operations
* (4 planes).
*/
-static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2)
+static const u32 two2word[] = {
+#ifndef __LITTLE_ENDIAN
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff,
+#else
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff,
+#endif
+};
+
+static __inline__ void expand4dl(u8 c, u32 *ret1, u32 *ret2)
{
- u_long rv1, rv2;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("lsrb #1,%3\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "swap %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "extw %1\n\t"
- "swap %1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "extw %1"
- : "=&d" (rv1), "=&d" (rv2), "=d" (c)
- : "2" (c));
-#endif /* !m68k */
- *ret1 = rv1;
- *ret2 = rv2;
+ *ret1 = two2word[c & 3];
+ *ret2 = two2word[c >> 2];
}
/* This duplicates a byte 4 times into a long. */
-static __inline__ u_long dup4l(u_char c)
+static __inline__ u32 dup4l(u8 c)
{
- ushort tmp;
- ulong rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("moveb %2,%0\n\t"
- "lslw #8,%0\n\t"
- "moveb %2,%0\n\t"
- "movew %0,%1\n\t"
- "swap %0\n\t"
- "movew %1,%0"
- : "=&d" (rv), "=d" (tmp)
- : "d" (c));
-#endif /* !m68k */
- return(rv);
+ u32 rv;
+
+ rv = c;
+ rv |= rv << 8;
+ rv |= rv << 16;
+ return rv;
}
-static int open_iplan2p4(struct display *p)
+void fbcon_iplan2p4_setup(struct display *p)
{
- if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 ||
- p->var.bits_per_pixel != 4)
- return -EINVAL;
-
p->next_line = p->var.xres_virtual>>1;
p->next_plane = 2;
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_iplan2p4(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
/* bmove() has to distinguish two major cases: If both, source and
* destination, start at even addresses or both are at odd
@@ -231,7 +173,7 @@ static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx,
* all movements by memmove_col().
*/
- if (sx == 0 && dx == 0 && width == p->next_line/4) {
+ if (sx == 0 && dx == 0 && width * 4 == p->next_line) {
/* Special (but often used) case: Moving whole lines can be
*done with memmove()
*/
@@ -240,8 +182,8 @@ static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx,
p->next_line * height * p->fontheight);
} else {
int rows, cols;
- u_char *src;
- u_char *dst;
+ u8 *src;
+ u8 *dst;
int bytes = p->next_line;
int linesize = bytes * p->fontheight;
u_int colsize = height * p->fontheight;
@@ -320,20 +262,20 @@ static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_iplan2p4(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
+void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
{
- ulong offset;
- u_char *start;
+ u32 offset;
+ u8 *start;
int rows;
int bytes = p->next_line;
int lines = height * p->fontheight;
- ulong size;
- u_long cval1, cval2, pcval;
+ u32 size;
+ u32 cval1, cval2, pcval;
expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
- if (sx == 0 && width == bytes/4) {
+ if (sx == 0 && width * 4 == bytes) {
offset = sy * bytes * p->fontheight;
size = lines * bytes;
memset_even_4p(p->screen_base+offset, size, cval1, cval2);
@@ -365,14 +307,14 @@ static void clear_iplan2p4(struct vc_data *conp, struct display *p, int sy,
}
}
-static void putc_iplan2p4(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
+void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
{
- u_char *dest;
- u_char *cdat;
+ u8 *dest;
+ u8 *cdat;
int rows;
int bytes = p->next_line;
- ulong eorx, fgx, bgx, fdx;
+ u32 eorx, fgx, bgx, fdx;
c &= 0xff;
@@ -385,22 +327,18 @@ static void putc_iplan2p4(struct vc_data *conp, struct display *p, int c,
for(rows = p->fontheight ; rows-- ; dest += bytes) {
fdx = dup4l(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepl %1,%0@(0)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-#endif /* !m68k */
+ movepl(dest, (fdx & eorx) ^ bgx);
}
}
-static void putcs_iplan2p4(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
+void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
{
- u_char *dest, *dest0;
- u_char *cdat, c;
+ u8 *dest, *dest0;
+ u8 *cdat, c;
int rows;
int bytes;
- ulong eorx, fgx, bgx, fdx;
+ u32 eorx, fgx, bgx, fdx;
bytes = p->next_line;
dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1);
@@ -421,19 +359,15 @@ static void putcs_iplan2p4(struct vc_data *conp, struct display *p,
for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
fdx = dup4l(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepl %1,%0@(0)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-#endif /* !m68k */
+ movepl(dest, (fdx & eorx) ^ bgx);
}
INC_4P(dest0);
}
}
-static void rev_char_iplan2p4(struct display *p, int xx, int yy)
+void fbcon_iplan2p4_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
+ u8 *dest;
int j;
int bytes;
@@ -456,18 +390,24 @@ static void rev_char_iplan2p4(struct display *p, int xx, int yy)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_iplan2p4(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_iplan2p4, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_iplan2p4);
-}
-#endif /* MODULE */
+struct display_switch fbcon_iplan2p4 = {
+ fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear,
+ fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_iplan2p4);
+EXPORT_SYMBOL(fbcon_iplan2p4_setup);
+EXPORT_SYMBOL(fbcon_iplan2p4_bmove);
+EXPORT_SYMBOL(fbcon_iplan2p4_clear);
+EXPORT_SYMBOL(fbcon_iplan2p4_putc);
+EXPORT_SYMBOL(fbcon_iplan2p4_putcs);
+EXPORT_SYMBOL(fbcon_iplan2p4_revc);
diff --git a/drivers/video/fbcon-iplan2p4.h b/drivers/video/fbcon-iplan2p4.h
new file mode 100644
index 000000000..ae3b38494
--- /dev/null
+++ b/drivers/video/fbcon-iplan2p4.h
@@ -0,0 +1,15 @@
+ /*
+ * Atari interleaved bitplanes (4 planes) (iplan2p4)
+ */
+
+extern struct display_switch fbcon_iplan2p4;
+extern void fbcon_iplan2p4_setup(struct display *p);
+extern void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width);
+extern void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_iplan2p4_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-iplan2p8.c b/drivers/video/fbcon-iplan2p8.c
index 78f2f2e0e..5ea15c26b 100644
--- a/drivers/video/fbcon-iplan2p8.c
+++ b/drivers/video/fbcon-iplan2p8.c
@@ -14,41 +14,13 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
-#include "fbcon.h"
-
-
-#ifndef __mc68000__
-#error No support for non-m68k yet
-#endif
-
-
- /*
- * Prototypes
- */
-
-static int open_iplan2p8(struct display *p);
-static void release_iplan2p8(void);
-static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_iplan2p8(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_iplan2p8(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_iplan2p8(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_iplan2p8(struct display *display, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
+#include <asm/byteorder.h>
-static struct display_switch dispsw_iplan2p8 = {
- open_iplan2p8, release_iplan2p8, bmove_iplan2p8, clear_iplan2p8,
- putc_iplan2p8, putcs_iplan2p8, rev_char_iplan2p8
-};
+#include "fbcon.h"
+#include "fbcon-iplan2p8.h"
/*
@@ -65,9 +37,26 @@ static struct display_switch dispsw_iplan2p8 = {
#define INC_8P(p) do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
#define DEC_8P(p) do { if ((long)(--(p)) & 1) (p) -= 14; } while(0)
+/* Perform the m68k movepl operation extended to 64 bits. */
+static inline void movepl2(u8 *d, u32 val1, u32 val2)
+{
+#if defined __mc68000__ && !defined CONFIG_OPTIMIZE_060
+ asm volatile ("movepl %1,%0@(0); movepl %2,%0@(8)"
+ : : "a" (d), "d" (val1), "d" (val2));
+#else
+ d[0] = (val1 >> 24) & 0xff;
+ d[2] = (val1 >> 16) & 0xff;
+ d[4] = (val1 >> 8) & 0xff;
+ d[6] = val1 & 0xff;
+ d[8] = (val2 >> 24) & 0xff;
+ d[10] = (val2 >> 16) & 0xff;
+ d[12] = (val2 >> 8) & 0xff;
+ d[14] = val2 & 0xff;
+#endif
+}
/* Sets the bytes in the visible column at d, height h, to the value
- * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are
+ * val1,val2 for a 8 plane screen. The bits of the color in 'color' are
* moved (8 times) to the respective bytes. This means:
*
* for(h times; d += bpr)
@@ -81,18 +70,14 @@ static struct display_switch dispsw_iplan2p8 = {
* *(d+14) = (color & 128) ? 0xff : 0;
*/
-static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
- u_long val2, int bpr)
+static __inline__ void memclear_8p_col(void *d, size_t h, u32 val1,
+ u32 val2, int bpr)
{
-#ifdef __mc68000__
- __asm__ __volatile__ ("1: movepl %4,%0@(0)\n\t"
- "movepl %5,%0@(8)\n\t"
- "addal %6,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val1), "d" (val2),
- "r" (bpr));
-#endif /* !m68k */
+ u8 *dd = d;
+ do {
+ movepl2(dd, val1, val2);
+ dd += bpr;
+ } while (--h);
}
/* Sets a 8 plane region from 'd', length 'count' bytes, to the color
@@ -110,10 +95,10 @@ static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
* *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
*/
-static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
- u_long val2, u_long val3, u_long val4)
+static __inline__ void memset_even_8p(void *d, size_t count, u32 val1,
+ u32 val2, u32 val3, u32 val4)
{
- u_long *dd = d;
+ u32 *dd = d;
count /= 16;
while (count--) {
@@ -128,7 +113,7 @@ static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
{
- u_char *dd = d, *ss = s;
+ u8 *dd = d, *ss = s;
while (h--) {
dd[0] = ss[0];
@@ -149,124 +134,64 @@ static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
* operations.
*/
-static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2)
+static const u32 four2long[] =
+{
+ 0x00000000, 0xff000000, 0x00ff0000, 0xffff0000,
+ 0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00,
+ 0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff,
+ 0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff,
+};
+
+static __inline__ void expand8dl(u8 c, u32 *ret1, u32 *ret2)
{
- u_long rv1, rv2;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1"
- : "=&d" (rv1), "=&d" (rv2),"=d" (c)
- : "2" (c));
-#endif /* !m68k */
- *ret1 = rv1;
- *ret2 = rv2;
+ *ret1 = four2long[c & 15];
+ *ret2 = four2long[c >> 4];
}
+
/* This expands a 8 bit color into four longs for four movel operations
* (8 planes).
*/
-#ifdef __mc68000__
-/* ++andreas: use macro to avoid taking address of return values */
-#define expand8ql(c, rv1, rv2, rv3, rv4) \
- do { \
- u_char tmp = c; \
- __asm__ __volatile__ ("lsrb #1,%5\n\t" \
- "scs %0\n\t" \
- "extw %0\n\t" \
- "swap %0\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %0\n\t" \
- "extw %0\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %1\n\t" \
- "extw %1\n\t" \
- "swap %1\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %1\n\t" \
- "extw %1\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %2\n\t" \
- "extw %2\n\t" \
- "swap %2\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %2\n\t" \
- "extw %2\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %3\n\t" \
- "extw %3\n\t" \
- "swap %3\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %3\n\t" \
- "extw %3" \
- : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3), \
- "=&d" (rv4), "=d" (tmp) \
- : "4" (tmp)); \
- } while (0)
-#endif /* !m68k */
+static const u32 two2word[] =
+{
+#ifndef __LITTLE_ENDIAN
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#endif
+};
+
+static inline void expand8ql(u8 c, u32 *rv1, u32 *rv2, u32 *rv3, u32 *rv4)
+{
+ *rv1 = two2word[c & 4];
+ *rv2 = two2word[(c >> 2) & 4];
+ *rv3 = two2word[(c >> 4) & 4];
+ *rv4 = two2word[c >> 6];
+}
/* This duplicates a byte 4 times into a long. */
-static __inline__ u_long dup4l(u_char c)
+static __inline__ u32 dup4l(u8 c)
{
- ushort tmp;
- ulong rv;
-
-#ifdef __mc68000__
- __asm__ __volatile__ ("moveb %2,%0\n\t"
- "lslw #8,%0\n\t"
- "moveb %2,%0\n\t"
- "movew %0,%1\n\t"
- "swap %0\n\t"
- "movew %1,%0"
- : "=&d" (rv), "=d" (tmp)
- : "d" (c));
-#endif /* !m68k */
- return(rv);
+ u32 rv;
+
+ rv = c;
+ rv |= rv << 8;
+ rv |= rv << 16;
+ return rv;
}
-static int open_iplan2p8(struct display *p)
+void fbcon_iplan2p8_setup(struct display *p)
{
- if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 ||
- p->var.bits_per_pixel != 8)
- return -EINVAL;
-
p->next_line = p->var.xres_virtual;
p->next_plane = 2;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static void release_iplan2p8(void)
-{
- MOD_DEC_USE_COUNT;
}
-static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+void fbcon_iplan2p8_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
/* bmove() has to distinguish two major cases: If both, source and
* destination, start at even addresses or both are at odd
@@ -280,7 +205,7 @@ static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx,
* all movements by memmove_col().
*/
- if (sx == 0 && dx == 0 && width == p->next_line/8) {
+ if (sx == 0 && dx == 0 && width * 8 == p->next_line) {
/* Special (but often used) case: Moving whole lines can be
* done with memmove()
*/
@@ -289,8 +214,8 @@ static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx,
p->next_line * height * p->fontheight);
} else {
int rows, cols;
- u_char *src;
- u_char *dst;
+ u8 *src;
+ u8 *dst;
int bytes = p->next_line;
int linesize = bytes * p->fontheight;
u_int colsize = height * p->fontheight;
@@ -369,20 +294,20 @@ static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_iplan2p8(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
+void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
{
- ulong offset;
- u_char *start;
+ u32 offset;
+ u8 *start;
int rows;
int bytes = p->next_line;
int lines = height * p->fontheight;
- ulong size;
- u_long cval1, cval2, cval3, cval4, pcval1, pcval2;
+ u32 size;
+ u32 cval1, cval2, cval3, cval4, pcval1, pcval2;
- expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4);
+ expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4);
- if (sx == 0 && width == bytes/8) {
+ if (sx == 0 && width * 8 == bytes) {
offset = sy * bytes * p->fontheight;
size = lines * bytes;
memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4);
@@ -414,14 +339,14 @@ static void clear_iplan2p8(struct vc_data *conp, struct display *p, int sy,
}
}
-static void putc_iplan2p8(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
+void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
{
- u_char *dest;
- u_char *cdat;
+ u8 *dest;
+ u8 *cdat;
int rows;
int bytes = p->next_line;
- ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
+ u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
c &= 0xff;
@@ -434,24 +359,18 @@ static void putc_iplan2p8(struct vc_data *conp, struct display *p, int c,
for(rows = p->fontheight ; rows-- ; dest += bytes) {
fdx = dup4l(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepl %1,%0@(0)\n\t"
- "movepl %2,%0@(8)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
- "d" ((fdx & eorx2) ^ bgx2) );
-#endif /* !m68k */
+ movepl2(dest, (fdx & eorx1) ^ bgx1, (fdx & eorx2) ^ bgx2);
}
}
-static void putcs_iplan2p8(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
+void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx)
{
- u_char *dest, *dest0;
- u_char *cdat, c;
+ u8 *dest, *dest0;
+ u8 *cdat, c;
int rows;
int bytes;
- ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
+ u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
bytes = p->next_line;
dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 +
@@ -475,21 +394,15 @@ static void putcs_iplan2p8(struct vc_data *conp, struct display *p,
for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
fdx = dup4l(*cdat++);
-#ifdef __mc68000__
- __asm__ __volatile__ ("movepl %1,%0@(0)\n\t"
- "movepl %2,%0@(8)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
- "d" ((fdx & eorx2) ^ bgx2));
-#endif /* !m68k */
+ movepl2(dest, (fdx & eorx1) ^ bgx1, (fdx & eorx2) ^ bgx2);
}
INC_8P(dest0);
}
}
-static void rev_char_iplan2p8(struct display *p, int xx, int yy)
+void fbcon_iplan2p8_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
+ u8 *dest;
int j;
int bytes;
@@ -502,7 +415,7 @@ static void rev_char_iplan2p8(struct display *p, int xx, int yy)
/* This should really obey the individual character's
* background and foreground colors instead of simply
* inverting. For 8 plane mode, only the lower 4 bits of the
- * color are inverted, because only that color registers have
+ * color are inverted, because only these color registers have
* been set up.
*/
dest[0] = ~dest[0];
@@ -514,18 +427,24 @@ static void rev_char_iplan2p8(struct display *p, int xx, int yy)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_iplan2p8(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_iplan2p8, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_iplan2p8);
-}
-#endif /* MODULE */
+struct display_switch fbcon_iplan2p8 = {
+ fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear,
+ fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_iplan2p8);
+EXPORT_SYMBOL(fbcon_iplan2p8_setup);
+EXPORT_SYMBOL(fbcon_iplan2p8_bmove);
+EXPORT_SYMBOL(fbcon_iplan2p8_clear);
+EXPORT_SYMBOL(fbcon_iplan2p8_putc);
+EXPORT_SYMBOL(fbcon_iplan2p8_putcs);
+EXPORT_SYMBOL(fbcon_iplan2p8_revc);
diff --git a/drivers/video/fbcon-iplan2p8.h b/drivers/video/fbcon-iplan2p8.h
new file mode 100644
index 000000000..f2c46e229
--- /dev/null
+++ b/drivers/video/fbcon-iplan2p8.h
@@ -0,0 +1,15 @@
+ /*
+ * Atari interleaved bitplanes (8 planes) (iplan2p8)
+ */
+
+extern struct display_switch fbcon_iplan2p8;
+extern void fbcon_iplan2p8_setup(struct display *p);
+extern void fbcon_iplan2p8_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p,
+ int sy, int sx, int height, int width);
+extern void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_iplan2p8_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c
new file mode 100644
index 000000000..1dd5f1988
--- /dev/null
+++ b/drivers/video/fbcon-mac.c
@@ -0,0 +1,513 @@
+/*
+ * linux/drivers/video/fbcon-mac.c -- Low level frame buffer operations for
+ * x bpp packed pixels, font width != 8
+ *
+ * Created 26 Dec 1997 by Michael Schmitz
+ * Based on the old macfb.c 6x11 code by Randy Thelen
+ *
+ * This driver is significantly slower than the 8bit font drivers
+ * and would probably benefit from splitting into drivers for each depth.
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+
+#include "fbcon.h"
+#include "fbcon-mac.h"
+
+
+ /*
+ * variable bpp packed pixels
+ */
+
+static void plot_pixel_mac(struct display *p, int bw, int pixel_x,
+ int pixel_y);
+static int get_pixel_mac(struct display *p, int pixel_x, int pixel_y);
+
+void fbcon_mac_setup(struct display *p)
+{
+ if (p->line_length)
+ p->next_line = p->line_length;
+ else
+ p->next_line = p->var.xres_virtual>>3;
+ p->next_plane = 0;
+}
+
+
+ /*
+ * Macintosh
+ */
+#define PIXEL_BLACK_MAC 0
+#define PIXEL_WHITE_MAC 1
+#define PIXEL_INVERT_MAC 2
+
+void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int i, j;
+ u8 *dest, *src;
+ int l,r,t,b,w,lo,s;
+ int dl,dr,dt,db,dw,dlo;
+ int move_up;
+
+ src = (u8 *) (p->screen_base + sy * p->fontheight * p->next_line);
+ dest = (u8 *) (p->screen_base + dy * p->fontheight * p->next_line);
+
+ if( sx == 0 && width == p->conp->vc_cols) {
+ s = height * p->fontheight * p->next_line;
+ mymemmove(dest, src, s);
+ return;
+ }
+
+ l = sx * p->fontwidth;
+ r = l + width * p->fontwidth;
+ t = sy * p->fontheight;
+ b = t + height * p->fontheight;
+
+ dl = dx * p->fontwidth;
+ dr = dl + width * p->fontwidth;
+ dt = dy * p->fontheight;
+ db = dt + height * p->fontheight;
+
+ /* w is the # pixels between two long-aligned points, left and right */
+ w = (r&~31) - ((l+31)&~31);
+ dw = (dr&~31) - ((dl+31)&~31);
+ /* lo is the # pixels between the left edge and a long-aligned left pixel */
+ lo = ((l+31)&~31) - l;
+ dlo = ((dl+31)&~31) - dl;
+
+ /* if dx != sx then, logic has to align the left and right edges for fast moves */
+ if (lo != dlo) {
+ lo = ((l+7)&~7) - l;
+ dlo = ((dl+7)&~7) - dl;
+ w = (r&~7) - ((l+7)&~7);
+ dw = (dr&~7) - ((dl+7)&~7);
+ if (lo != dlo) {
+ char err_str[256];
+ unsigned long cnt;
+ sprintf( err_str, "ERROR: Shift algorithm: sx=%d,sy=%d,dx=%d,dy=%d,w=%d,h=%d,bpp=%d",
+ sx,sy,dx,dy,width,height,p->var.bits_per_pixel);
+ fbcon_mac_putcs(p->conp, p, err_str, strlen(err_str), 0, 0);
+ /* pause for the user */
+ for(cnt = 0; cnt < 50000; cnt++)
+ udelay(100);
+ return;
+ }
+ }
+
+ s = 0;
+ switch (p->var.bits_per_pixel) {
+ case 1:
+ s = w >> 3;
+ src += lo >> 3;
+ dest += lo >> 3;
+ break;
+ case 2:
+ s = w >> 2;
+ src += lo >> 2;
+ dest += lo >> 2;
+ break;
+ case 4:
+ s = w >> 1;
+ src += lo >> 1;
+ dest += lo >> 1;
+ break;
+ case 8:
+ s = w;
+ src += lo;
+ dest += lo;
+ break;
+ case 16:
+ s = w << 1;
+ src += lo << 1;
+ dest += lo << 1;
+ break;
+ case 32:
+ s = w << 2;
+ src += lo << 2;
+ dest += lo << 2;
+ break;
+ }
+
+ if (sy <= sx) {
+ i = b;
+ move_up = 0;
+ src += height * p->fontheight;
+ dest += height * p->fontheight;
+ } else {
+ i = t;
+ move_up = 1;
+ }
+
+ while (1) {
+ for (i = t; i < b; i++) {
+ j = l;
+
+ for (; j & 31 && j < r; j++)
+ plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
+
+ if (j < r) {
+ mymemmove(dest, src, s);
+ if (move_up) {
+ dest += p->next_line;
+ src += p->next_line;
+ } else {
+ dest -= p->next_line;
+ src -= p->next_line;
+ }
+ j += w;
+ }
+
+ for (; j < r; j++)
+ plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
+ }
+
+ if (move_up) {
+ i++;
+ if (i >= b)
+ break;
+ } else {
+ i--;
+ if (i < t)
+ break;
+ }
+ }
+}
+
+
+void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ int pixel;
+ int i, j;
+ int inverse;
+ u8 *dest;
+ int l,r,t,b,w,lo,s;
+
+ inverse = attr_reverse(p,conp);
+ pixel = inverse ? PIXEL_WHITE_MAC : PIXEL_BLACK_MAC;
+ dest = (u8 *) (p->screen_base + sy * p->fontheight * p->next_line);
+
+ if( sx == 0 && width == p->conp->vc_cols) {
+ s = height * p->fontheight * p->next_line;
+ if (inverse)
+ mymemclear(dest, s);
+ else
+ mymemset(dest, s);
+ }
+
+ l = sx * p->fontwidth;
+ r = l + width * p->fontwidth;
+ t = sy * p->fontheight;
+ b = t + height * p->fontheight;
+ /* w is the # pixels between two long-aligned points, left and right */
+ w = (r&~31) - ((l+31)&~31);
+ /* lo is the # pixels between the left edge and a long-aligned left pixel */
+ lo = ((l+31)&~31) - l;
+ s = 0;
+ switch (p->var.bits_per_pixel) {
+ case 1:
+ s = w >> 3;
+ dest += lo >> 3;
+ break;
+ case 2:
+ s = w >> 2;
+ dest += lo >> 2;
+ break;
+ case 4:
+ s = w >> 1;
+ dest += lo >> 1;
+ break;
+ case 8:
+ s = w;
+ dest += lo;
+ break;
+ case 16:
+ s = w << 1;
+ dest += lo << 1;
+ break;
+ case 32:
+ s = w << 2;
+ dest += lo << 2;
+ break;
+ }
+
+ for (i = t; i < b; i++) {
+ j = l;
+
+ for (; j & 31 && j < r; j++)
+ plot_pixel_mac(p, pixel, j, i);
+
+ if (j < r) {
+ if (PIXEL_WHITE_MAC == pixel)
+ mymemclear(dest, s);
+ else
+ mymemset(dest, s);
+ dest += p->next_line;
+ j += w;
+ }
+
+ for (; j < r; j++)
+ plot_pixel_mac(p, pixel, j, i);
+ }
+}
+
+
+void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ u8 *cdat;
+ u_int rows, bold, ch_reverse, ch_underline;
+ u8 d;
+ int j;
+
+ c &= 0xff;
+
+ cdat = p->fontdata+c*p->fontheight;
+ bold = attr_bold(p,conp);
+ ch_reverse = attr_reverse(p,conp);
+ ch_underline = attr_underline(p,conp);
+
+ for (rows = 0; rows < p->fontheight; rows++) {
+ d = *cdat++;
+ if (!conp->vc_can_do_color) {
+ if (ch_underline && rows == (p->fontheight-2))
+ d = 0xff;
+ else if (bold)
+ d |= d>>1;
+ if (ch_reverse)
+ d = ~d;
+ }
+ for (j = 0; j < p->fontwidth; j++) {
+ plot_pixel_mac(p, (d & 0x80) >> 7, (xx*p->fontwidth) + j, (yy*p->fontheight) + rows);
+ d <<= 1;
+ }
+ }
+}
+
+
+void fbcon_mac_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u8 c;
+
+ while (count--) {
+ c = *s++;
+ fbcon_mac_putc(conp, p, c, yy, xx++);
+ }
+}
+
+
+void fbcon_mac_revc(struct display *p, int xx, int yy)
+{
+ u_int rows, j;
+
+ for (rows = 0; rows < p->fontheight; rows++) {
+ for (j = 0; j < p->fontwidth; j++) {
+ plot_pixel_mac (p, PIXEL_INVERT_MAC, (xx*p->fontwidth)+j, (yy*p->fontheight)+rows);
+ }
+ }
+}
+
+/*
+ * plot_pixel_mac
+ *
+ * bw == 0 = black
+ * 1 = white
+ * 2 = invert
+ */
+static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y)
+{
+ u8 *dest, bit;
+ u16 *dest16, pix16;
+ u32 *dest32, pix32;
+
+ if (pixel_x < 0 || pixel_y < 0 || pixel_x >= 832 || pixel_y >= 624) {
+ int cnt;
+ printk ("ERROR: pixel_x == %d, pixel_y == %d", pixel_x, pixel_y);
+ for(cnt = 0; cnt < 100000; cnt++)
+ udelay(100);
+ return;
+ }
+
+ switch (p->var.bits_per_pixel) {
+ case 1:
+ dest = (u8 *) ((pixel_x >> 3) + p->screen_base + pixel_y * p->next_line);
+ bit = 0x80 >> (pixel_x & 7);
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest |= bit;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest &= ~bit;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest ^= bit;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+
+ case 2:
+ dest = (u8 *) ((pixel_x >> 2) + p->screen_base + pixel_y * p->next_line);
+ bit = 0xC0 >> ((pixel_x & 3) << 1);
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest |= bit;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest &= ~bit;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest ^= bit;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+
+ case 4:
+ dest = (u8 *) ((pixel_x / 2) + p->screen_base + pixel_y * p->next_line);
+ bit = 0xF0 >> ((pixel_x & 1) << 2);
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest |= bit;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest &= ~bit;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest ^= bit;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+
+ case 8:
+ dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
+ bit = 0xFF;
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest |= bit;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest &= ~bit;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest ^= bit;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+
+ case 16:
+ dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
+ pix16 = 0xFFFF;
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest16 = ~pix16;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest16 = pix16;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest16 ^= pix16;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+
+ case 32:
+ dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
+ pix32 = 0xFFFFFFFF;
+ switch (bw) {
+ case PIXEL_BLACK_MAC:
+ *dest32 = ~pix32;
+ break;
+ case PIXEL_WHITE_MAC:
+ *dest32 = pix32;
+ break;
+ case PIXEL_INVERT_MAC:
+ *dest32 ^= pix32;
+ break;
+ default:
+ printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
+ }
+ break;
+ }
+}
+
+static int get_pixel_mac(struct display *p, int pixel_x, int pixel_y)
+{
+ u8 *dest, bit;
+ u16 *dest16;
+ u32 *dest32;
+ u8 pixel;
+
+ switch (p->var.bits_per_pixel) {
+ case 1:
+ dest = (u8 *) ((pixel_x / 8) + p->screen_base + pixel_y * p->next_line);
+ bit = 0x80 >> (pixel_x & 7);
+ pixel = *dest & bit;
+ break;
+ case 2:
+ dest = (u8 *) ((pixel_x / 4) + p->screen_base + pixel_y * p->next_line);
+ bit = 0xC0 >> (pixel_x & 3);
+ pixel = *dest & bit;
+ break;
+ case 4:
+ dest = (u8 *) ((pixel_x / 2) + p->screen_base + pixel_y * p->next_line);
+ bit = 0xF0 >> (pixel_x & 1);
+ pixel = *dest & bit;
+ break;
+ case 8:
+ dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
+ pixel = *dest;
+ break;
+ case 16:
+ dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
+ pixel = *dest16 ? 1 : 0;
+ break;
+ case 32:
+ dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
+ pixel = *dest32 ? 1 : 0;
+ break;
+ }
+
+ return pixel ? PIXEL_BLACK_MAC : PIXEL_WHITE_MAC;
+}
+
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_mac = {
+ fbcon_mac_setup, fbcon_mac_bmove, fbcon_mac_clear, fbcon_mac_putc,
+ fbcon_mac_putcs, fbcon_mac_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_mac);
+EXPORT_SYMBOL(fbcon_mac_setup);
+EXPORT_SYMBOL(fbcon_mac_bmove);
+EXPORT_SYMBOL(fbcon_mac_clear);
+EXPORT_SYMBOL(fbcon_mac_putc);
+EXPORT_SYMBOL(fbcon_mac_putcs);
+EXPORT_SYMBOL(fbcon_mac_revc);
diff --git a/drivers/video/fbcon-mac.h b/drivers/video/fbcon-mac.h
new file mode 100644
index 000000000..7e807cce9
--- /dev/null
+++ b/drivers/video/fbcon-mac.h
@@ -0,0 +1,15 @@
+ /*
+ * Mac variable bpp packed pixels (mac)
+ */
+
+extern struct display_switch fbcon_mac;
+extern void fbcon_mac_setup(struct display *p);
+extern void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_mac_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_mac_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c
index 7ac001ab4..3484cef2a 100644
--- a/drivers/video/fbcon-mfb.c
+++ b/drivers/video/fbcon-mfb.c
@@ -13,65 +13,30 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
-
-
- /*
- * Prototypes
- */
-
-static int open_mfb(struct display *p);
-static void release_mfb(void);
-static void bmove_mfb(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_mfb(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_mfb(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_mfb(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_mfb(struct display *p, int xx, int yy);
-
-
- /*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_mfb = {
- open_mfb, release_mfb, bmove_mfb, clear_mfb, putc_mfb, putcs_mfb,
- rev_char_mfb
-};
+#include "fbcon-mfb.h"
/*
* Monochrome
*/
-static int open_mfb(struct display *p)
+void fbcon_mfb_setup(struct display *p)
{
- if (p->var.bits_per_pixel != 1)
- return -EINVAL;
-
if (p->line_length)
p->next_line = p->line_length;
else
p->next_line = p->var.xres_virtual>>3;
p->next_plane = 0;
- MOD_INC_USE_COUNT;
- return 0;
}
-static void release_mfb(void)
+void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_mfb(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- u_char *src, *dest;
+ u8 *src, *dest;
u_int rows;
if (sx == 0 && dx == 0 && width == p->next_line) {
@@ -97,10 +62,10 @@ static void bmove_mfb(struct display *p, int sy, int sx, int dy, int dx,
}
}
-static void clear_mfb(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
+void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
{
- u_char *dest;
+ u8 *dest;
u_int rows;
dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
@@ -118,12 +83,12 @@ static void clear_mfb(struct vc_data *conp, struct display *p, int sy, int sx,
mymemclear_small(dest, width);
}
-static void putc_mfb(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
+void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
{
- u_char *dest, *cdat;
+ u8 *dest, *cdat;
u_int rows, bold, revs, underl;
- u_char d;
+ u8 d;
c &= 0xff;
@@ -145,12 +110,12 @@ static void putc_mfb(struct vc_data *conp, struct display *p, int c, int yy,
}
}
-static void putcs_mfb(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
+void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
{
- u_char *dest, *dest0, *cdat;
+ u8 *dest, *dest0, *cdat;
u_int rows, bold, revs, underl;
- u_char c, d;
+ u8 c, d;
dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
bold = attr_bold(p,conp);
@@ -174,9 +139,9 @@ static void putcs_mfb(struct vc_data *conp, struct display *p, const char *s,
}
}
-static void rev_char_mfb(struct display *p, int xx, int yy)
+void fbcon_mfb_revc(struct display *p, int xx, int yy)
{
- u_char *dest;
+ u8 *dest;
u_int rows;
dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -185,18 +150,24 @@ static void rev_char_mfb(struct display *p, int xx, int yy)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_mfb(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_mfb, 0));
-}
+ /*
+ * `switch' for the low level operations
+ */
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_mfb);
-}
-#endif /* MODULE */
+struct display_switch fbcon_mfb = {
+ fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc,
+ fbcon_mfb_putcs, fbcon_mfb_revc
+};
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_mfb);
+EXPORT_SYMBOL(fbcon_mfb_setup);
+EXPORT_SYMBOL(fbcon_mfb_bmove);
+EXPORT_SYMBOL(fbcon_mfb_clear);
+EXPORT_SYMBOL(fbcon_mfb_putc);
+EXPORT_SYMBOL(fbcon_mfb_putcs);
+EXPORT_SYMBOL(fbcon_mfb_revc);
diff --git a/drivers/video/fbcon-mfb.h b/drivers/video/fbcon-mfb.h
new file mode 100644
index 000000000..b67d9f70e
--- /dev/null
+++ b/drivers/video/fbcon-mfb.h
@@ -0,0 +1,15 @@
+ /*
+ * Monochrome (mfb)
+ */
+
+extern struct display_switch fbcon_mfb;
+extern void fbcon_mfb_setup(struct display *p);
+extern void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+extern void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_mfb_putcs(struct vc_data *conp, struct display *p,
+ const char *s, int count, int yy, int xx);
+extern void fbcon_mfb_revc(struct display *p, int xx, int yy);
diff --git a/drivers/video/fbcon-retz3.c b/drivers/video/fbcon-retz3.c
deleted file mode 100644
index 71095a084..000000000
--- a/drivers/video/fbcon-retz3.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * linux/drivers/video/retz3.c -- Low level frame buffer operations for the
- * RetinaZ3 (accelerated)
- *
- * Created 5 Apr 1997 by Geert Uytterhoeven
- *
- * 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/module.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-
-#include "fbcon.h"
-
-
-/*
- * Prototypes
- */
-
-static int open_retz3(struct display *p);
-static void release_retz3(void);
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_retz3(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width);
-static void putc_retz3(struct vc_data *conp, struct display *p, int c,
- int ypos, int xpos);
-static void putcs_retz3(struct vc_data *conp, struct display *p, const
- char *s, int count, int ypos, int xpos);
-static void rev_char_retz3(struct display *p, int xpos, int ypos);
-
-
- /*
- * Acceleration functions in retz3fb.c
- */
-
-extern void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-
-#define Z3BLTcopy 0xc0
-#define Z3BLTset 0xf0
-
-
-/*
- * `switch' for the low level operations
- */
-
-static struct display_switch dispsw_retz3 = {
- open_retz3, release_retz3, bmove_retz3, clear_retz3, putc_retz3,
- putcs_retz3, rev_char_retz3
-};
-
-
-/*
- * RetinaZ3 (accelerated)
- */
-
-static int open_retz3(struct display *p)
-{
- if (p->type != FB_TYPE_PACKED_PIXELS ||
- p->var.accel != FB_ACCEL_RETINAZ3)
- return -EINVAL;
-
- p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
- p->next_plane = 0;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static void release_retz3(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- int fontwidth = p->fontwidth;
-
- sx *= fontwidth;
- dx *= fontwidth;
- width *= fontwidth;
-
- retz3_bitblt(&p->var,
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)dx,
- (unsigned short)(dy*p->fontheight),
- (unsigned short)width,
- (unsigned short)(height*p->fontheight),
- Z3BLTcopy,
- 0xffff);
-}
-
-static void clear_retz3(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width)
-{
- unsigned short col;
- int fontwidth = p->fontwidth;
-
- sx *= fontwidth;
- width *= fontwidth;
-
- col = attr_bgcol_ec(p, conp);
- col &= 0xff;
- col |= (col << 8);
-
- retz3_bitblt(&p->var,
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)width,
- (unsigned short)(height*p->fontheight),
- Z3BLTset,
- col);
-}
-
-static void putc_retz3(struct vc_data *conp, struct display *p,
- int c, int ypos, int xpos)
-{
- unsigned char *dest, *cdat;
- unsigned long tmp;
- unsigned int rows, revs, underl;
- unsigned char d;
- unsigned char fg, bg;
-
- c &= 0xff;
-
- dest = p->screen_base + ypos * p->fontheight * p->next_line +
- xpos*p->fontwidth;
- cdat = p->fontdata + c * p->fontheight;
-
- fg = p->fgcol;
- bg = p->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((unsigned long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((unsigned long*) dest + 1) = tmp;
- }
-}
-
-static void putcs_retz3(struct vc_data *conp, struct display *p,
- const char *s, int count, int ypos, int xpos)
-{
- unsigned char *dest, *dest0, *cdat;
- unsigned long tmp;
- unsigned int rows, revs, underl;
- unsigned char c, d;
- unsigned char fg, bg;
-
- dest0 = p->screen_base + ypos * p->fontheight * p->next_line
- + xpos * p->fontwidth;
-
- fg = p->fgcol;
- bg = p->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- while (count--) {
- c = *s++;
- dest = dest0;
- dest0 += 8;
-
- cdat = p->fontdata + c * p->fontheight;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((unsigned long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((unsigned long*) dest + 1) = tmp;
- }
- }
-}
-
-static void rev_char_retz3(struct display *p, int xpos, int ypos)
-{
- unsigned char *dest;
- int bytes=p->next_line, rows;
- unsigned int bpp, mask;
-
- bpp = p->var.bits_per_pixel;
-
- switch (bpp){
- case 8:
- mask = 0x0f0f0f0f;
- break;
- case 16:
- mask = 0xffffffff;
- break;
- case 24:
- mask = 0xffffffff; /* ??? */
- break;
- default:
- printk("illegal depth for rev_char_retz3(), bpp = %i\n", bpp);
- return;
- }
-
- dest = p->screen_base + ypos * p->fontheight * bytes +
- xpos * p->fontwidth;
-
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((unsigned long *)dest)[0] ^= mask;
- ((unsigned long *)dest)[1] ^= mask;
- }
-}
-
-
-#ifdef MODULE
-int init_module(void)
-#else
-int fbcon_init_retz3(void)
-#endif
-{
- return(fbcon_register_driver(&dispsw_retz3, 1));
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- fbcon_unregister_driver(&dispsw_retz3);
-}
-#endif /* MODULE */
diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c
index 872d77928..a41bf081d 100644
--- a/drivers/video/fbcon.c
+++ b/drivers/video/fbcon.c
@@ -28,26 +28,17 @@
* The low level operations for the various display memory organizations are
* now in separate source files.
*
- * Currently only the following organizations are supported:
+ * Currently the following organizations are supported:
*
- * - non-accelerated:
- *
- * o mfb Monochrome
- * o ilbm Interleaved bitplanes ŕ la Amiga
- * o afb Bitplanes ŕ la Amiga
- * o iplan2p[248] Interleaved bitplanes ŕ la Atari (2, 4 and 8 planes)
- * o cfb{8,16} Packed pixels (8 and 16 bpp)
- *
- * - accelerated:
- *
- * o cyber CyberVision64 packed pixels (accelerated)
- * o retz3 Retina Z3 packed pixels (accelerated)
- * o mach64 ATI Mach 64 packed pixels (accelerated)
+ * o afb Amiga bitplanes
+ * o cfb{2,4,8,16,24,32} Packed pixels
+ * o ilbm Amiga interleaved bitplanes
+ * o iplan2p[248] Atari interleaved bitplanes
+ * o mfb Monochrome
*
* To do:
*
* - Implement 16 plane mode (iplan2p16)
- * - Add support for 24/32 bit packed pixels (cfb{24,32})
* - Hardware cursor
*
*
@@ -56,6 +47,8 @@
* more details.
*/
+#undef FBCONDEBUG
+
#define SUPPORT_SCROLLBACK 0
#define FLASHING_CURSOR 1
@@ -65,6 +58,7 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
+#include <linux/delay.h> /* MSch: for IRQ probe */
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
@@ -74,9 +68,6 @@
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/init.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
#include <asm/irq.h>
#include <asm/system.h>
@@ -88,6 +79,9 @@
#ifdef CONFIG_ATARI
#include <asm/atariints.h>
#endif
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
#ifdef __mc68000__
#include <asm/machdep.h>
#include <asm/setup.h>
@@ -95,8 +89,14 @@
#include <asm/linux_logo.h>
#include "fbcon.h"
+#include "fbcon-mac.h" /* for 6x11 font on mac */
#include "font.h"
+#ifdef FBCONDEBUG
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+# define DPRINTK(fmt, args...)
+#endif
struct display fb_display[MAX_NR_CONSOLES];
@@ -112,6 +112,7 @@ static int cursor_drawn = 0;
/* # VBL ints between cursor state changes */
#define AMIGA_CURSOR_BLINK_RATE (20)
#define ATARI_CURSOR_BLINK_RATE (42)
+#define MAC_CURSOR_BLINK_RATE (32)
#define DEFAULT_CURSOR_BLINK_RATE (20)
static int vbl_cursor_cnt = 0;
@@ -146,26 +147,25 @@ static __inline__ int CURSOR_UNDRAWN(void)
static unsigned long fbcon_startup(unsigned long kmem_start,
const char **display_desc);
static void fbcon_init(struct vc_data *conp);
-static int fbcon_deinit(struct vc_data *conp);
+static void fbcon_deinit(struct vc_data *conp);
static int fbcon_changevar(int con);
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
+static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
int width);
-static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count,
- int ypos, int xpos);
-static int fbcon_cursor(struct vc_data *conp, int mode);
-static int fbcon_scroll(struct vc_data *conp, int t, int b,
- int dir, int count);
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width);
+static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
+static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
+ int ypos, int xpos);
+static void fbcon_cursor(struct vc_data *conp, int mode);
+static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count);
+static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+ int height, int width);
static int fbcon_switch(struct vc_data *conp);
static int fbcon_blank(int blank);
static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
static int fbcon_scrolldelta(int lines);
-int fbcon_register_driver(struct display_switch *dispsw, int is_accel);
-int fbcon_unregister_driver(struct display_switch *dispsw);
+static int fbcon_set_mode(struct vc_data *conp, int mode);
/*
@@ -193,16 +193,23 @@ static __inline__ void ypan_down(int unit, struct vc_data *conp,
struct display *p, int count);
static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
int height, int width, u_int y_break);
-static struct display_switch *probe_list(struct display_switch *dispsw,
- struct display *disp);
-#ifdef CONFIG_KMOD
-static void request_driver(struct display *disp, int is_accel);
-#endif
-static struct display_switch *fbcon_get_driver(struct display *disp);
static int fbcon_show_logo(void);
#if FLASHING_CURSOR
+
+#ifdef CONFIG_MAC
+/*
+ * On the Macintoy, there may or may not be a working VBL int. We need to prob
+ */
+static int vbl_detected = 0;
+
+static void fbcon_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
+{
+ vbl_detected++;
+}
+#endif
+
static void cursor_timer_handler(unsigned long dev_addr);
static struct timer_list cursor_timer = {
@@ -212,7 +219,7 @@ static struct timer_list cursor_timer = {
static void cursor_timer_handler(unsigned long dev_addr)
{
fbcon_vbl_handler(0, NULL, NULL);
- cursor_timer.expires = jiffies+2;
+ cursor_timer.expires = jiffies+HZ/50;
cursor_timer.data = 0;
cursor_timer.next = cursor_timer.next = NULL;
add_timer(&cursor_timer);
@@ -223,49 +230,8 @@ static void cursor_timer_handler(unsigned long dev_addr)
* Low Level Operations
*/
-static struct display_switch dispsw_dummy;
+static struct display_switch fbcon_dummy;
-#ifdef CONFIG_FBCON_MFB
-extern int fbcon_init_mfb(void);
-#endif
-#ifdef CONFIG_FBCON_ILBM
-extern int fbcon_init_ilbm(void);
-#endif
-#ifdef CONFIG_FBCON_AFB
-extern int fbcon_init_afb(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P2
-extern int fbcon_init_iplan2p2(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P4
-extern int fbcon_init_iplan2p4(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P8
-extern int fbcon_init_iplan2p8(void);
-#endif
-#ifdef CONFIG_FBCON_CFB8
-extern int fbcon_init_cfb8(void);
-#endif
-#ifdef CONFIG_FBCON_CFB16
-extern int fbcon_init_cfb16(void);
-#endif
-#ifdef CONFIG_FBCON_CFB24
-extern int fbcon_init_cfb24(void);
-#endif
-#ifdef CONFIG_FBCON_CFB32
-extern int fbcon_init_cfb32(void);
-#endif
-#ifdef CONFIG_FBCON_CYBER
-extern int fbcon_init_cyber(void);
-#endif
-#ifdef CONFIG_FBCON_RETINAZ3
-extern int fbcon_init_retz3(void);
-#endif
-#ifdef CONFIG_FBCON_MACH64
-extern int fbcon_init_mach64(void);
-#endif
-
-extern int num_registered_fb;
__initfunc(static unsigned long fbcon_startup(unsigned long kmem_start,
const char **display_desc))
@@ -275,49 +241,10 @@ __initfunc(static unsigned long fbcon_startup(unsigned long kmem_start,
/* Probe all frame buffer devices */
kmem_start = probe_framebuffers(kmem_start);
- if (!num_registered_fb)
+ if (!num_registered_fb) {
+ DPRINTK("no framebuffer registered\n");
return kmem_start;
-
- /* Initialize all built-in low level drivers */
-#ifdef CONFIG_FBCON_RETINAZ3
- fbcon_init_retz3();
-#endif
-#ifdef CONFIG_FBCON_MFB
- fbcon_init_mfb();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P2
- fbcon_init_iplan2p2();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P4
- fbcon_init_iplan2p4();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P8
- fbcon_init_iplan2p8();
-#endif
-#ifdef CONFIG_FBCON_ILBM
- fbcon_init_ilbm();
-#endif
-#ifdef CONFIG_FBCON_AFB
- fbcon_init_afb();
-#endif
-#ifdef CONFIG_FBCON_CFB8
- fbcon_init_cfb8();
-#endif
-#ifdef CONFIG_FBCON_CFB16
- fbcon_init_cfb16();
-#endif
-#ifdef CONFIG_FBCON_CFB24
- fbcon_init_cfb24();
-#endif
-#ifdef CONFIG_FBCON_CFB32
- fbcon_init_cfb32();
-#endif
-#ifdef CONFIG_FBCON_CYBER
- fbcon_init_cyber();
-#endif
-#ifdef CONFIG_FBCON_MACH64
- fbcon_init_mach64();
-#endif
+ }
*display_desc = "frame buffer device";
@@ -335,9 +262,49 @@ __initfunc(static unsigned long fbcon_startup(unsigned long kmem_start,
"console/cursor", fbcon_vbl_handler);
}
#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_MAC
+ /*
+ * On a Macintoy, the VBL interrupt may or may not be active.
+ * As interrupt based cursor is more reliable and race free, we
+ * probe for VBL interrupts.
+ */
+ if (MACH_IS_MAC) {
+ int ct = 0;
+ /*
+ * Probe for VBL: set temp. handler ...
+ */
+ irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0,
+ "console/cursor", fbcon_vbl_detect);
+ /*
+ * ... and spin for 20 ms ...
+ */
+ while (!vbl_detected && ++ct<1000)
+ udelay(20);
+
+ if(ct==1000)
+ printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
+
+ if (vbl_detected) {
+ /*
+ * interrupt based cursor ok
+ */
+ cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
+ irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0,
+ "console/cursor", fbcon_vbl_handler);
+ } else {
+ /*
+ * VBL not detected: fall through, use timer based cursor
+ */
+ irqres = 1;
+ /* free interrupt here ?? */
+ }
+ }
+#endif /* CONFIG_MAC */
+
if (irqres) {
cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
- cursor_timer.expires = jiffies+2;
+ cursor_timer.expires = jiffies+HZ/50;
cursor_timer.data = 0;
cursor_timer.next = cursor_timer.prev = NULL;
add_timer(&cursor_timer);
@@ -360,22 +327,24 @@ static void fbcon_init(struct vc_data *conp)
info->changevar = &fbcon_changevar;
fb_display[unit] = *(info->disp); /* copy from default */
+ DPRINTK("mode: %s\n",info->modename);
+ DPRINTK("visual: %d\n",fb_display[unit].visual);
+ DPRINTK("res: %dx%d-%d\n",fb_display[unit].var.xres,
+ fb_display[unit].var.yres,
+ fb_display[unit].var.bits_per_pixel);
fb_display[unit].conp = conp;
fb_display[unit].fb_info = info;
fbcon_setup(unit, 1, 1);
}
-static int fbcon_deinit(struct vc_data *conp)
+static void fbcon_deinit(struct vc_data *conp)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
- if (p->dispsw)
- p->dispsw->release();
- p->dispsw = 0;
+ p->dispsw = NULL;
p->conp = 0;
- return(0);
}
@@ -405,7 +374,6 @@ static void fbcon_setup(int con, int setcol, int init)
struct display *p = &fb_display[con];
struct vc_data *conp = p->conp;
int nr_rows, nr_cols;
- struct display_switch *old_dispsw, *new_dispsw;
p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
@@ -415,9 +383,17 @@ static void fbcon_setup(int con, int setcol, int init)
getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
&p->fontheight, &p->fontdata);
if (p->fontwidth != 8) {
- /* ++Geert: changed from panic() to `correct and continue' */
- printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8");
- p->fontwidth = 8;
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC)
+ /* ++Geert: hack to make 6x11 fonts work on mac */
+ p->dispsw = &fbcon_mac;
+ else
+#endif
+ {
+ /* ++Geert: changed from panic() to `correct and continue' */
+ printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8");
+ p->dispsw = &fbcon_dummy;
+ }
}
updatescrollmode(p);
@@ -435,18 +411,12 @@ static void fbcon_setup(int con, int setcol, int init)
p->vrows = p->var.yres_virtual/p->fontheight;
conp->vc_can_do_color = p->var.bits_per_pixel != 1;
- new_dispsw = fbcon_get_driver(p);
- if (!new_dispsw) {
+ if (!p->dispsw) {
printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
"supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
- dispsw_dummy.open(p);
- new_dispsw = &dispsw_dummy;
+ p->dispsw = &fbcon_dummy;
}
- /* Be careful when changing dispsw, it might be the current console. */
- old_dispsw = p->dispsw;
- p->dispsw = new_dispsw;
- if (old_dispsw)
- old_dispsw->release();
+ p->dispsw->setup(p);
if (setcol) {
p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
@@ -492,15 +462,18 @@ static __inline__ int real_y(struct display *p, int ypos)
}
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width)
+static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
+ int width)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
u_int y_break;
if (!p->can_soft_blank && console_blanked)
- return(0);
+ return;
+
+ if (!height || !width)
+ return;
if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
(sx <= p->cursor_x) && (p->cursor_x < sx+width))
@@ -515,47 +488,41 @@ static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
} else
p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
-
- return(0);
}
-static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
if (!p->can_soft_blank && console_blanked)
- return 0;
+ return;
if ((p->cursor_x == xpos) && (p->cursor_y == ypos))
CURSOR_UNDRAWN();
p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos);
-
- return 0;
}
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count,
+static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
int ypos, int xpos)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
if (!p->can_soft_blank && console_blanked)
- return 0;
+ return;
if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
(p->cursor_x < (xpos + count)))
CURSOR_UNDRAWN();
p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
-
- return(0);
}
-static int fbcon_cursor(struct vc_data *conp, int mode)
+static void fbcon_cursor(struct vc_data *conp, int mode)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
@@ -563,9 +530,9 @@ static int fbcon_cursor(struct vc_data *conp, int mode)
/* Avoid flickering if there's no real change. */
if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y &&
(mode == CM_ERASE) == !cursor_on)
- return 0;
+ return;
if (CURSOR_UNDRAWN ())
- p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
+ p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
p->cursor_x = conp->vc_x;
p->cursor_y = conp->vc_y;
@@ -580,8 +547,6 @@ static int fbcon_cursor(struct vc_data *conp, int mode)
cursor_on = 1;
break;
}
-
- return(0);
}
@@ -598,7 +563,7 @@ static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
* switching code should set vbl_cursor_cnt to an appropriate value.
*/
p = &fb_display[fg_console];
- p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
+ p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
cursor_drawn ^= 1;
vbl_cursor_cnt = cursor_blink_rate;
}
@@ -623,7 +588,7 @@ static __inline__ void ywrap_up(int unit, struct display *p, int count)
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode |= FB_VMODE_YWRAP;
- p->fb_info->updatevar(unit);
+ p->fb_info->updatevar(unit, p->fb_info);
#if SUPPORT_SCROLLBACK
scrollback_max += count;
if (scrollback_max > p->vrows-conp->vc_rows)
@@ -646,7 +611,7 @@ static __inline__ void ywrap_down(int unit, struct display *p, int count)
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode |= FB_VMODE_YWRAP;
- p->fb_info->updatevar(unit);
+ p->fb_info->updatevar(unit, p->fb_info);
#if SUPPORT_SCROLLBACK
scrollback_max -= count;
if (scrollback_max < 0)
@@ -668,7 +633,7 @@ static __inline__ void ypan_up(int unit, struct vc_data *conp,
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode &= ~FB_VMODE_YWRAP;
- p->fb_info->updatevar(unit);
+ p->fb_info->updatevar(unit, p->fb_info);
}
@@ -684,17 +649,21 @@ static __inline__ void ypan_down(int unit, struct vc_data *conp,
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode &= ~FB_VMODE_YWRAP;
- p->fb_info->updatevar(unit);
+ p->fb_info->updatevar(unit, p->fb_info);
}
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
if (!p->can_soft_blank && console_blanked)
- return(0);
+ return;
+
+ if (!count)
+ return;
fbcon_cursor(conp, CM_ERASE);
@@ -822,19 +791,20 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
fbcon_clear(conp, 0, t, conp->vc_rows, count);
break;
}
-
- return(0);
}
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width)
+static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+ int height, int width)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
if (!p->can_soft_blank && console_blanked)
- return(0);
+ return;
+
+ if (!width || !height)
+ return;
if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
@@ -850,8 +820,6 @@ static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
* over again, so we use fbcon_bmove_rec()
*/
fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
-
- return(0);
}
@@ -894,7 +862,7 @@ static int fbcon_switch(struct vc_data *conp)
struct fb_info *info = p->fb_info;
if (info && info->switch_con)
- (*info->switch_con)(conp->vc_num);
+ (*info->switch_con)(conp->vc_num, info);
#if SUPPORT_SCROLLBACK
scrollback_max = 0;
scrollback_current = 0;
@@ -906,11 +874,19 @@ static int fbcon_switch(struct vc_data *conp)
static int fbcon_blank(int blank)
{
struct display *p = &fb_display[fg_console];
+ struct fb_info *info = p->fb_info;
fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
if (!p->can_soft_blank) {
if (blank) {
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC)
+ mymemset(p->screen_base,
+ p->var.xres_virtual*p->var.yres_virtual*
+ p->var.bits_per_pixel>>3);
+ else
+#endif
if (p->visual == FB_VISUAL_MONO01)
mymemset(p->screen_base,
p->var.xres_virtual*p->var.yres_virtual*
@@ -925,7 +901,7 @@ static int fbcon_blank(int blank)
return(1);
}
}
- (*p->fb_info->blank)(blank);
+ (*info->blank)(blank, info);
return(0);
}
@@ -975,7 +951,7 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
copy_from_user( name, data, MAX_FONT_NAME );
name[sizeof(name)-1] = 0;
- if (!findsoftfont( name, &w, &h, (u_char **)&data ))
+ if (!findsoftfont( name, &w, &h, (u8 **)&data ))
return( -ENOENT );
userspace = 0;
} else if (w == 1) {
@@ -1049,9 +1025,9 @@ activate:
return( 0 );
}
-static unsigned short palette_red[16];
-static unsigned short palette_green[16];
-static unsigned short palette_blue[16];
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
static struct fb_cmap palette_cmap = {
0, 16, palette_red, palette_green, palette_blue, NULL
@@ -1062,7 +1038,7 @@ static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
int i, j, k;
- u_char val;
+ u8 val;
if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
return(-EINVAL);
@@ -1078,7 +1054,7 @@ static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
palette_cmap.len = 1<<p->var.bits_per_pixel;
if (palette_cmap.len > 16)
palette_cmap.len = 16;
- return(p->fb_info->setcmap(&palette_cmap, unit));
+ return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);
}
static int fbcon_scrolldelta(int lines)
@@ -1109,13 +1085,27 @@ static int fbcon_scrolldelta(int lines)
p->var.vmode |= FB_VMODE_YWRAP;
p->var.xoffset = 0;
p->var.yoffset = offset*p->fontheight;
- p->fb_info->updatevar(unit);
+ p->fb_info->updatevar(unit, p->fb_info);
#else
return -ENOSYS;
#endif
}
+ /*
+ * Switch between `text' (emulated and accelerated) and `graphics'
+ * (unaccelerated text) mode
+ */
+
+static int fbcon_set_mode(struct vc_data *conp, int mode)
+{
+ struct display *p = &fb_display[conp->vc_num];
+ struct fb_ops *ops = p->fb_info->fbops;
+
+ return ops->fb_set_mode ? ops->fb_set_mode(mode, p->fb_info) : 0;
+}
+
+
#define LOGO_H 80
#define LOGO_W 80
#define LOGO_LINE (LOGO_W/8)
@@ -1166,7 +1156,8 @@ __initfunc(static int fbcon_show_logo( void ))
palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
}
- p->fb_info->setcmap( &palette_cmap, fg_console );
+ p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
+ p->fb_info);
}
fb_display[fg_console].cmap.len = old_cmap_len;
}
@@ -1184,12 +1175,65 @@ __initfunc(static int fbcon_show_logo( void ))
logo_depth = 1;
}
-#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CYBER) || \
- defined(CONFIG_FBCON_RETINAZ3)
- if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR ||
- p->visual == FB_VISUAL_DIRECTCOLOR)) {
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
+ defined(CONFIG_FBCON_CFB32)
+ if (p->visual == FB_VISUAL_TRUECOLOR) {
+ unsigned int val; /* max. depth 32! */
+ int bdepth;
+ int redshift, greenshift, blueshift;
+
+ /* Bug: Doesn't obey msb_right ... (who needs that?) */
+ redshift = p->var.red.offset;
+ greenshift = p->var.green.offset;
+ blueshift = p->var.blue.offset;
+
+ if (depth >= 24 && (depth % 8) == 0) {
+ /* have at least 8 bits per color */
+ src = logo;
+ bdepth = depth/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line;
+ for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+ val = ((linux_logo_red[*src] & redmask) << redshift) |
+ ((linux_logo_green[*src] & greenmask) << greenshift) |
+ ((linux_logo_blue[*src] & bluemask) << blueshift);
+ for( i = bdepth-1; i >= 0; --i )
+ *dst++ = val >> (i*8);
+ }
+ }
+ }
+ else if (depth >= 15 && depth <= 23) {
+ /* have 5..7 bits per color, using 16 color image */
+ unsigned int pix;
+ src = linux_logo16;
+ bdepth = (depth+7)/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line;
+ for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
+ pix = (*src >> 4) | 0x10; /* upper nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
+ for( i = 0; i < bdepth; ++i )
+ *dst++ = val >> (i*8);
+ pix = (*src & 0x0f) | 0x10; /* lower nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
+ for( i = bdepth-1; i >= 0; --i )
+ *dst++ = val >> (i*8);
+ }
+ }
+ }
+
+ done = 1;
+ }
+#endif
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
+ defined(CONFIG_FBCON_CFB32)
+ if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
/* Modes without color mapping, needs special data transformation... */
- unsigned long val; /* max. depth 32! */
+ unsigned int val; /* max. depth 32! */
int bdepth = depth/8;
unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
unsigned char redmask, greenmask, bluemask;
@@ -1218,8 +1262,7 @@ __initfunc(static int fbcon_show_logo( void ))
done = 1;
}
#endif
-#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CYBER) || \
- defined(CONFIG_FBCON_RETINAZ3)
+#if defined(CONFIG_FBCON_CFB8)
if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
/* depth 8 or more, packed, with color registers */
@@ -1316,153 +1359,23 @@ struct consw fb_con = {
fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette,
- fbcon_scrolldelta
+ fbcon_scrolldelta, fbcon_set_mode
};
/*
- * Driver registration
- */
-
-static struct display_switch *drivers = NULL, *accel_drivers = NULL;
-
-int fbcon_register_driver(struct display_switch *dispsw, int is_accel)
-{
- struct display_switch **list;
-
- list = is_accel ? &accel_drivers : &drivers;
- dispsw->next = *list;
- *list = dispsw;
- return 0;
-}
-
-int fbcon_unregister_driver(struct display_switch *dispsw)
-{
- struct display_switch **list;
-
- for (list = &accel_drivers; *list; list = &(*list)->next)
- if (*list == dispsw) {
- *list = dispsw->next;
- dispsw->next = NULL;
- return 0;
- }
- for (list = &drivers; *list; list = &(*list)->next)
- if (*list == dispsw) {
- *list = dispsw->next;
- dispsw->next = NULL;
- return 0;
- }
- return -EINVAL;
-}
-
-
-static struct display_switch *probe_list(struct display_switch *dispsw,
- struct display *disp)
-{
- while (dispsw) {
- if (!dispsw->open(disp))
- return(dispsw);
- dispsw = dispsw->next;
- }
- return(NULL);
-}
-
-
-#ifdef CONFIG_KMOD
-static void request_driver(struct display *disp, int is_accel)
-{
- char modname[30];
- int len;
- const char *type;
-
- if (disp->var.bits_per_pixel == 1)
- type = "mfb";
- else
- switch (disp->type) {
- case FB_TYPE_INTERLEAVED_PLANES:
- if (disp->type_aux == 2)
- type = "iplan2p%d";
- else
- type = "ilbm";
- break;
- case FB_TYPE_PLANES:
- type = "afb";
- break;
- case FB_TYPE_PACKED_PIXELS:
- type = "cfb%d";
- break;
- default:
- return;
- }
- len = sprintf(modname, "fbcon-");
- len += sprintf(modname+len, type, disp->var.bits_per_pixel);
- if (is_accel)
- len += sprintf(modname+len, "-%d", disp->var.accel);
- request_module(modname);
-}
-#endif /* CONFIG_KMOD */
-
-
-static struct display_switch *fbcon_get_driver(struct display *disp)
-{
- struct display_switch *dispsw;
-
- if (disp->var.accel != FB_ACCEL_NONE) {
- /* First try an accelerated driver */
- dispsw = probe_list(accel_drivers, disp);
-#ifdef CONFIG_KMOD
- if (!dispsw) {
- request_driver(disp, 1);
- dispsw = probe_list(accel_drivers, disp);
- }
-#endif
- if (dispsw)
- return(dispsw);
- }
-
- /* Then try an unaccelerated driver */
- dispsw = probe_list(drivers, disp);
-#ifdef CONFIG_KMOD
- if (!dispsw) {
- request_driver(disp, 0);
- dispsw = probe_list(drivers, disp);
- }
-#endif
- return(dispsw);
-}
-
-
-/*
* Dummy Low Level Operations
*/
-static int open_dummy(struct display *p)
-{
- if (p->line_length)
- p->next_line = p->line_length;
- else
- p->next_line = p->var.xres_virtual>>3;
- p->next_plane = 0;
- p->var.bits_per_pixel = 1;
- return 0;
-}
+static void fbcon_dummy_op(void) {}
-static void misc_dummy(void) {}
-
-static struct display_switch dispsw_dummy = {
- open_dummy,
- /* release_dummy */
- misc_dummy,
- /* bmove_dummy */
- (void (*)(struct display *, int, int, int, int, int, int))misc_dummy,
- /* clear_dummy */
- (void (*)(struct vc_data *, struct display *, int, int, int, int))misc_dummy,
- /* putc_dummy */
- (void (*)(struct vc_data *, struct display *, int, int, int))misc_dummy,
- /* putcs_dummy */
- (void (*)(struct vc_data *, struct display *, const char *, int, int, int))misc_dummy,
- /* rev_char_dummy */
- (void (*)(struct display *, int, int))misc_dummy,
+static struct display_switch fbcon_dummy = {
+ (void *)fbcon_dummy_op, /* fbcon_dummy_setup */
+ (void *)fbcon_dummy_op, /* fbcon_dummy_bmove */
+ (void *)fbcon_dummy_op, /* fbcon_dummy_clear */
+ (void *)fbcon_dummy_op, /* fbcon_dummy_putc */
+ (void *)fbcon_dummy_op, /* fbcon_dummy_putcs */
+ (void *)fbcon_dummy_op, /* fbcon_dummy_revc */
};
@@ -1471,5 +1384,3 @@ static struct display_switch dispsw_dummy = {
*/
EXPORT_SYMBOL(fb_display);
-EXPORT_SYMBOL(fbcon_register_driver);
-EXPORT_SYMBOL(fbcon_unregister_driver);
diff --git a/drivers/video/fbcon.h b/drivers/video/fbcon.h
index b83376d9e..4868b7730 100644
--- a/drivers/video/fbcon.h
+++ b/drivers/video/fbcon.h
@@ -8,6 +8,9 @@
* for more details.
*/
+#ifndef __VIDEO_FBCON_H
+#define __VIDEO_FBCON_H
+
#include <linux/console_struct.h>
@@ -16,8 +19,7 @@
*/
struct display_switch {
- int (*open)(struct display *p);
- void (*release)(void);
+ void (*setup)(struct display *p);
void (*bmove)(struct display *p, int sy, int sx, int dy, int dx,
int height, int width);
void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx,
@@ -26,20 +28,11 @@ struct display_switch {
int xx);
void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
int count, int yy, int xx);
- void (*rev_char)(struct display *p, int xx, int yy);
- struct display_switch *next;
+ void (*revc)(struct display *p, int xx, int yy);
};
/*
- * Driver registration
- */
-
-extern int fbcon_register_driver(struct display_switch *dispsw, int is_accel);
-int fbcon_unregister_driver(struct display_switch *dispsw);
-
-
- /*
* Attribute Decoding
*/
@@ -335,3 +328,5 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
}
#endif /* !m68k */
+
+#endif /* __VIDEO_FBCON_H */
diff --git a/drivers/video/fbgen.c b/drivers/video/fbgen.c
new file mode 100644
index 000000000..730438d16
--- /dev/null
+++ b/drivers/video/fbgen.c
@@ -0,0 +1,386 @@
+/*
+ * linux/drivers/video/fbgen.c -- Generic routines for frame buffer devices
+ *
+ * Created 3 Jan 1998 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.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+
+#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 ----------- */
+
+
+ /*
+ * Get the Fixed Part of the Display
+ */
+
+int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ char par[info2->parsize];
+
+ if (con == -1)
+ fbhw->get_par(&par, info2);
+ else {
+ int err;
+
+ if ((err = fbhw->decode_var(&fb_display[con].var, &par, info2)))
+ return err;
+ }
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ return fbhw->encode_fix(fix, &par, info2);
+}
+
+
+ /*
+ * Get the User Defined Part of the Display
+ */
+
+int fbgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ char par[info2->parsize];
+
+ if (con == -1) {
+ fbhw->get_par(&par, info2);
+ fbhw->encode_var(var, &par, info2);
+ } else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+
+ /*
+ * Set the User Defined Part of the Display
+ */
+
+int fbgen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ int err;
+ int oldxres, oldyres, oldbpp, oldxres_virtual, oldyres_virtual, oldyoffset;
+
+ if ((err = fbgen_do_set_var(var, con == currcon, info2)))
+ return err;
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ oldxres = fb_display[con].var.xres;
+ oldyres = fb_display[con].var.yres;
+ oldxres_virtual = fb_display[con].var.xres_virtual;
+ oldyres_virtual = fb_display[con].var.yres_virtual;
+ oldbpp = fb_display[con].var.bits_per_pixel;
+ oldyoffset = fb_display[con].var.yoffset;
+ fb_display[con].var = *var;
+ if (oldxres != var->xres || oldyres != var->yres ||
+ oldxres_virtual != var->xres_virtual ||
+ oldyres_virtual != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel ||
+ oldyoffset != var->yoffset) {
+ fbgen_set_disp(con, info2);
+ if (info->changevar)
+ (*info->changevar)(con);
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+ return err;
+ fbgen_install_cmap(con, info2);
+ }
+ }
+ var->activate = 0;
+ return 0;
+}
+
+
+ /*
+ * Get the Colormap
+ */
+
+int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+
+ if (con == currcon) /* current console ? */
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, fbhw->getcolreg,
+ info);
+ 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);
+ return 0;
+}
+
+
+ /*
+ * Set the Colormap
+ */
+
+int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ 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)))
+ return err;
+ }
+ if (con == currcon) /* current console ? */
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, fbhw->setcolreg,
+ info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+
+ /*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+
+int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ int xoffset = var->xoffset;
+ int yoffset = var->yoffset;
+ int err;
+
+ if (xoffset < 0 ||
+ xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+ yoffset < 0 ||
+ yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ return -EINVAL;
+ if (con == currcon) {
+ if (fbhw->pan_display) {
+ if ((err = fbhw->pan_display(var, info2)))
+ return err;
+ } else
+ return -EINVAL;
+ }
+ fb_display[con].var.xoffset = var->xoffset;
+ fb_display[con].var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+ else
+ fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+
+ return 0;
+}
+
+
+ /*
+ * Frame Buffer Specific ioctls
+ */
+
+int fbgen_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+
+/* ---- Helper functions --------------------------------------------------- */
+
+
+ /*
+ * Change the video mode
+ */
+
+int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info_gen *info)
+{
+ struct fbgen_hwswitch *fbhw = info->fbhw;
+ int err, activate;
+ char par[info->parsize];
+
+ if ((err = fbhw->decode_var(var, &par, info)))
+ return err;
+ activate = var->activate;
+ if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
+ fbhw->set_par(&par, info);
+ fbhw->encode_var(var, &par, info);
+ var->activate = activate;
+ return 0;
+}
+
+
+void fbgen_set_disp(int con, struct fb_info_gen *info)
+{
+ struct fbgen_hwswitch *fbhw = info->fbhw;
+ struct fb_fix_screeninfo fix;
+ char par[info->parsize];
+ struct display *display;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ if (con == -1)
+ fbhw->get_par(&par, info);
+ else
+ fbhw->decode_var(&fb_display[con].var, &par, info);
+ memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
+ fbhw->encode_fix(&fix, &par, info);
+
+ display->screen_base = fix.smem_start;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ if (info->fbhw->blank || fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+ fix.visual == FB_VISUAL_DIRECTCOLOR)
+ display->can_soft_blank = 1;
+ else
+ display->can_soft_blank = 0;
+ display->dispsw = fbhw->get_dispsw(&par, info);
+#if 0 /* FIXME: generic inverse is not supported yet */
+ display->inverse = (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+#else
+ display->inverse = fix.visual == FB_VISUAL_MONO01;
+#endif
+}
+
+
+ /*
+ * Install the current colormap
+ */
+
+void fbgen_install_cmap(int con, struct fb_info_gen *info)
+{
+ struct fbgen_hwswitch *fbhw = info->fbhw;
+ if (con != currcon)
+ return;
+ 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);
+}
+
+
+ /*
+ * Update the `var' structure (called by fbcon.c)
+ */
+
+int fbgen_update_var(int con, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ int err;
+
+ if (fbhw->pan_display) {
+ if ((err = fbhw->pan_display(&fb_display[con].var, info2)))
+ return err;
+ }
+ return 0;
+}
+
+
+ /*
+ * Switch to a different virtual console
+ */
+
+int fbgen_switch(int con, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+
+ /* 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,
+ fbhw->getcolreg, &info2->info);
+ fbgen_do_set_var(&fb_display[con].var, 1, info2);
+ currcon = con;
+ /* Install new colormap */
+ fbgen_install_cmap(con, info2);
+ return 0;
+}
+
+
+ /*
+ * Blank the screen
+ */
+
+void fbgen_blank(int blank, struct fb_info *info)
+{
+ struct fb_info_gen *info2 = (struct fb_info_gen *)info;
+ struct fbgen_hwswitch *fbhw = info2->fbhw;
+ u16 black[16];
+ struct fb_cmap cmap;
+
+ if (fbhw->blank && !fbhw->blank(blank, info2))
+ return;
+ if (blank) {
+ memset(black, 0, 16*sizeof(u16));
+ cmap.red = black;
+ cmap.green = black;
+ cmap.blue = black;
+ cmap.transp = NULL;
+ cmap.start = 0;
+ cmap.len = 16;
+ fb_set_cmap(&cmap, &fb_display[currcon].var, 1, fbhw->setcolreg, info);
+ } else
+ fbgen_install_cmap(currcon, info2);
+}
diff --git a/drivers/video/font_6x11.c b/drivers/video/font_6x11.c
new file mode 100644
index 000000000..ebfe24258
--- /dev/null
+++ b/drivers/video/font_6x11.c
@@ -0,0 +1,3345 @@
+/**********************************************/
+/* */
+/* Font file generated by rthelen */
+/* */
+/**********************************************/
+
+#define FONTDATAMAX (11*256)
+
+char fontname_6x11[] = "ProFont6x11";
+
+int fontheight_6x11 = 11;
+int fontwidth_6x11 = 6;
+
+unsigned char fontdata_6x11[FONTDATAMAX] = {
+
+ /* 0 0x00 '^A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 1 0x01 '^B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 2 0x02 '^C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 3 0x03 '^D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 4 0x04 '^E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 5 0x05 '^F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 6 0x06 '^G' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 7 0x07 '^H' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 8 0x08 '^I' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 9 0x09 '^J' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 10 0x0a '^K' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 11 0x0b '^L' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 12 0x0c '^M' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 13 0x0d '^N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 14 0x0e '^O' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 15 0x0f '^P' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 16 0x10 '^Q' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 17 0x11 '^R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 18 0x12 '^S' */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 19 0x13 '^T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x7c, /* 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 20 0x14 '^U' */
+ 0x18, /* 000 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x78, /* 0 000 */
+ 0x78, /* 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 21 0x15 '^V' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 22 0x16 '^W' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 23 0x17 '^X' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 24 0x18 '^Y' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 25 0x19 '^Z' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 26 0x1a '^[' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 27 0x1b '^\' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 28 0x1c '^]' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 29 0x1d '^^' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 30 0x1e '^_' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 31 0x1f '^`' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 34 0x22 '"' */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 36 0x24 '$' */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x38, /* 00 000 */
+ 0x14, /* 000 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x34, /* 00 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x54, /* 0 0 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 39 0x27 ''' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 40 0x28 '(' */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 41 0x29 ')' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 47 0x2f '/' */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x18, /* 000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x18, /* 000 000 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x18, /* 000 000 */
+ 0x28, /* 00 0 000 */
+ 0x48, /* 0 00 000 */
+ 0x7c, /* 0 00 */
+ 0x08, /* 0000 000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, /* 00000000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x74, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x60, /* 0 00000 */
+ 0x50, /* 0 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x6c, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x6c, /* 0 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 91 0x5b '[' */
+ 0x0c, /* 0000 00 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x0c, /* 0000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 92 0x5c '\' */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x02, /* 000000 0 */
+ 0x02, /* 000000 0 */
+ 0x00, /* 00000000 */
+
+ /* 93 0x5d ']' */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x30, /* 00 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 94 0x5e '^' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 96 0x60 '`' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 98 0x62 'b' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 100 0x64 'd' */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 102 0x66 'f' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 0000 00 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 104 0x68 'h' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 107 0x6b 'k' */
+ 0x00, /* 00000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x48, /* 0 00 000 */
+ 0x50, /* 0 0 0000 */
+ 0x70, /* 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 108 0x6c 'l' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x40, /* 0 000000 */
+ 0x38, /* 00 000 */
+ 0x04, /* 00000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 116 0x74 't' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x0c, /* 0000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 123 0x7b '{' */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+
+ /* 124 0x7c '|' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 125 0x7d '}' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, /* 00000000 */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 127 0x7f '^?' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 128 0x80 '\200' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 129 0x81 '\201' */
+ 0x28, /* 00 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 130 0x82 '\202' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 131 0x83 '\203' */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x78, /* 0 000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 132 0x84 '\204' */
+ 0x58, /* 0 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x4c, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 133 0x85 '\205' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 134 0x86 '\206' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 135 0x87 '\207' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 136 0x88 '\210' */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 137 0x89 '\211' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 138 0x8a '\212' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 139 0x8b '\213' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 140 0x8c '\214' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x3c, /* 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 141 0x8d '\215' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+
+ /* 142 0x8e '\216' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 143 0x8f '\217' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 144 0x90 '\220' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 145 0x91 '\221' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x40, /* 0 000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 146 0x92 '\222' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 147 0x93 '\223' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 148 0x94 '\224' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 149 0x95 '\225' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 150 0x96 '\226' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x58, /* 0 0 000 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 151 0x97 '\227' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 152 0x98 '\230' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 153 0x99 '\231' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 154 0x9a '\232' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 155 0x9b '\233' */
+ 0x34, /* 00 0 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 156 0x9c '\234' */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 157 0x9d '\235' */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 158 0x9e '\236' */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 159 0x9f '\237' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x34, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 160 0xa0 '\240' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 161 0xa1 '\241' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 162 0xa2 '\242' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x54, /* 0 0 0 00 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 163 0xa3 '\243' */
+ 0x30, /* 00 0000 */
+ 0x48, /* 0 00 000 */
+ 0x40, /* 0 000000 */
+ 0x70, /* 0 0000 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x78, /* 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 164 0xa4 '\244' */
+ 0x44, /* 0 000 00 */
+ 0x24, /* 00 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x14, /* 000 0 00 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 165 0xa5 '\245' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x7c, /* 0 00 */
+ 0x7c, /* 0 00 */
+ 0x7c, /* 0 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 166 0xa6 '\246' */
+ 0x3c, /* 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x3c, /* 00 00 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 167 0xa7 '\247' */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x58, /* 0 0 000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 168 0xa8 '\250' */
+ 0x00, /* 00000000 */
+ 0x70, /* 0 0000 */
+ 0x08, /* 0000 000 */
+ 0x64, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x58, /* 0 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 169 0xa9 '\251' */
+ 0x00, /* 00000000 */
+ 0x70, /* 0 0000 */
+ 0x08, /* 0000 000 */
+ 0x34, /* 00 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x34, /* 00 0 00 */
+ 0x08, /* 0000 000 */
+ 0x70, /* 0 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 170 0xaa '\252' */
+ 0x00, /* 00000000 */
+ 0x7a, /* 0 0 0 */
+ 0x2e, /* 00 0 0 */
+ 0x2e, /* 00 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 171 0xab '\253' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 172 0xac '\254' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 173 0xad '\255' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 174 0xae '\256' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x78, /* 0 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x5c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 175 0xaf '\257' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 176 0xb0 '\260' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 0 0 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x6c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 177 0xb1 '\261' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 178 0xb2 '\262' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 179 0xb3 '\263' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x04, /* 00000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 180 0xb4 '\264' */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x7c, /* 0 00 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 181 0xb5 '\265' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x74, /* 0 0 00 */
+ 0x40, /* 0 000000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+
+ /* 182 0xb6 '\266' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x0c, /* 0000 00 */
+ 0x14, /* 000 0 00 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 183 0xb7 '\267' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x24, /* 00 00 00 */
+ 0x10, /* 000 0000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x24, /* 00 00 00 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 184 0xb8 '\270' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 185 0xb9 '\271' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 186 0xba '\272' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 187 0xbb '\273' */
+ 0x00, /* 00000000 */
+ 0x1c, /* 000 00 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x1c, /* 000 00 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 188 0xbc '\274' */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 189 0xbd '\275' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x6c, /* 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 190 0xbe '\276' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x5c, /* 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 191 0xbf '\277' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x4c, /* 0 00 00 */
+ 0x54, /* 0 0 0 00 */
+ 0x64, /* 0 00 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 192 0xc0 '\300' */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x20, /* 00 00000 */
+ 0x40, /* 0 000000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 193 0xc1 '\301' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x08, /* 0000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 194 0xc2 '\302' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x04, /* 00000 00 */
+ 0x04, /* 00000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 195 0xc3 '\303' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 0000 00 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x20, /* 00 00000 */
+ 0x20, /* 00 00000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 196 0xc4 '\304' */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x60, /* 0 00000 */
+ 0x00, /* 00000000 */
+
+ /* 197 0xc5 '\305' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x40, /* 0 000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 198 0xc6 '\306' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 199 0xc7 '\307' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x24, /* 00 00 00 */
+ 0x48, /* 0 00 000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 200 0xc8 '\310' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x48, /* 0 00 000 */
+ 0x24, /* 00 00 00 */
+ 0x24, /* 00 00 00 */
+ 0x48, /* 0 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 201 0xc9 '\311' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x54, /* 0 0 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 202 0xca '\312' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 203 0xcb '\313' */
+ 0x10, /* 000 0000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 204 0xcc '\314' */
+ 0x58, /* 0 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x7c, /* 0 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 205 0xcd '\315' */
+ 0x58, /* 0 0 000 */
+ 0x38, /* 00 000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 206 0xce '\316' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x58, /* 0 0 000 */
+ 0x50, /* 0 0 0000 */
+ 0x50, /* 0 0 0000 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 207 0xcf '\317' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x54, /* 0 0 0 00 */
+ 0x5c, /* 0 0 00 */
+ 0x50, /* 0 0 0000 */
+ 0x2c, /* 00 0 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 208 0xd0 '\320' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 209 0xd1 '\321' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 210 0xd2 '\322' */
+ 0x00, /* 00000000 */
+ 0x14, /* 000 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 211 0xd3 '\323' */
+ 0x00, /* 00000000 */
+ 0x14, /* 000 0 00 */
+ 0x14, /* 000 0 00 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 212 0xd4 '\324' */
+ 0x00, /* 00000000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x18, /* 000 000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 213 0xd5 '\325' */
+ 0x00, /* 00000000 */
+ 0x18, /* 000 000 */
+ 0x08, /* 0000 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 214 0xd6 '\326' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 0 00 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 215 0xd7 '\327' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 000 0000 */
+ 0x28, /* 00 0 000 */
+ 0x44, /* 0 000 00 */
+ 0x28, /* 00 0 000 */
+ 0x10, /* 000 0000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 216 0xd8 '\330' */
+ 0x00, /* 00000000 */
+ 0x28, /* 00 0 000 */
+ 0x00, /* 00000000 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x44, /* 0 000 00 */
+ 0x3c, /* 00 00 */
+ 0x04, /* 00000 00 */
+ 0x38, /* 00 000 */
+ 0x00, /* 00000000 */
+
+ /* 217 0xd9 '\331' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 0 0 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 218 0xda '\332' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 219 0xdb '\333' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 220 0xdc '\334' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 221 0xdd '\335' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 222 0xde '\336' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 223 0xdf '\337' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 224 0xe0 '\340' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 225 0xe1 '\341' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 226 0xe2 '\342' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 227 0xe3 '\343' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 228 0xe4 '\344' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 229 0xe5 '\345' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 230 0xe6 '\346' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 231 0xe7 '\347' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 232 0xe8 '\350' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 233 0xe9 '\351' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 234 0xea '\352' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 235 0xeb '\353' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 236 0xec '\354' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 237 0xed '\355' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 238 0xee '\356' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 239 0xef '\357' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 240 0xf0 '\360' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 241 0xf1 '\361' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 242 0xf2 '\362' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 243 0xf3 '\363' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 244 0xf4 '\364' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 245 0xf5 '\365' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 246 0xf6 '\366' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 247 0xf7 '\367' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 248 0xf8 '\370' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 249 0xf9 '\371' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 250 0xfa '\372' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 251 0xfb '\373' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 252 0xfc '\374' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 253 0xfd '\375' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 254 0xfe '\376' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 255 0xff '\377' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x3c, /* 00 00 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+};
+
diff --git a/drivers/video/fonts.c b/drivers/video/fonts.c
index 8e89805bb..56a3a33b2 100644
--- a/drivers/video/fonts.c
+++ b/drivers/video/fonts.c
@@ -9,7 +9,7 @@
*/
-#include <linux/config.h> /* for CONFIG_AMIGA */
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#ifdef __mc68000__
@@ -25,17 +25,22 @@
/* VGA8x8 */
extern char fontname_8x8[];
extern int fontwidth_8x8, fontheight_8x8;
-extern u_char fontdata_8x8[];
+extern u8 fontdata_8x8[];
/* VGA8x16 */
extern char fontname_8x16[];
extern int fontwidth_8x16, fontheight_8x16;
-extern u_char fontdata_8x16[];
+extern u8 fontdata_8x16[];
/* PEARL8x8 */
extern char fontname_pearl8x8[];
extern int fontwidth_pearl8x8, fontheight_pearl8x8;
-extern u_char fontdata_pearl8x8[];
+extern u8 fontdata_pearl8x8[];
+
+/* VGA6x11 */
+extern char fontname_6x11[];
+extern int fontwidth_6x11, fontheight_6x11;
+extern u8 fontdata_6x11[];
/*
@@ -46,18 +51,20 @@ struct softfontdesc {
char *name;
int *width;
int *height;
- u_char *data;
+ u8 *data;
};
#define VGA8x8_IDX 0
#define VGA8x16_IDX 1
#define PEARL8x8_IDX 2
+#define VGA6x11_IDX 3
static struct softfontdesc softfonts[] = {
{ fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 },
{ fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 },
{ fontname_pearl8x8, &fontwidth_pearl8x8, &fontheight_pearl8x8,
fontdata_pearl8x8 },
+ { fontname_6x11, &fontwidth_6x11, &fontheight_6x11, fontdata_6x11 },
};
static unsigned int numsoftfonts = sizeof(softfonts)/sizeof(*softfonts);
@@ -67,7 +74,7 @@ static unsigned int numsoftfonts = sizeof(softfonts)/sizeof(*softfonts);
* Find a font with a specific name
*/
-int findsoftfont(char *name, int *width, int *height, u_char *data[])
+int findsoftfont(char *name, int *width, int *height, u8 *data[])
{
unsigned int i;
@@ -90,7 +97,7 @@ int findsoftfont(char *name, int *width, int *height, u_char *data[])
*/
void getdefaultfont(int xres, int yres, char *name[], int *width, int *height,
- u_char *data[])
+ u8 *data[])
{
int i;
@@ -103,6 +110,16 @@ void getdefaultfont(int xres, int yres, char *name[], int *width, int *height,
} else
i = VGA8x16_IDX;
+#if defined(CONFIG_MAC)
+ if (MACH_IS_MAC) {
+#if 0 /* MSch: removed until 6x11 is debugged */
+ i = VGA6x11_IDX; /* I added this for fun ... I like 6x11 */
+#endif
+ if (xres < 640)
+ i = VGA6x11_IDX;
+ }
+#endif
+
if (name)
*name = softfonts[i].name;
if (width)
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
new file mode 100644
index 000000000..43932a080
--- /dev/null
+++ b/drivers/video/macfb.c
@@ -0,0 +1,459 @@
+/*
+ * 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>
+#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/nubus.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/macintosh.h>
+#include <linux/fb.h>
+
+
+/* conditionalize these ?? */
+#include "fbcon-mfb.h"
+#include "fbcon-cfb2.h"
+#include "fbcon-cfb4.h"
+#include "fbcon-cfb8.h"
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+static struct fb_var_screeninfo macfb_defined={
+ 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/
+ 0,0, /* virtual -> visible no offset */
+ 8, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ 274,195, /* 14" monitor *Mikael Nykvist's anyway* */
+ FB_ACCEL_NONE, /* The only way to accelerate a mac is .. */
+ 0L,0L,0L,0L,0L,
+ 0L,0L,0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+#define NUM_TOTAL_MODES 1
+#define NUM_PREDEF_MODES 1
+
+static struct display disp;
+static struct fb_info fb_info;
+
+static int inverse = 0;
+
+struct macfb_par
+{
+ void *unused;
+};
+
+static int currcon = 0;
+static int current_par_valid = 0;
+struct macfb_par current_par;
+
+static int mac_xres,mac_yres,mac_depth, mac_xbytes, mac_vxres;
+static unsigned long mac_videobase;
+static unsigned long mac_videosize;
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int macfb_open(struct fb_info *info)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int macfb_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static void macfb_encode_var(struct fb_var_screeninfo *var,
+ struct macfb_par *par)
+{
+ int i=0;
+ var->xres=mac_xres;
+ var->yres=mac_yres;
+ var->xres_virtual=mac_vxres;
+ var->yres_virtual=var->yres;
+ var->xoffset=0;
+ var->yoffset=0;
+ var->bits_per_pixel = mac_depth;
+ var->grayscale=0;
+ var->transp.offset=0;
+ var->transp.length=0;
+ var->transp.msb_right=0;
+ var->nonstd=0;
+ var->activate=0;
+ var->height= -1;
+ var->width= -1;
+ var->accel=0;
+ var->vmode=FB_VMODE_NONINTERLACED;
+ var->pixclock=0;
+ var->sync=0;
+ var->left_margin=0;
+ var->right_margin=0;
+ var->upper_margin=0;
+ var->lower_margin=0;
+ var->hsync_len=0;
+ var->vsync_len=0;
+ for(i=0;i<arraysize(var->reserved);i++)
+ var->reserved[i]=0;
+ return;
+}
+
+
+static void macfb_get_par(struct macfb_par *par)
+{
+ *par=current_par;
+}
+
+static void macfb_set_par(struct macfb_par *par)
+{
+ current_par_valid=1;
+}
+
+static int fb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+ struct macfb_par par;
+
+ macfb_get_par(&par);
+ macfb_encode_var(var, &par);
+ return 0;
+}
+
+extern int console_loglevel;
+
+static void macfb_encode_fix(struct fb_fix_screeninfo *fix,
+ struct macfb_par *par)
+{
+ int i;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id,"Macintosh");
+
+ /*
+ * X works, but screen wraps ...
+ */
+ fix->smem_start=(char *)(mac_videobase&PAGE_MASK);
+ fix->smem_offset=(mac_videobase&~PAGE_MASK);
+ fix->smem_len=PAGE_ALIGN(mac_videosize);
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ fix->xpanstep=0;
+ fix->ypanstep=0;
+ fix->ywrapstep=0;
+ fix->line_length=mac_xbytes;
+ return;
+}
+
+static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct macfb_par par;
+ macfb_get_par(&par);
+ macfb_encode_fix(fix, &par);
+ return 0;
+}
+
+static int macfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct macfb_par par;
+ if(con==-1)
+ {
+ macfb_get_par(&par);
+ macfb_encode_var(var, &par);
+ }
+ else
+ *var=fb_display[con].var;
+ return 0;
+}
+
+static void macfb_set_disp(int con)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ macfb_get_fix(&fix, con, 0);
+
+ display->screen_base = (u_char *)(fix.smem_start+fix.smem_offset);
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 0;
+ display->inverse = inverse;
+
+ switch (mac_depth) {
+#ifdef CONFIG_FBCON_MFB
+ case 1:
+ display->dispsw = &fbcon_mfb;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB2
+ case 2:
+ display->dispsw = &fbcon_cfb2;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB4
+ case 4:
+ display->dispsw = &fbcon_cfb4;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_cfb8;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
+}
+
+static int macfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if ((err=do_fb_set_var(var, 1)))
+ return err;
+ return 0;
+}
+
+static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+#if 0
+ printk("macfb_get_cmap: not supported!\n");
+ /* interferes with X11 */
+ if (console_loglevel < 7)
+ return -EINVAL;
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, 0 /*offb_getcolreg*/, info);
+ 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(fb_display[con].var.bits_per_pixel),
+ cmap, kspc ? 0 : 2);
+#endif
+ return 0;
+
+}
+
+static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+#if 0
+ printk("macfb_set_cmap: not supported!\n");
+ if (console_loglevel < 7)
+ return -EINVAL;
+ 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)))
+ return err;
+ }
+ if (con == currcon) /* current console? */
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, 1 /*offb_setcolreg*/, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+#endif
+ return 0;
+}
+
+static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ /* no panning */
+ printk("macfb_pan: not supported!\n");
+ return -EINVAL;
+}
+
+static int macfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ printk("macfb_ioctl: not supported!\n");
+ return -EINVAL;
+}
+
+static struct fb_ops macfb_ops = {
+ macfb_open,
+ macfb_release,
+ macfb_get_fix,
+ macfb_get_var,
+ macfb_set_var,
+ macfb_get_cmap,
+ macfb_set_cmap,
+ macfb_pan_display,
+ NULL,
+ macfb_ioctl
+};
+
+void macfb_setup(char *options, int *ints)
+{
+ char *this_opt;
+ int temp;
+
+ fb_info.fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ if (! strcmp(this_opt, "inverse"))
+ inverse=1;
+ else if (!strncmp(this_opt, "font:", 5)) {
+ strcpy(fb_info.fontname, this_opt+5);
+ printk("macfb_setup: option %s\n", this_opt);
+ }
+ }
+}
+
+static int macfb_switch(int con, struct fb_info *info)
+{
+ do_fb_set_var(&fb_display[con].var,1);
+ currcon=con;
+ return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void macfb_blank(int blank, struct fb_info *info)
+{
+ /* Not supported */
+}
+
+/*
+ * Nubus call back. This will give us our board identity and also
+ * other useful info we need later
+ */
+
+static int nubus_video_card(struct nubus_device_specifier *ns, int slot, struct nubus_type *nt)
+{
+ if(nt->category==NUBUS_CAT_DISPLAY)
+ return 0;
+ /* Claim all video cards. We dont yet do driver specifics tho. */
+ return -ENODEV;
+}
+
+static struct nubus_device_specifier nb_video={
+ nubus_video_card,
+ NULL
+};
+
+__initfunc(unsigned long macfb_init(unsigned long mem_start))
+{
+ /* nubus_remap the video .. */
+ int err;
+
+ if (!MACH_IS_MAC)
+ return mem_start;
+
+ mac_xres=mac_bi_data.dimensions&0xFFFF;
+ mac_yres=(mac_bi_data.dimensions&0xFFFF0000)>>16;
+ mac_depth=mac_bi_data.videodepth;
+ mac_xbytes=mac_bi_data.videorow;
+ mac_vxres = (mac_xbytes/mac_depth)*8;
+ mac_videosize=mac_xbytes*mac_yres;
+ mac_videobase=mac_bi_data.videoaddr;
+
+ printk("macfb_init: xres %d yres %d bpp %d addr %x size %d \n",
+ mac_xres, mac_yres, mac_depth, mac_videobase, mac_videosize);
+
+ mac_debugging_penguin(4);
+
+ /*
+ * Fill in the available video resolution
+ */
+
+ macfb_defined.xres=mac_xres;
+ macfb_defined.yres=mac_yres;
+ macfb_defined.xres_virtual=mac_vxres;
+ macfb_defined.yres_virtual=mac_yres;
+ macfb_defined.bits_per_pixel=mac_depth;
+
+
+ /*
+ * Let there be consoles..
+ */
+ strcpy(fb_info.modename, "Macintosh Builtin ");
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &macfb_ops;
+ fb_info.disp=&disp;
+ fb_info.switch_con=&macfb_switch;
+ fb_info.updatevar=&fb_update_var;
+ fb_info.blank=&macfb_blank;
+ do_fb_set_var(&macfb_defined,1);
+
+ err=register_framebuffer(&fb_info);
+ if(err<0)
+ {
+ mac_boom(6);
+ return NULL;
+ }
+
+ macfb_get_var(&disp.var, -1, &fb_info);
+ macfb_set_disp(-1);
+
+ /*
+ * Register the nubus hook
+ */
+
+ register_nubus_device(&nb_video);
+
+ printk("fb%d: %s frame buffer device using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename, mac_videosize>>10);
+
+ return mem_start;
+}
+
+#if 0
+/*
+ * These two auxiliary debug functions should go away ASAP. Only usage:
+ * before the console output is up (after head.S come some other crucial
+ * setup routines :-)
+ *
+ * Now in debug.c ...
+ */
+#endif
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cc521899a..26ab95dfb 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -12,6 +12,7 @@
* more details.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -23,53 +24,83 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
+#include <linux/selection.h>
#include <linux/init.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <linux/vc_ioctl.h>
+#endif
#include <asm/io.h>
#include <asm/prom.h>
+#include "fbcon-cfb8.h"
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
static int currcon = 0;
-static struct display disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-static char offb_name[16] = "OFfb ";
-static volatile unsigned char *unknown_cmap_adr = NULL;
-static volatile unsigned char *unknown_cmap_data = NULL;
+struct fb_info_offb {
+ struct fb_info info;
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ struct display disp;
+ struct { u_char red, green, blue, pad; } palette[256];
+ volatile unsigned char *cmap_adr;
+ volatile unsigned char *cmap_data;
+};
+
+static struct fb_info_offb fb_info[FB_MAX];
+
+#ifdef __powerpc__
+#define mach_eieio() eieio()
+#else
+#define mach_eieio() do {} while (0)
+#endif
-static struct fb_fix_screeninfo fb_fix = { 0, };
-static struct fb_var_screeninfo fb_var = { 0, };
+static int ofonly = 0;
/*
* Interface used by the world
*/
-void offb_video_setup(char *options, int *ints);
-
-static int offb_open(int fbidx);
-static int offb_release(int fbidx);
-static int offb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int offb_get_var(struct fb_var_screeninfo *var, int con);
-static int offb_set_var(struct fb_var_screeninfo *var, int con);
-static int offb_pan_display(struct fb_var_screeninfo *var, int con);
-static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
+unsigned long offb_init(unsigned long mem_start);
+void offb_setup(char *options, int *ints);
+
+static int offb_open(struct fb_info *info);
+static int offb_release(struct fb_info *info);
+static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int offb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int offb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int offb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
+ u_long arg, int con, struct fb_info *info);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+int console_getmode(struct vc_mode *);
+int console_setmode(struct vc_mode *, int);
+int console_powermode(int);
+struct fb_info *console_fb_info = NULL;
+int (*console_setmode_ptr)(struct vc_mode *, int) = NULL;
+int (*console_set_cmap_ptr)(struct fb_cmap *, int, int, struct fb_info *)
+ = NULL;
+struct vc_mode display_info;
+#endif /* CONFIG_FB_COMPAT_XPMAC */
/*
* Interface to the low level console driver
*/
-unsigned long offb_init(unsigned long mem_start);
-static int offbcon_switch(int con);
-static int offbcon_updatevar(int con);
-static void offbcon_blank(int blank);
-static int offbcon_setcmap(struct fb_cmap *cmap, int con);
+static int offbcon_switch(int con, struct fb_info *info);
+static int offbcon_updatevar(int con, struct fb_info *info);
+static void offbcon_blank(int blank, struct fb_info *info);
/*
@@ -77,15 +108,15 @@ static int offbcon_setcmap(struct fb_cmap *cmap, int con);
*/
static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
-static void do_install_cmap(int con);
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
static struct fb_ops offb_ops = {
offb_open, offb_release, offb_get_fix, offb_get_var, offb_set_var,
- offb_get_cmap, offb_set_cmap, offb_pan_display, offb_ioctl
+ offb_get_cmap, offb_set_cmap, offb_pan_display, NULL, offb_ioctl
};
@@ -93,20 +124,20 @@ static struct fb_ops offb_ops = {
* Open/Release the frame buffer device
*/
-static int offb_open(int fbidx)
+static int offb_open(struct fb_info *info)
{
- /*
- * Nothing, only a usage count for the moment
- */
+ /*
+ * Nothing, only a usage count for the moment
+ */
MOD_INC_USE_COUNT;
- return(0);
+ return(0);
}
-
-static int offb_release(int fbidx)
+
+static int offb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
- return(0);
+ return(0);
}
@@ -114,9 +145,12 @@ static int offb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int offb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
- memcpy(fix, &fb_fix, sizeof(fb_fix));
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
+
+ memcpy(fix, &info2->fix, sizeof(struct fb_fix_screeninfo));
return 0;
}
@@ -125,9 +159,12 @@ static int offb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int offb_get_var(struct fb_var_screeninfo *var, int con)
+static int offb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
- memcpy(var, &fb_var, sizeof(fb_var));
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
+
+ memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
return 0;
}
@@ -136,33 +173,36 @@ static int offb_get_var(struct fb_var_screeninfo *var, int con)
* Set the User Defined Part of the Display
*/
-static int offb_set_var(struct fb_var_screeninfo *var, int con)
+static int offb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
struct display *display;
int oldbpp = -1, err;
+ int activate = var->activate;
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
if (con >= 0)
display = &fb_display[con];
else
- display = &disp; /* used during initialization */
+ display = &info2->disp; /* used during initialization */
- if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
- var->xres_virtual > fb_var.xres_virtual ||
- var->yres_virtual > fb_var.yres_virtual ||
- var->bits_per_pixel > fb_var.bits_per_pixel ||
+ if (var->xres > info2->var.xres || var->yres > info2->var.yres ||
+ var->xres_virtual > info2->var.xres_virtual ||
+ var->yres_virtual > info2->var.yres_virtual ||
+ var->bits_per_pixel > info2->var.bits_per_pixel ||
var->nonstd ||
(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
return -EINVAL;
- memcpy(var, &fb_var, sizeof(fb_var));
+ memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldbpp = display->var.bits_per_pixel;
display->var = *var;
}
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
return 0;
}
@@ -174,7 +214,8 @@ static int offb_set_var(struct fb_var_screeninfo *var, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int offb_pan_display(struct fb_var_screeninfo *var, int con)
+static int offb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
if (var->xoffset || var->yoffset)
return -EINVAL;
@@ -186,14 +227,16 @@ static int offb_pan_display(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int offb_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, offb_getcolreg);
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, offb_getcolreg,
+ info);
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
@@ -202,11 +245,13 @@ static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
int err;
- if (!unknown_cmap_adr)
+ if (!info2->cmap_adr)
return -ENOSYS;
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
@@ -215,7 +260,8 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
return err;
}
if (con == currcon) /* current console? */
- return fb_set_cmap(cmap, &fb_display[con].var, kspc, offb_setcolreg);
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, offb_setcolreg,
+ info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
@@ -223,12 +269,24 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con)
+ u_long arg, int con, struct fb_info *info)
{
return -EINVAL;
}
+#ifdef CONFIG_FB_ATY
+extern unsigned long atyfb_of_init(unsigned long mem_start,
+ struct device_node *dp);
+
+static const char *aty_names[] = {
+ "ATY,mach64", "ATY,XCLAIM", "ATY,264VT", "ATY,mach64ii", "ATY,264GT-B",
+ "ATY,mach64_3D_pcc", "ATY,XCLAIM3D", "ATY,XCLAIMVR", "ATY,RAGEII_M",
+ "ATY,XCLAIMVRPro", "ATY,mach64_3DU"
+};
+#endif /* CONFIG_FB_ATY */
+
+
/*
* Initialisation
*/
@@ -236,128 +294,196 @@ static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
__initfunc(unsigned long offb_init(unsigned long mem_start))
{
struct device_node *dp;
- int i, err, *pp, len;
+ int dpy, i, err, *pp, len;
unsigned *up, address;
+ struct fb_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ struct display *disp;
+ struct fb_info_offb *info;
+
+ for (dpy = 0; dpy < prom_num_displays; dpy++) {
+ if (!(dp = find_path_device(prom_display_paths[dpy])))
+ continue;
+
+ info = &fb_info[dpy];
+ fix = &info->fix;
+ var = &info->var;
+ disp = &info->disp;
+
+ if (!ofonly) {
+#ifdef CONFIG_FB_ATY
+ for (i = 0; i < sizeof(aty_names)/sizeof(*aty_names); i++)
+ if (!strcmp(dp->name, aty_names[i]))
+ break;
+ if (i < sizeof(aty_names)/sizeof(*aty_names)) {
+ mem_start = atyfb_of_init(mem_start, dp);
+ continue;
+ }
+#endif /* CONFIG_FB_ATY */
+ }
- if (!prom_display_path[0])
- return mem_start;
- if (!(dp = find_path_device(prom_display_path)))
- return mem_start;
-
- strncat(offb_name, dp->name, sizeof(offb_name));
- offb_name[sizeof(offb_name)-1] = '\0';
- strcpy(fb_fix.id, offb_name);
+ strcpy(fix->id, "OFfb ");
+ strncat(fix->id, dp->name, sizeof(fix->id));
+ fix->id[sizeof(fix->id)-1] = '\0';
- if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
- && len == sizeof(int) && *pp != 8) {
- printk("%s: can't use depth = %d\n", dp->full_name, *pp);
- return mem_start;
- }
- if ((pp = (int *)get_property(dp, "width", &len)) != NULL
- && len == sizeof(int))
- fb_var.xres = fb_var.xres_virtual = *pp;
- if ((pp = (int *)get_property(dp, "height", &len)) != NULL
- && len == sizeof(int))
- fb_var.yres = fb_var.yres_virtual = *pp;
- if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
- && len == sizeof(int))
- fb_fix.line_length = *pp;
- else
- fb_fix.line_length = fb_var.xres_virtual;
- fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
- if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
- && len == sizeof(unsigned))
- address = (u_long)*up;
- else {
- for (i = 0; i < dp->n_addrs; ++i)
- if (dp->addrs[i].size >= len)
- break;
- if (i >= dp->n_addrs) {
- printk("no framebuffer address found for %s\n", dp->full_name);
- return mem_start;
+ if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+ && len == sizeof(int) && *pp != 8) {
+ printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+ continue;
+ }
+ if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+ && len == sizeof(int))
+ var->xres = var->xres_virtual = *pp;
+ if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+ && len == sizeof(int))
+ var->yres = var->yres_virtual = *pp;
+ if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+ && len == sizeof(int))
+ fix->line_length = *pp;
+ else
+ fix->line_length = var->xres_virtual;
+ fix->smem_len = fix->line_length*var->yres;
+ if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
+ && len == sizeof(unsigned))
+ address = (u_long)*up;
+ else {
+ for (i = 0; i < dp->n_addrs; ++i)
+ if (dp->addrs[i].size >= len)
+ break;
+ if (i >= dp->n_addrs) {
+ printk("no framebuffer address found for %s\n", dp->full_name);
+ continue;
+ }
+ address = (u_long)dp->addrs[i].address;
+ }
+ fix->smem_start = ioremap(address, fix->smem_len);
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+
+ /* XXX kludge for ati */
+ if (strncmp(dp->name, "ATY,", 4) == 0) {
+ info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
+ info->cmap_data = info->cmap_adr + 1;
}
- address = (u_long)dp->addrs[i].address;
- }
- fb_fix.smem_start = ioremap(address, fb_fix.smem_len);
- fb_fix.type = FB_TYPE_PACKED_PIXELS;
- fb_fix.type_aux = 0;
-
- /* XXX kludge for ati */
- if (strncmp(dp->name, "ATY,", 4) == 0) {
- unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
- unknown_cmap_data = unknown_cmap_adr + 1;
- }
- fb_fix.visual = unknown_cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
+ fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
FB_VISUAL_STATIC_PSEUDOCOLOR;
- fb_var.xoffset = fb_var.yoffset = 0;
- fb_var.bits_per_pixel = 8;
- fb_var.grayscale = 0;
- fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
- fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
- fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
- fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
- fb_var.nonstd = 0;
- fb_var.activate = 0;
- fb_var.height = fb_var.width = -1;
- fb_var.accel = FB_ACCEL_NONE;
- fb_var.pixclock = 10000;
- fb_var.left_margin = fb_var.right_margin = 16;
- fb_var.upper_margin = fb_var.lower_margin = 16;
- fb_var.hsync_len = fb_var.vsync_len = 8;
- fb_var.sync = 0;
- fb_var.vmode = FB_VMODE_NONINTERLACED;
-
- disp.var = fb_var;
- disp.cmap.start = 0;
- disp.cmap.len = 0;
- disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
- disp.screen_base = fb_fix.smem_start;
- disp.visual = fb_fix.visual;
- disp.type = fb_fix.type;
- disp.type_aux = fb_fix.type_aux;
- disp.ypanstep = 0;
- disp.ywrapstep = 0;
- disp.line_length = fb_fix.line_length;
- disp.can_soft_blank = 1;
- disp.inverse = 0;
-
- strcpy(fb_info.modename, "OFfb ");
- strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
- fb_info.node = -1;
- fb_info.fbops = &offb_ops;
- fb_info.fbvar_num = 1;
- fb_info.fbvar = &fb_var;
- fb_info.disp = &disp;
- fb_info.fontname[0] = '\0';
- fb_info.changevar = NULL;
- fb_info.switch_con = &offbcon_switch;
- fb_info.updatevar = &offbcon_updatevar;
- fb_info.blank = &offbcon_blank;
- fb_info.setcmap = &offbcon_setcmap;
-
- err = register_framebuffer(&fb_info);
- if (err < 0)
- return mem_start;
-
- offb_set_var(&fb_var, -1);
-
- printk("Open Firmware frame buffer device on %s\n", dp->full_name);
+ var->xoffset = var->yoffset = 0;
+ var->bits_per_pixel = 8;
+ var->grayscale = 0;
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 8;
+ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+ var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->height = var->width = -1;
+ var->accel = FB_ACCEL_NONE;
+ var->pixclock = 10000;
+ var->left_margin = var->right_margin = 16;
+ var->upper_margin = var->lower_margin = 16;
+ var->hsync_len = var->vsync_len = 8;
+ var->sync = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ disp->var = *var;
+ disp->cmap.start = 0;
+ disp->cmap.len = 0;
+ disp->cmap.red = disp->cmap.green = disp->cmap.blue = disp->cmap.transp = NULL;
+ disp->screen_base = fix->smem_start;
+ disp->visual = fix->visual;
+ disp->type = fix->type;
+ disp->type_aux = fix->type_aux;
+ disp->ypanstep = 0;
+ disp->ywrapstep = 0;
+ disp->line_length = fix->line_length;
+ disp->can_soft_blank = info->cmap_adr ? 1 : 0;
+ disp->inverse = 0;
+#ifdef CONFIG_FBCON_CFB8
+ disp->dispsw = &fbcon_cfb8;
+#else
+ disp->dispsw = NULL;
+#endif
+
+ strcpy(info->info.modename, "OFfb ");
+ strncat(info->info.modename, dp->full_name,
+ sizeof(info->info.modename));
+ info->info.node = -1;
+ info->info.fbops = &offb_ops;
+ info->info.disp = disp;
+ info->info.fontname[0] = '\0';
+ info->info.changevar = NULL;
+ info->info.switch_con = &offbcon_switch;
+ info->info.updatevar = &offbcon_updatevar;
+ info->info.blank = &offbcon_blank;
+
+ err = register_framebuffer(&info->info);
+ if (err < 0)
+ continue;
+
+ for (i = 0; i < 16; i++) {
+ int j = color_table[i];
+ info->palette[i].red = default_red[j];
+ info->palette[i].green = default_grn[j];
+ info->palette[i].blue = default_blu[j];
+ }
+ offb_set_var(var, -1, &info->info);
+
+ printk("fb%d: Open Firmware frame buffer device on %s\n",
+ GET_FB_IDX(info->info.node), dp->full_name);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info) {
+ display_info.height = var->yres;
+ display_info.width = var->xres;
+ display_info.depth = 8;
+ display_info.pitch = fix->line_length;
+ display_info.mode = 0;
+ strncpy(display_info.name, dp->name, sizeof(display_info.name));
+ display_info.fb_address = iopa((unsigned long)fix->smem_start);
+ display_info.cmap_adr_address = 0;
+ display_info.cmap_data_address = 0;
+ display_info.disp_reg_address = 0;
+ /* XXX kludge for ati */
+ if (strncmp(dp->name, "ATY,", 4) == 0) {
+ display_info.disp_reg_address = iopa(address + 0x7ffc00);
+ display_info.cmap_adr_address = iopa(address + 0x7ffcc0);
+ display_info.cmap_data_address = iopa(address + 0x7ffcc1);
+ }
+ console_fb_info = &info->info;
+ console_set_cmap_ptr = offb_set_cmap;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
+ }
return mem_start;
}
-static int offbcon_switch(int con)
+ /*
+ * Setup: parse used options
+ */
+
+void offb_setup(char *options, int *ints)
+{
+ if (!options || !*options)
+ return;
+
+ if (!strcmp(options, "ofonly"))
+ ofonly = 1;
+}
+
+
+static int offbcon_switch(int con, struct fb_info *info)
{
/* 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,
- offb_getcolreg);
+ offb_getcolreg, info);
currcon = con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -365,7 +491,7 @@ static int offbcon_switch(int con)
* Update the `var' structure (called by fbcon.c)
*/
-static int offbcon_updatevar(int con)
+static int offbcon_updatevar(int con, struct fb_info *info)
{
/* Nothing */
return 0;
@@ -375,34 +501,42 @@ static int offbcon_updatevar(int con)
* Blank the display.
*/
-static void offbcon_blank(int blank)
+static void offbcon_blank(int blank, struct fb_info *info)
{
- /* Nothing */
-}
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
+ int i, j;
- /*
- * Set the colormap
- */
+ if (!info2->cmap_adr)
+ return;
-static int offbcon_setcmap(struct fb_cmap *cmap, int con)
-{
- return(offb_set_cmap(cmap, 1, con));
+ if (blank)
+ for (i = 0; i < 256; i++) {
+ *info2->cmap_adr = i;
+ mach_eieio();
+ for (j = 0; j < 3; j++) {
+ *info2->cmap_data = 0;
+ mach_eieio();
+ }
+ }
+ else
+ do_install_cmap(currcon, info);
}
-
/*
* Read a single color register and split it into
* colors/transparent. Return != 0 for invalid regno.
*/
static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
+ u_int *transp, struct fb_info *info)
{
- if (!unknown_cmap_adr || regno > 255)
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
+
+ if (!info2->cmap_adr || regno > 255)
return 1;
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
+ *red = info2->palette[regno].red;
+ *green = info2->palette[regno].green;
+ *blue = info2->palette[regno].blue;
return 0;
}
@@ -414,41 +548,113 @@ static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
*/
static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
+ u_int transp, struct fb_info *info)
{
- if (!unknown_cmap_adr || regno > 255)
+ struct fb_info_offb *info2 = (struct fb_info_offb *)info;
+
+ if (!info2->cmap_adr || regno > 255)
return 1;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
- *unknown_cmap_adr = regno;
-#ifdef __powerpc__
- eieio();
-#endif
- *unknown_cmap_data = red;
-#ifdef __powerpc__
- eieio();
-#endif
- *unknown_cmap_data = green;
-#ifdef __powerpc__
- eieio();
-#endif
- *unknown_cmap_data = blue;
-#ifdef __powerpc__
- eieio();
-#endif
+ info2->palette[regno].red = red;
+ info2->palette[regno].green = green;
+ info2->palette[regno].blue = blue;
+ *info2->cmap_adr = regno;
+ mach_eieio();
+ *info2->cmap_data = red;
+ mach_eieio();
+ *info2->cmap_data = green;
+ mach_eieio();
+ *info2->cmap_data = blue;
+ mach_eieio();
return 0;
}
-static void do_install_cmap(int con)
+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,
- offb_setcolreg);
+ offb_setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, offb_setcolreg);
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, offb_setcolreg,
+ info);
}
+
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+
+ /*
+ * Backward compatibility mode for Xpmac
+ *
+ * To do:
+ *
+ * - console_setmode() should fill in a struct fb_var_screeninfo (using
+ * the MacOS video mode database) and simply call a decode_var()
+ * function, so console_setmode_ptr is no longer needed.
+ *
+ * - instead of using the console_* stuff (filled in by the frame
+ * buffer), we should use the correct struct fb_info for the
+ * foreground virtual console.
+ */
+
+int console_getmode(struct vc_mode *mode)
+{
+ *mode = display_info;
+ return 0;
+}
+
+int console_setmode(struct vc_mode *mode, int doit)
+{
+ int err;
+
+ if (console_setmode_ptr == NULL)
+ return -EINVAL;
+
+ err = (*console_setmode_ptr)(mode, doit);
+ return err;
+}
+
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
+
+static struct fb_cmap palette_cmap = {
+ 0, 16, palette_red, palette_green, palette_blue, NULL
+};
+
+int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
+ unsigned char *blue)
+{
+ int i, j, n;
+
+ if (console_set_cmap_ptr == NULL)
+ return -EOPNOTSUPP;
+ for (i = 0; i < n_entries; i += n) {
+ n = n_entries-i;
+ if (n > 16)
+ n = 16;
+ palette_cmap.start = i;
+ palette_cmap.len = n;
+ for (j = 0; j < n; j++) {
+ palette_cmap.red[j] = (red[i+j] << 8) | red[i+j];
+ palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
+ palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
+ }
+ (*console_set_cmap_ptr)(&palette_cmap, 1, fg_console, console_fb_info);
+ }
+ return 0;
+}
+
+int console_powermode(int mode)
+{
+ if (mode == VC_POWERMODE_INQUIRY)
+ return 0;
+ if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+ return -EINVAL;
+ /* Not supported */
+ return -ENXIO;
+}
+
+#endif /* CONFIG_FB_COMPAT_XPMAC */
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index 18a410614..82dcc2877 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -21,6 +21,7 @@
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -39,6 +40,10 @@
#include <asm/pgtable.h>
#include "retz3fb.h"
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+
/* #define DEBUG if(1) */
#define DEBUG if(0)
@@ -54,7 +59,7 @@
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-struct retz3_fb_par {
+struct retz3fb_par {
int xres;
int yres;
int xres_vir;
@@ -93,7 +98,7 @@ struct display_data {
long v_dispend; /* Horizontal Display End */
};
-static struct retz3_fb_par current_par;
+static struct retz3fb_par current_par;
static int current_par_valid = 0;
static int currcon = 0;
@@ -114,13 +119,15 @@ static struct fb_hwswitch {
/* Display Control */
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
+ int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3fb_par *par);
+ int (*decode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
+ int (*encode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par);
int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
- int *green, unsigned int *blue, unsigned int *transp);
+ int *green, unsigned int *blue, unsigned int *transp,
+ struct fb_info *info);
int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
- green, unsigned int blue, unsigned int transp);
+ green, unsigned int blue, unsigned int transp,
+ struct fb_info *info);
void (*blank)(int blank);
} *fbhw;
@@ -129,7 +136,7 @@ static struct fb_hwswitch {
* Frame Buffer Name
*/
-static char retz3_fb_name[16] = "RetinaZ3";
+static char retz3fb_name[16] = "RetinaZ3";
static unsigned char retz3_color_table [256][4];
@@ -140,46 +147,6 @@ static volatile unsigned char *z3_regs;
/*
- * Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "640x480", /* RetinaZ3 8 bpp */
- "800x600", /* RetinaZ3 8 bpp */
- "1024x768i",
- "640x480-16", /* RetinaZ3 16 bpp */
- "640x480-24", /* RetinaZ3 24 bpp */
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3",
- "user4", "user5", "user6", "user7"
-};
-
-/*
* A small info on how to convert XFree86 timing values into fb
* timings - by Frank Neumann:
*
@@ -217,131 +184,124 @@ under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
*/
/*
- * Predefined Video Mode Definitions
+ * Predefined Video Modes
*/
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- /*
- * NB: it is very important to adjust the pixel-clock to the color-depth.
- */
-
- {
- 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_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 800 x 600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 1024 x 768, 8 bpp, interlaced */
- 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_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 24, 0,
- {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
-
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+static struct fb_videomode retz3fb_predefined[] __initdata = {
+ /*
+ * NB: it is very important to adjust the pixel-clock to the color-depth.
+ */
+
+ {
+ "640x480", { /* 640x480, 8 bpp */
+ 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_NCR77C32BLT, 38461, 28, 32, 12, 10, 96, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ },
+ /*
+ ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
+ < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
+ */
+ {
+ "800x600", { /* 800x600, 8 bpp */
+ 800, 600, 800, 600, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NCR77C32BLT, 27778, 64, 24, 22, 1, 120, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ },
+ /*
+ ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
+ < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
+ */
+ {
+ "1024x768i", { /* 1024x768, 8 bpp, interlaced */
+ 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_NCR77C32BLT, 22222, 40, 40, 32, 9, 160, 8,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
+ }
+ }, {
+ "640x480-16", { /* 640x480, 16 bpp */
+ 640, 480, 640, 480, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NCR77C32BLT, 38461/2, 28, 32, 12, 10, 96, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "640x480-24", { /* 640x480, 24 bpp */
+ 640, 480, 640, 480, 0, 0, 24, 0,
+ {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NCR77C32BLT, 38461/3, 28, 32, 12, 10, 96, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ },
};
-#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES 5
+#define NUM_TOTAL_MODES arraysize(retz3fb_predefined)
+static struct fb_var_screeninfo retz3fb_default;
static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
+static int z3fb_mode __initdata = 0;
/*
* Interface used by the world
*/
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_open(int fbidx);
-static int retz3_fb_release(int fbidx);
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con);
+void retz3fb_setup(char *options, int *ints);
+
+static int retz3fb_open(struct fb_info *info);
+static int retz3fb_release(struct fb_info *info);
+static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int retz3fb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
/*
* Interface to the low level console driver
*/
-unsigned long retz3_fb_init(unsigned long mem_start);
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
+unsigned long retz3fb_init(unsigned long mem_start);
+static int z3fb_switch(int con, struct fb_info *info);
+static int z3fb_updatevar(int con, struct fb_info *info);
+static void z3fb_blank(int blank, struct fb_info *info);
+
+
+/*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static struct display_switch fbcon_retz3_8;
+#endif
/*
* Accelerated Functions used by the low level console driver
*/
-void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short curx, unsigned short cury, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
- width, unsigned short height, unsigned short mode,
- unsigned short color);
+static void retz3_bitblt(struct fb_var_screeninfo *scr,
+ unsigned short curx, unsigned short cury, unsigned
+ short destx, unsigned short desty, unsigned short
+ width, unsigned short height, unsigned short cmd,
+ unsigned short mask);
/*
* Hardware Specific Routines
@@ -349,17 +309,17 @@ void retz3_fill(unsigned short x, unsigned short y, unsigned short
static int retz3_init(void);
static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par);
+ struct retz3fb_par *par);
static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
+ struct retz3fb_par *par);
static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
+ struct retz3fb_par *par);
static int retz3_getcolreg(unsigned int regno, unsigned int *red,
unsigned int *green, unsigned int *blue,
- unsigned int *transp);
+ unsigned int *transp, struct fb_info *info);
static int retz3_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
- unsigned int transp);
+ unsigned int transp, struct fb_info *info);
static void retz3_blank(int blank);
@@ -367,13 +327,11 @@ static void retz3_blank(int blank);
* Internal routines
*/
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
+static void retz3fb_get_par(struct retz3fb_par *par);
+static void retz3fb_set_par(struct retz3fb_par *par);
static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static void do_install_cmap(int con);
-/*
-static void retz3_fb_set_disp(int con);
-*/
+static void do_install_cmap(int con, struct fb_info *info);
+static void retz3fb_set_disp(int con, struct fb_info *info);
static int get_video_mode(const char *name);
@@ -397,7 +355,7 @@ static unsigned short find_fq(unsigned int freq)
else if (freq <= 250000000)
n2 = 0;
else
- return(0);
+ return 0;
do {
@@ -424,10 +382,12 @@ static unsigned short find_fq(unsigned int freq)
static int retz3_set_video(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
+ struct retz3fb_par *par)
{
+#if 0
float freq_f;
- long freq;
+#endif
+ unsigned int freq;
int xres, hfront, hsync, hback;
int yres, vfront, vsync, vback;
@@ -478,7 +438,7 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
vback = var->upper_margin;
}
- data.h_total = (hback / 8) + (xres / 8)
+ data.h_total = (hback / 8) + (xres / 8)
+ (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
data.h_bstart = xres / 8 /* + 1 */;
@@ -736,8 +696,13 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
/*
* Convert from ps to Hz.
*/
+#if 0
freq_f = (1.0/(float)var->pixclock) * 1000000000;
- freq = ((long)freq_f) * 1000;
+ freq = ((unsigned int)freq_f) * 1000;
+#else
+ freq = 2000000000 / var->pixclock;
+ freq = freq * 500;
+#endif
best_freq = find_fq(freq);
pll_w(0x02, best_freq);
@@ -791,7 +756,7 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
*/
switch (bpp){
case 8:
- reg_w(0x83c6, 0x00);
+ reg_w(0x83c6, 0x00);
break;
case 16:
reg_w(0x83c6, 0x60);
@@ -805,7 +770,7 @@ static int retz3_set_video(struct fb_var_screeninfo *var,
reg_w(VDAC_ADDRESS, 0x00);
- seq_w(SEQ_MAP_MASK, 0x0f );
+ seq_w(SEQ_MAP_MASK, 0x0f );
return 0;
}
@@ -854,8 +819,8 @@ static int retz3_init(void)
}
#endif
- retz3_setcolreg (255, 56, 100, 160, 0);
- retz3_setcolreg (254, 0, 0, 0, 0);
+ retz3_setcolreg (255, 56, 100, 160, 0, NULL /* unused */);
+ retz3_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
return 0;
}
@@ -867,11 +832,11 @@ static int retz3_init(void)
*/
static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par)
+ struct retz3fb_par *par)
{
short i;
- strcpy(fix->id, retz3_fb_name);
+ strcpy(fix->id, retz3fb_name);
fix->smem_start = (char *)z3_fbmem;
fix->smem_len = z3_size;
fix->mmio_start = (unsigned char *)z3_regs;
@@ -889,6 +854,8 @@ static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
fix->ywrapstep = 0;
fix->line_length = 0;
+ fix->accel = FB_ACCEL_NCR77C32BLT;
+
for (i = 0; i < arraysize(fix->reserved); i++)
fix->reserved[i] = 0;
@@ -902,7 +869,7 @@ static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
*/
static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
+ struct retz3fb_par *par)
{
par->xres = var->xres;
par->yres = var->yres;
@@ -934,7 +901,7 @@ static int retz3_decode_var(struct fb_var_screeninfo *var,
*/
static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
+ struct retz3fb_par *par)
{
short i;
@@ -959,7 +926,7 @@ static int retz3_encode_var(struct fb_var_screeninfo *var,
var->height = -1;
var->width = -1;
- var->accel = FB_ACCEL_RETINAZ3;
+ var->accel = FB_ACCEL_NCR77C32BLT;
var->pixclock = par->pixclock;
@@ -987,7 +954,7 @@ static int retz3_encode_var(struct fb_var_screeninfo *var,
static int retz3_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
- unsigned int transp)
+ unsigned int transp, struct fb_info *info)
{
/* We'll get to this */
@@ -1015,7 +982,7 @@ static int retz3_setcolreg(unsigned int regno, unsigned int red,
static int retz3_getcolreg(unsigned int regno, unsigned int *red,
unsigned int *green, unsigned int *blue,
- unsigned int *transp)
+ unsigned int *transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -1052,11 +1019,11 @@ void retz3_blank(int blank)
}
-void retz3_bitblt (struct fb_var_screeninfo *var,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask)
+static void retz3_bitblt (struct fb_var_screeninfo *var,
+ unsigned short srcx, unsigned short srcy,
+ unsigned short destx, unsigned short desty,
+ unsigned short width, unsigned short height,
+ unsigned short cmd, unsigned short mask)
{
volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
@@ -1129,7 +1096,7 @@ void retz3_bitblt (struct fb_var_screeninfo *var,
*(acm + ACM_CONTROL/4) = tmp;
tmp = width | (height << 16);
-
+
*(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
@@ -1154,20 +1121,10 @@ void retz3_bitblt (struct fb_var_screeninfo *var,
}
#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
- short width, unsigned short height,
- unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-#if 0
/*
* Move cursor to x, y
*/
-void retz3_MoveCursor (unsigned short x, unsigned short y)
+static void retz3_MoveCursor (unsigned short x, unsigned short y)
{
/* Guess we gotta deal with the cursor at some point */
}
@@ -1189,16 +1146,16 @@ static struct fb_hwswitch retz3_switch = {
* Fill the hardware's `par' structure.
*/
-static void retz3_fb_get_par(struct retz3_fb_par *par)
+static void retz3fb_get_par(struct retz3fb_par *par)
{
if (current_par_valid)
*par = current_par;
else
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
+ fbhw->decode_var(&retz3fb_default, par);
}
-static void retz3_fb_set_par(struct retz3_fb_par *par)
+static void retz3fb_set_par(struct retz3fb_par *par)
{
current_par = *par;
current_par_valid = 1;
@@ -1208,7 +1165,7 @@ static void retz3_fb_set_par(struct retz3_fb_par *par)
static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
{
int err, activate;
- struct retz3_fb_par par;
+ struct retz3fb_par par;
if ((err = fbhw->decode_var(var, &par)))
return err;
@@ -1217,7 +1174,7 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
/* XXX ... what to do about isactive ? */
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3_fb_set_par(&par);
+ retz3fb_set_par(&par);
fbhw->encode_var(var, &par);
var->activate = activate;
@@ -1227,17 +1184,17 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
}
-static void do_install_cmap(int con)
+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,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
&fb_display[con].var, 1,
- fbhw->setcolreg);
+ fbhw->setcolreg, info);
}
@@ -1245,7 +1202,7 @@ static void do_install_cmap(int con)
* Open/Release the frame buffer device
*/
-static int retz3_fb_open(int fbidx)
+static int retz3fb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -1255,7 +1212,7 @@ static int retz3_fb_open(int fbidx)
return 0;
}
-static int retz3_fb_release(int fbidx)
+static int retz3fb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return 0;
@@ -1266,13 +1223,14 @@ static int retz3_fb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
- struct retz3_fb_par par;
+ struct retz3fb_par par;
int error = 0;
if (con == -1)
- retz3_fb_get_par(&par);
+ retz3fb_get_par(&par);
else
error = fbhw->decode_var(&fb_display[con].var, &par);
return(error ? error : fbhw->encode_fix(fix, &par));
@@ -1283,13 +1241,14 @@ static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
+static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
- struct retz3_fb_par par;
+ struct retz3fb_par par;
int error = 0;
if (con == -1) {
- retz3_fb_get_par(&par);
+ retz3fb_get_par(&par);
error = fbhw->encode_var(var, &par);
} else
*var = fb_display[con].var;
@@ -1298,7 +1257,7 @@ static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
#if 1
-static void retz3_fb_set_disp(int con)
+static void retz3fb_set_disp(int con, struct fb_info *info)
{
struct fb_fix_screeninfo fix;
struct display *display;
@@ -1308,7 +1267,7 @@ static void retz3_fb_set_disp(int con)
else
display = &disp; /* used during initialization */
- retz3_fb_get_fix(&fix, con);
+ retz3fb_get_fix(&fix, con, info);
if (con == -1)
con = 0;
@@ -1321,6 +1280,21 @@ static void retz3_fb_set_disp(int con)
display->ywrapstep = fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = z3fb_inverse;
+ switch (display->var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_retz3_8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
}
#endif
@@ -1328,7 +1302,8 @@ static void retz3_fb_set_disp(int con)
* Set the User Defined Part of the Display
*/
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
+static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
struct display *display;
@@ -1359,7 +1334,7 @@ static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
oldbpp != var->bits_per_pixel) {
struct fb_fix_screeninfo fix;
- retz3_fb_get_fix(&fix, con);
+ retz3fb_get_fix(&fix, con, info);
display->screen_base = fix.smem_start;
display->visual = fix.visual;
@@ -1370,8 +1345,23 @@ static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = z3fb_inverse;
+ switch (display->var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_retz3_8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
/*
- retz3_fb_set_disp(con);
+ retz3fb_set_disp(con, info);
*/
if (fb_info.changevar)
(*fb_info.changevar)(con);
@@ -1380,7 +1370,7 @@ static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
}
return 0;
@@ -1391,15 +1381,16 @@ static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
if (con == currcon) /* current console? */
return(fb_get_cmap(cmap, &fb_display[con].var, kspc,
- fbhw->getcolreg));
+ fbhw->getcolreg, info));
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
@@ -1409,7 +1400,8 @@ static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
int err;
@@ -1421,7 +1413,7 @@ static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
}
if (con == currcon) /* current console? */
return(fb_set_cmap(cmap, &fb_display[con].var, kspc,
- fbhw->setcolreg));
+ fbhw->setcolreg, info));
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
@@ -1434,7 +1426,8 @@ static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
return -EINVAL;
}
@@ -1444,21 +1437,22 @@ static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
* RetinaZ3 Frame Buffer Specific ioctls
*/
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con)
+static int retz3fb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
{
return -EINVAL;
}
-static struct fb_ops retz3_fb_ops = {
- retz3_fb_open, retz3_fb_release, retz3_fb_get_fix, retz3_fb_get_var,
- retz3_fb_set_var, retz3_fb_get_cmap, retz3_fb_set_cmap,
- retz3_fb_pan_display, retz3_fb_ioctl
+static struct fb_ops retz3fb_ops = {
+ retz3fb_open, retz3fb_release, retz3fb_get_fix, retz3fb_get_var,
+ retz3fb_set_var, retz3fb_get_cmap, retz3fb_set_cmap,
+ retz3fb_pan_display, NULL, retz3fb_ioctl
};
-__initfunc(void retz3_video_setup(char *options, int *ints))
+__initfunc(void retz3fb_setup(char *options, int *ints))
{
char *this_opt;
@@ -1467,7 +1461,7 @@ __initfunc(void retz3_video_setup(char *options, int *ints))
if (!options || !*options)
return;
- for (this_opt = strtok(options, ","); this_opt;
+ for (this_opt = strtok(options, ","); this_opt;
this_opt = strtok(NULL, ",")){
if (!strcmp(this_opt, "inverse")) {
z3fb_inverse = 1;
@@ -1484,14 +1478,14 @@ __initfunc(void retz3_video_setup(char *options, int *ints))
* Initialization
*/
-__initfunc(unsigned long retz3_fb_init(unsigned long mem_start))
+__initfunc(unsigned long retz3fb_init(unsigned long mem_start))
{
int err;
unsigned long board_addr, board_size;
unsigned int key;
const struct ConfigDev *cd;
- struct retz3_fb_par par;
+ struct retz3fb_par par;
if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
return mem_start;
@@ -1511,43 +1505,38 @@ __initfunc(unsigned long retz3_fb_init(unsigned long mem_start))
z3_size = 0x00400000; /* 4 MB */
- memset ((char*)z3_fbmem, 0, z3_size);
-
fbhw = &retz3_switch;
fbhw->init();
- strcpy(fb_info.modename, retz3_fb_name);
+ strcpy(fb_info.modename, retz3fb_name);
fb_info.changevar = NULL;
fb_info.node = -1;
- fb_info.fbops = &retz3_fb_ops;
- fb_info.fbvar_num = NUM_TOTAL_MODES;
- fb_info.fbvar = retz3_fb_predefined;
+ fb_info.fbops = &retz3fb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &z3fb_switch;
fb_info.updatevar = &z3fb_updatevar;
fb_info.blank = &z3fb_blank;
- fb_info.setcmap = &z3fb_setcmap;
err = register_framebuffer(&fb_info);
if (err < 0)
return mem_start;
if (z3fb_mode == -1)
- z3fb_mode = 1;
+ retz3fb_default = retz3fb_predefined[0].var;
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
- fbhw->encode_var(&retz3_fb_predefined[0], &par);
+ fbhw->decode_var(&retz3fb_default, &par);
+ fbhw->encode_var(&retz3fb_default, &par);
- do_fb_set_var(&retz3_fb_predefined[0], 0);
- retz3_fb_get_var(&disp.var, -1);
+ do_fb_set_var(&retz3fb_default, 0);
+ retz3fb_get_var(&disp.var, -1, &fb_info);
- retz3_fb_set_disp(-1);
+ retz3fb_set_disp(-1, &fb_info);
- do_install_cmap(0);
+ do_install_cmap(0, &fb_info);
- printk("%s frame buffer device, using %ldK of video memory\n",
- fb_info.modename, z3_size>>10);
+ printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename, z3_size>>10);
/* TODO: This driver cannot be unloaded yet */
MOD_INC_USE_COUNT;
@@ -1556,17 +1545,18 @@ __initfunc(unsigned long retz3_fb_init(unsigned long mem_start))
}
-static int z3fb_switch(int con)
+static int z3fb_switch(int con, struct fb_info *info)
{
/* 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, fbhw->getcolreg);
+ &fb_display[currcon].var, 1, fbhw->getcolreg,
+ info);
do_fb_set_var(&fb_display[con].var, 1);
currcon = con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -1578,7 +1568,7 @@ static int z3fb_switch(int con)
* Since it's called by a kernel driver, no range checking is done.
*/
-static int z3fb_updatevar(int con)
+static int z3fb_updatevar(int con, struct fb_info *info)
{
return 0;
}
@@ -1588,33 +1578,23 @@ static int z3fb_updatevar(int con)
* Blank the display.
*/
-static void z3fb_blank(int blank)
+static void z3fb_blank(int blank, struct fb_info *info)
{
fbhw->blank(blank);
}
/*
- * Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
* Get a Video Mode
*/
-static int get_video_mode(const char *name)
+__initfunc(static int get_video_mode(const char *name))
{
short i;
- for (i = 1; i <= NUM_PREDEF_MODES; i++)
- if (!strcmp(name, retz3_fb_modenames[i])){
- retz3_fb_predefined[0] = retz3_fb_predefined[i];
+ for (i = 0; i <= NUM_TOTAL_MODES; i++)
+ if (!strcmp(name, retz3fb_predefined[i].name)){
+ retz3fb_default = retz3fb_predefined[i].var;
return i;
}
return -1;
@@ -1624,7 +1604,7 @@ static int get_video_mode(const char *name)
#ifdef MODULE
int init_module(void)
{
- return(retz3_fb_init(NULL));
+ return(retz3fb_init(NULL));
}
void cleanup_module(void)
@@ -1636,11 +1616,60 @@ void cleanup_module(void)
unregister_framebuffer(&fb_info);
/* TODO: clean up ... */
}
-#endif /* MODULE */
+#endif
/*
- * Visible symbols for modules
+ * Text console acceleration
*/
-EXPORT_SYMBOL(retz3_bitblt);
+#ifdef CONFIG_FBCON_CFB8
+static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ int fontwidth = p->fontwidth;
+
+ sx *= fontwidth;
+ dx *= fontwidth;
+ width *= fontwidth;
+
+ retz3_bitblt(&p->var,
+ (unsigned short)sx,
+ (unsigned short)(sy*p->fontheight),
+ (unsigned short)dx,
+ (unsigned short)(dy*p->fontheight),
+ (unsigned short)width,
+ (unsigned short)(height*p->fontheight),
+ Z3BLTcopy,
+ 0xffff);
+}
+
+static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int
+ sy, int sx, int height, int width)
+{
+ unsigned short col;
+ int fontwidth = p->fontwidth;
+
+ sx *= fontwidth;
+ width *= fontwidth;
+
+ col = attr_bgcol_ec(p, conp);
+ col &= 0xff;
+ col |= (col << 8);
+
+ retz3_bitblt(&p->var,
+ (unsigned short)sx,
+ (unsigned short)(sy*p->fontheight),
+ (unsigned short)sx,
+ (unsigned short)(sy*p->fontheight),
+ (unsigned short)width,
+ (unsigned short)(height*p->fontheight),
+ Z3BLTset,
+ col);
+}
+
+static struct display_switch fbcon_retz3_8 = {
+ fbcon_cfb8_setup, fbcon_retz3_8_bmove, fbcon_retz3_8_clear,
+ fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc
+};
+#endif
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
new file mode 100644
index 000000000..3f795cd63
--- /dev/null
+++ b/drivers/video/skeletonfb.c
@@ -0,0 +1,388 @@
+/*
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *
+ * 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.
+ */
+
+#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 "fbcon.h"
+
+
+ /*
+ * This is just simple sample code.
+ *
+ * No warranty that it actually compiles.
+ * Even less warranty that it actually works :-)
+ */
+
+
+struct xxxfb_info {
+ /*
+ * Choose _one_ of the two alternatives:
+ *
+ * 1. Use the generic frame buffer operations (fbgen_*).
+ */
+ struct fb_info_gen gen;
+ /*
+ * 2. Provide your own frame buffer operations.
+ */
+ struct fb_info info;
+
+ /* Here starts the frame buffer device dependent part */
+ /* You can use this to store e.g. the board number if you support */
+ /* multiple boards */
+};
+
+
+struct xxxfb_par {
+ /*
+ * The hardware specific data in this structure uniquely defines a video
+ * mode.
+ *
+ * If your hardware supports only one video mode, you can leave it empty.
+ */
+};
+
+
+ /*
+ * If your driver supports multiple boards, you should make these arrays,
+ * or allocate them dynamically (using mem_start for builtin drivers, and
+ * kmalloc() for loaded modules).
+ */
+
+static struct xxxfb_info fb_info;
+static struct xxxfb_par current_par;
+static int current_par_valid = 0;
+static struct display disp;
+
+static struct fb_var_screeninfo default_var;
+
+static int currcon = 0;
+static int inverse = 0;
+
+
+/* ------------------- chipset specific functions -------------------------- */
+
+
+static void xxx_detect(void)
+{
+ /*
+ * This function should detect the current video mode settings and store
+ * it as the default video mode
+ */
+
+ /* ... */
+ xxx_get_par(&par);
+ xxx_encode_var(&default_var, &par);
+}
+
+static int xxx_encode_fix(struct fb_fix_screeninfo *fix, struct xxxfb_par *par,
+ const struct fb_info *fb_info)
+{
+ /*
+ * This function should fill in the 'fix' structure based on the values
+ * in the `par' structure.
+ */
+
+ /* ... */
+ return 0;
+}
+
+static int xxx_decode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
+ const struct fb_info *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.
+ */
+
+ /* ... */
+
+ /* pixclock in picos, htotal in pixels, vtotal in scanlines */
+ if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int xxx_encode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Fill the 'var' structure based on the values in 'par' and maybe other
+ * values read out of the hardware.
+ */
+
+ /* ... */
+ return 0;
+}
+
+static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *fb_info)
+{
+ /*
+ * Fill the hardware's 'par' structure.
+ */
+
+ if (current_par_valid)
+ *par = current_par;
+ else {
+ /* ... */
+ }
+}
+
+static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *fb_info)
+{
+ /*
+ * Set the hardware according to 'par'.
+ */
+
+ current_par = *par;
+ current_par_valid = 1;
+ /* ... */
+}
+
+static int xxx_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ /* ... */
+ return 0;
+}
+
+static int xxx_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Set a single color register. The values supplied are already rounded
+ * down to the hardware's capabilities (according to the entries in the
+ * `var' structure). Return != 0 for invalid regno.
+ */
+
+ if (regno < 16) {
+ /*
+ * Make the first 16 colors of the palette available to fbcon
+ */
+ if (is_cfb15) /* RGB 555 */
+ fbcon_cfb15_cmap[regno] = be16_to_cpu((red << 10) | (green << 5) |
+ blue);
+ if (is_cfb16) /* RGB 565 */
+ fbcon_cfb16_cmap[regno] = be16_to_cpu((red << 11) | (green << 5) |
+ blue);
+ if (is_cfb24) /* RGB 888 */
+ fbcon_cfb24_cmap[regno] = be32_to_cpu((red << 16) | (green << 8) |
+ blue);
+ if (is_cfb32) /* RGBA 8888 */
+ fbcon_cfb32_cmap[regno] = be32_to_cpu((red << 24) | (green << 16) |
+ (blue << 8) | transp);
+ }
+ /* ... */
+ return 0;
+}
+
+static int xxx_pan_display(struct fb_var_screeninfo *var,
+ struct xxxfb_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.
+ */
+
+ /* ... */
+ return 0;
+}
+
+static int xxx_blank(int blank_mode, const struct fb_info *fb_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
+ */
+
+ /* ... */
+ return 0;
+}
+
+static struct display_switch *xxx_get_dispsw(const void *par,
+ struct fb_info_gen *info)
+{
+ /*
+ * Return a pointer to appropriate low level text console operations for
+ * the video mode `par' of your video hardware. These can be generic
+ * software routines, or hardware accelerated routines specifically
+ * tailored for your hardware.
+ * If you don't have any appropriate operations, simple fill in the NULL
+ * pointer, and there will be no text output.
+ */
+#ifdef CONFIG_FBCON_CFB8
+ if (is_cfb8)
+ return &fbcon_cfb8;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ if (is_cfb16)
+ return &fbcon_cfb16;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ if (is_cfb32)
+ return &fbcon_cfb32;
+#endif
+ return NULL;
+}
+
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+
+struct fbgen_hwswitch xxx_switch = {
+ xxx_detect, xxx_encode_fix, xxx_decode_var, xxx_encode_var, xxx_get_par,
+ xxx_set_par, xxx_getcolreg, xxx_setcolreg, xxx_blank, xxx_dispsw
+};
+
+
+
+/* ------------ Hardware Independant Functions ------------ */
+
+
+ /*
+ * Initialization
+ */
+
+__initfunc(unsigned long xxxfb_init(unsigned long mem_start))
+{
+ int err;
+ struct fb_var_screeninfo var;
+
+ fb_info.fbhw = &xxx_switch;
+ fbhw->detect();
+ strcpy(fb_info.modename, "XXX");
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &xxxfb_ops;
+ fb_info.disp = disp;
+ fb_info.switch_con = &xxxfb_switch;
+ fb_info.updatevar = &xxxfb_update_var;
+ fb_info.blank = &xxxfb_blank;
+ /* This should give a reasonable default video mode */
+ fbgen_get_var(&disp.var, -1, &fb_info.gen);
+ fbgen_do_set_var(var, 1, &fbinfo.gen);
+ err = register_framebuffer(&fb_info.gen.info);
+ if (err < 0)
+ return err;
+ fbgen_set_disp(-1, &fb_info.gen.info);
+ fbgen_install_cmap(0, &fb_info.gen);
+ printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
+ fb_info.modename);
+
+ /* uncomment this if your driver cannot be unloaded */
+ /* MOD_INC_USE_COUNT; */
+
+ return mem_start;
+}
+
+
+ /*
+ * Cleanup
+ */
+
+void xxxfb_cleanup(struct fb_info *info)
+{
+ /*
+ * If your driver supports multiple boards, you should unregister and
+ * clean up all instances.
+ */
+
+ unregister_framebuffer(&fb_info);
+ /* ... */
+}
+
+
+ /*
+ * Setup
+ */
+
+__initfunc(void xxxfb_setup(char *options, int *ints))
+{
+ /* Parse user speficied options (`video=xxxfb:') */
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+ /*
+ * Frame buffer operations
+ */
+
+static int xxxfb_open(const struct fb_info *info)
+{
+ /* Nothing, only a usage count for the moment */
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int xxxfb_release(const struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+ /*
+ * In most cases the `generic' routines (fbgen_*) should be satisfactory.
+ * However, you're free to fill in your own replacements.
+ */
+
+static struct fb_ops xxxfb_ops = {
+ xxxfb_open, xxxfb_release, fbgen_get_fix, fbgen_get_var, fbgen_set_var,
+ fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, NULL, fbgen_ioctl
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+ /*
+ * Modularization
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ return xxxfb_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ xxxfb_cleanup(void);
+}
+#endif /* MODULE */
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index ac3746109..7e74f7449 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -17,13 +17,12 @@
*
* - How to set a single color register?
*
- * - We don't have support for CFB32 yet (fbcon-cfb32.c)
- *
* - Hardware cursor (useful for other graphics boards too)
*
* KNOWN PROBLEMS/TO DO ==================================================== */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -37,11 +36,13 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/selection.h>
#include <asm/io.h>
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb32.h"
+
/* TGA hardware description (minimal) */
/*
@@ -188,10 +189,17 @@ static unsigned int base_addr_presets[4] __initdata = {
unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
const unsigned long bt485_cursor_source[64] __initdata = {
+#if 1
+ 0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
+ 0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
+ 0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
+ 0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
+#else
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
+#endif
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
@@ -235,9 +243,8 @@ static int currcon = 0;
static struct display disp;
static struct fb_info fb_info;
static struct { u_char red, green, blue, pad; } palette[256];
-static char tgafb_name[16] = "DEC TGA ";
-static struct fb_fix_screeninfo fb_fix;
+static struct fb_fix_screeninfo fb_fix = { { "DEC TGA ", } };
static struct fb_var_screeninfo fb_var = { 0, };
@@ -245,18 +252,22 @@ static struct fb_var_screeninfo fb_var = { 0, };
* Interface used by the world
*/
-void tgafb_video_setup(char *options, int *ints);
-
-static int tgafb_open(int fbidx);
-static int tgafb_release(int fbidx);
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con);
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con);
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con);
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
+static int tgafb_open(struct fb_info *info);
+static int tgafb_release(struct fb_info *info);
+static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
+ u_long arg, int con, struct fb_info *info);
/*
@@ -264,10 +275,9 @@ static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
*/
unsigned long tgafb_init(unsigned long mem_start);
-static int tgafbcon_switch(int con);
-static int tgafbcon_updatevar(int con);
-static void tgafbcon_blank(int blank);
-static int tgafbcon_setcmap(struct fb_cmap *cmap, int con);
+static int tgafbcon_switch(int con, struct fb_info *info);
+static int tgafbcon_updatevar(int con, struct fb_info *info);
+static void tgafbcon_blank(int blank, struct fb_info *info);
/*
@@ -275,18 +285,18 @@ static int tgafbcon_setcmap(struct fb_cmap *cmap, int con);
*/
static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
+ u_int transp, struct fb_info *info);
#if 1
static void tga_update_palette(void);
#endif
-static void do_install_cmap(int con);
+static void do_install_cmap(int con, struct fb_info *info);
static struct fb_ops tgafb_ops = {
tgafb_open, tgafb_release, tgafb_get_fix, tgafb_get_var, tgafb_set_var,
- tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, tgafb_ioctl
+ tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, NULL, tgafb_ioctl
};
@@ -294,7 +304,7 @@ static struct fb_ops tgafb_ops = {
* Open/Release the frame buffer device
*/
-static int tgafb_open(int fbidx)
+static int tgafb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -304,7 +314,7 @@ static int tgafb_open(int fbidx)
return(0);
}
-static int tgafb_release(int fbidx)
+static int tgafb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
@@ -315,7 +325,8 @@ static int tgafb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
memcpy(fix, &fb_fix, sizeof(fb_fix));
return 0;
@@ -326,7 +337,8 @@ static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con)
+static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
memcpy(var, &fb_var, sizeof(fb_var));
return 0;
@@ -337,7 +349,8 @@ static int tgafb_get_var(struct fb_var_screeninfo *var, int con)
* Set the User Defined Part of the Display
*/
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con)
+static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
struct display *display;
int oldbpp = -1, err;
@@ -363,7 +376,7 @@ static int tgafb_set_var(struct fb_var_screeninfo *var, int con)
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
return 0;
}
@@ -375,7 +388,8 @@ static int tgafb_set_var(struct fb_var_screeninfo *var, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con)
+static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
if (var->xoffset || var->yoffset)
return -EINVAL;
@@ -387,14 +401,16 @@ static int tgafb_pan_display(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int tgafb_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, tgafb_getcolreg);
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, tgafb_getcolreg,
+ info);
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
@@ -403,7 +419,8 @@ static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
int err;
@@ -413,7 +430,8 @@ static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
return err;
}
if (con == currcon) { /* current console? */
- err = fb_set_cmap(cmap, &fb_display[con].var, kspc, tgafb_setcolreg);
+ err = fb_set_cmap(cmap, &fb_display[con].var, kspc, tgafb_setcolreg,
+ info);
#if 1
tga_update_palette();
#endif
@@ -425,7 +443,7 @@ static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con)
+ u_long arg, int con, struct fb_info *info)
{
return -EINVAL;
}
@@ -437,22 +455,14 @@ static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
__initfunc(unsigned long tgafb_init(unsigned long mem_start))
{
- unsigned char pci_bus, pci_devfn;
- int status;
int i, j, temp, err;
unsigned char *cbp;
+ struct pci_dev *pdev;
- status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
- 0, &pci_bus, &pci_devfn);
- if (status == PCIBIOS_DEVICE_NOT_FOUND)
+ pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
+ if (!pdev)
return mem_start;
-
- /*
- * read BASE_REG_0 for memory address
- */
- pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
- &tga_mem_base);
- tga_mem_base &= ~15;
+ tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
#ifdef DEBUG
printk("tgafb_init: mem_base 0x%x\n", tga_mem_base);
#endif /* DEBUG */
@@ -460,19 +470,18 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
tga_type = (readl((unsigned long)tga_mem_base) >> 12) & 0x0f;
switch (tga_type) {
case 0:
- strcat(tgafb_name, "8plane");
+ strcat(fb_fix.id, "8plane");
break;
case 1:
- strcat(tgafb_name, "24plane");
+ strcat(fb_fix.id, "24plane");
break;
case 3:
- strcat(tgafb_name, "24plusZ");
+ strcat(fb_fix.id, "24plusZ");
break;
default:
printk("TGA type (0x%x) unrecognized!\n", tga_type);
return mem_start;
}
- strcpy(fb_fix.id, tgafb_name);
tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET);
tga_fb_base = ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]);
@@ -537,6 +546,9 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
+ palette[i].red=default_red[j];
+ palette[i].green=default_grn[j];
+ palette[i].blue=default_blu[j];
}
for (i = 0; i < 240*3; i += 4) {
TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
@@ -548,9 +560,9 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
/* initialize RAMDAC cursor colors */
BT485_WRITE(0, BT485_ADDR_CUR_WRITE);
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
+ BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
+ BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
+ BT485_WRITE(0x00, BT485_DATA_CUR); /* overscan WHITE */
BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
@@ -677,7 +689,7 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
fb_var.xres = fb_var.xres_virtual = 640;
fb_var.yres = fb_var.yres_virtual = 480;
fb_fix.line_length = 80*fb_var.bits_per_pixel;
- fb_fix.smem_start = (char *)tga_fb_base;
+ fb_fix.smem_start = (char *)(tga_fb_base + LCA_DENSE_MEM);
fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
fb_fix.type = FB_TYPE_PACKED_PIXELS;
fb_fix.type_aux = 0;
@@ -686,7 +698,16 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
fb_var.xoffset = fb_var.yoffset = 0;
fb_var.grayscale = 0;
- fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
+ if (tga_type == 0) { /* 8-plane */
+ fb_var.red.offset = 0;
+ fb_var.green.offset = 0;
+ fb_var.blue.offset = 0;
+ } else { /* 24-plane or 24plusZ */
+ /* XXX: is this correct?? */
+ fb_var.red.offset = 16;
+ fb_var.green.offset = 8;
+ fb_var.blue.offset = 0;
+ }
fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
@@ -717,41 +738,54 @@ __initfunc(unsigned long tgafb_init(unsigned long mem_start))
disp.line_length = fb_fix.line_length;
disp.can_soft_blank = 1;
disp.inverse = 0;
+ switch (tga_type) {
+#ifdef CONFIG_FBCON_CFB8
+ case 0: /* 8-plane */
+ disp.dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ case 1: /* 24-plane */
+ case 3: /* 24plusZ */
+ disp.dispsw = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ disp.dispsw = NULL;
+ }
- strcpy(fb_info.modename, tgafb_name);
+ strcpy(fb_info.modename, fb_fix.id);
fb_info.node = -1;
fb_info.fbops = &tgafb_ops;
- fb_info.fbvar_num = 1;
- fb_info.fbvar = &fb_var;
fb_info.disp = &disp;
fb_info.fontname[0] = '\0';
fb_info.changevar = NULL;
fb_info.switch_con = &tgafbcon_switch;
fb_info.updatevar = &tgafbcon_updatevar;
fb_info.blank = &tgafbcon_blank;
- fb_info.setcmap = &tgafbcon_setcmap;
err = register_framebuffer(&fb_info);
if (err < 0)
return mem_start;
- tgafb_set_var(&fb_var, -1);
+ tgafb_set_var(&fb_var, -1, &fb_info);
- printk("%s frame buffer device\n", tgafb_name);
+ printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
+ fb_fix.id);
return mem_start;
}
-static int tgafbcon_switch(int con)
+static int tgafbcon_switch(int con, struct fb_info *info)
{
/* 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,
- tgafb_getcolreg);
+ tgafb_getcolreg, info);
currcon = con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -759,7 +793,7 @@ static int tgafbcon_switch(int con)
* Update the `var' structure (called by fbcon.c)
*/
-static int tgafbcon_updatevar(int con)
+static int tgafbcon_updatevar(int con, struct fb_info *info)
{
/* Nothing */
return 0;
@@ -769,28 +803,18 @@ static int tgafbcon_updatevar(int con)
* Blank the display.
*/
-static void tgafbcon_blank(int blank)
+static void tgafbcon_blank(int blank, struct fb_info *info)
{
/* Nothing */
}
/*
- * Set the colormap
- */
-
-static int tgafbcon_setcmap(struct fb_cmap *cmap, int con)
-{
- return(tgafb_set_cmap(cmap, 1, con));
-}
-
-
- /*
* Read a single color register and split it into
* colors/transparent. Return != 0 for invalid regno.
*/
static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
+ u_int *transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -808,7 +832,7 @@ static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
*/
static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
+ u_int transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -816,6 +840,11 @@ static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
palette[regno].green = green;
palette[regno].blue = blue;
+#ifdef CONFIG_FBCON_CFB32
+ if (regno < 16 && tga_type != 0)
+ fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+#endif /* CONFIG_FBCON_CFB32 */
+
/* How to set a single color register?? */
return 0;
@@ -853,22 +882,22 @@ static void tga_update_palette(void)
}
#endif
-static void do_install_cmap(int con)
+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,
- tgafb_setcolreg);
+ tgafb_setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, tgafb_setcolreg);
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, tgafb_setcolreg,
+ info);
#if 1
tga_update_palette();
#endif
}
-
#if 0 /* No cursor stuff yet */
/*
diff --git a/drivers/video/txtcon.c b/drivers/video/txtcon.c
index cdecc08b0..83165b49b 100644
--- a/drivers/video/txtcon.c
+++ b/drivers/video/txtcon.c
@@ -14,48 +14,55 @@
*/
+#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/kdev_t.h>
#include <linux/console.h>
- /*
- * Interface used by the world
- */
+ /*
+ * Interface used by the world
+ */
-static int txtcon_startup(u_long *kmem_start, const char **display_desc);
+static unsigned long txtcon_startup(unsigned long kmem_start,
+ const char **display_desc);
static void txtcon_init(struct vc_data *conp);
-static int txtcon_deinit(struct vc_data *conp);
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width);
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x);
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
- int x);
-static int txtcon_cursor(struct vc_data *conp, int mode);
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width);
+static void txtcon_deinit(struct vc_data *conp);
+static void txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
+ int width);
+static void txtcon_putc(struct vc_data *conp, int c, int y, int x);
+static void txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
+ int x);
+static void txtcon_cursor(struct vc_data *conp, int mode);
+static void txtcon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count);
+static void txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+ int height, int width);
static int txtcon_switch(struct vc_data *conp);
static int txtcon_blank(int blank);
static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data);
static int txtcon_set_palette(struct vc_data *conp, unsigned char *table);
static int txtcon_scrolldelta(int lines);
+static int txtcon_set_mode(struct vc_data *conp, int mode);
-static int txtcon_startup(u_long *kmem_start, const char **display_desc)
+static unsigned long txtcon_startup(unsigned long kmem_start,
+ const char **display_desc)
{
- return -ENODEV;
+ return kmem_start;
}
static void txtcon_init(struct vc_data *conp)
{
+ /* ... */
}
-static int txtcon_deinit(struct vc_data *conp)
+static void txtcon_deinit(struct vc_data *conp)
{
- return 0;
+ /* ... */
}
@@ -64,90 +71,108 @@ static int txtcon_deinit(struct vc_data *conp)
/* txtcon_XXX routines - interface used by the world */
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width)
+static void txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
+ int width)
{
- return -ENOSYS;
+ /* ... */
}
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x)
+static void txtcon_putc(struct vc_data *conp, int c, int y, int x)
{
- return -ENOSYS;
+ /* ... */
}
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
- int x)
+static void txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
+ int x)
{
- return -ENOSYS;
+ /* ... */
}
-static int txtcon_cursor(struct vc_data *conp, int mode)
+static void txtcon_cursor(struct vc_data *conp, int mode)
{
- return -ENOSYS;
+ /* ... */
}
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+static void txtcon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count)
{
- return -ENOSYS;
+ /* ... */
}
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width)
+static void txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+ int height, int width)
{
- return -ENOSYS;
+ /* ... */
}
static int txtcon_switch(struct vc_data *conp)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int txtcon_blank(int blank)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int txtcon_set_palette(struct vc_data *conp, unsigned char *table)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int txtcon_scrolldelta(int lines)
{
- return -ENOSYS;
+ return -ENOSYS;
+}
+
+static int txtcon_set_mode(struct vc_data *conp, int mode)
+{
+ return -ENOSYS;
}
/* ====================================================================== */
- /*
- * The console `switch' structure for the text mode based console
- */
+ /*
+ * The console `switch' structure for the text mode based console
+ */
struct consw txt_con = {
- txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc,
- txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch,
- txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette,
- txtcon_scrolldelta
+ txtcon_startup,
+ txtcon_init,
+ txtcon_deinit,
+ txtcon_clear,
+ txtcon_putc,
+ txtcon_putcs,
+ txtcon_cursor,
+ txtcon_scroll,
+ txtcon_bmove,
+ txtcon_switch,
+ txtcon_blank,
+ txtcon_get_font,
+ txtcon_set_font,
+ txtcon_set_palette,
+ txtcon_scrolldelta,
+ txtcon_set_mode
};
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 63e7f7ca2..eea430ffa 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -22,6 +23,14 @@
#include <linux/fb.h>
#include <linux/init.h>
+#include "fbcon-mfb.h"
+#include "fbcon-cfb2.h"
+#include "fbcon-cfb4.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
+#include "fbcon-cfb32.h"
+
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
@@ -41,61 +50,51 @@ static int currcon = 0;
static struct display disp;
static struct fb_info fb_info;
static struct { u_char red, green, blue, pad; } palette[256];
-static char virtual_fb_name[16] = "Virtual FB";
-
-static struct fb_var_screeninfo virtual_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- {
- /* 640x480, 8 bpp */
- 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, 20000, 64, 64, 32, 32, 64, 2,
- 0, FB_VMODE_NONINTERLACED
- },
-
- /*
- * User Defined Video Modes (8)
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+static char vfb_name[16] = "Virtual FB";
+
+static struct fb_var_screeninfo vfb_default = {
+ /* 640x480, 8 bpp */
+ 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, 20000, 64, 64, 32, 32, 64, 2,
+ 0, FB_VMODE_NONINTERLACED
};
-#define NUM_USER_MODES (8)
-#define NUM_TOTAL_MODES arraysize(virtual_fb_predefined)
-#define NUM_PREDEF_MODES (1)
+static int vfb_enable = 0; /* disabled by default */
/*
* Interface used by the world
*/
-void vfb_video_setup(char *options, int *ints);
-
-static int virtual_fb_open(int fbidx);
-static int virtual_fb_release(int fbidx);
-static int virtual_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int virtual_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int virtual_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int virtual_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int virtual_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
+void vfb_setup(char *options, int *ints);
+
+static int vfb_open(struct fb_info *info);
+static int vfb_release(struct fb_info *info);
+static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int vfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int vfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int vfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
/*
* Interface to the low level console driver
*/
-unsigned long virtual_fb_init(unsigned long mem_start);
-static int vfbcon_switch(int con);
-static int vfbcon_updatevar(int con);
-static void vfbcon_blank(int blank);
-static int vfbcon_setcmap(struct fb_cmap *cmap, int con);
+unsigned long vfb_init(unsigned long mem_start);
+static int vfbcon_switch(int con, struct fb_info *info);
+static int vfbcon_updatevar(int con, struct fb_info *info);
+static void vfbcon_blank(int blank, struct fb_info *info);
/*
@@ -107,16 +106,15 @@ static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
struct fb_var_screeninfo *var);
static void set_color_bitfields(struct fb_var_screeninfo *var);
static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
+ u_int *transp, struct fb_info *info);
static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
-static void do_install_cmap(int con);
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
-static struct fb_ops virtual_fb_ops = {
- virtual_fb_open, virtual_fb_release, virtual_fb_get_fix,
- virtual_fb_get_var, virtual_fb_set_var, virtual_fb_get_cmap,
- virtual_fb_set_cmap, virtual_fb_pan_display, virtual_fb_ioctl
+static struct fb_ops vfb_ops = {
+ vfb_open, vfb_release, vfb_get_fix, vfb_get_var, vfb_set_var, vfb_get_cmap,
+ vfb_set_cmap, vfb_pan_display, NULL, vfb_ioctl
};
@@ -124,7 +122,7 @@ static struct fb_ops virtual_fb_ops = {
* Open/Release the frame buffer device
*/
-static int virtual_fb_open(int fbidx)
+static int vfb_open(struct fb_info *info)
{
/*
* Nothing, only a usage count for the moment
@@ -134,7 +132,7 @@ static int virtual_fb_open(int fbidx)
return(0);
}
-static int virtual_fb_release(int fbidx)
+static int vfb_release(struct fb_info *info)
{
MOD_DEC_USE_COUNT;
return(0);
@@ -145,12 +143,13 @@ static int virtual_fb_release(int fbidx)
* Get the Fixed Part of the Display
*/
-static int virtual_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
{
struct fb_var_screeninfo *var;
if (con == -1)
- var = &virtual_fb_predefined[0];
+ var = &vfb_default;
else
var = &fb_display[con].var;
vfb_encode_fix(fix, var);
@@ -162,10 +161,11 @@ static int virtual_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
* Get the User Defined Part of the Display
*/
-static int virtual_fb_get_var(struct fb_var_screeninfo *var, int con)
+static int vfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
if (con == -1)
- *var = virtual_fb_predefined[0];
+ *var = vfb_default;
else
*var = fb_display[con].var;
set_color_bitfields(var);
@@ -177,7 +177,8 @@ static int virtual_fb_get_var(struct fb_var_screeninfo *var, int con)
* Set the User Defined Part of the Display
*/
-static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con)
+static int vfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
int err, activate = var->activate;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
@@ -258,13 +259,53 @@ static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con)
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = 0;
+ switch (var->bits_per_pixel) {
+#ifdef CONFIG_FBCON_MFB
+ case 1:
+ display->dispsw = &fbcon_mfb;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB2
+ case 2:
+ display->dispsw = &fbcon_cfb2;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB4
+ case 4:
+ display->dispsw = &fbcon_cfb4;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB24
+ case 24:
+ display->dispsw = &fbcon_cfb24;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ case 32:
+ display->dispsw = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
if (fb_info.changevar)
(*fb_info.changevar)(con);
}
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con);
+ do_install_cmap(con, info);
}
}
return 0;
@@ -277,7 +318,8 @@ static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con)
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int virtual_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0 ||
@@ -304,14 +346,16 @@ static int virtual_fb_pan_display(struct fb_var_screeninfo *var, int con)
* Get the Colormap
*/
-static int virtual_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int vfb_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, vfb_getcolreg);
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, vfb_getcolreg,
+ info);
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(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
@@ -320,7 +364,8 @@ static int virtual_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
* Set the Colormap
*/
-static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
int err;
@@ -330,7 +375,8 @@ static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
return err;
}
if (con == currcon) /* current console? */
- return fb_set_cmap(cmap, &fb_display[con].var, kspc, vfb_setcolreg);
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, vfb_setcolreg,
+ info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
@@ -341,19 +387,21 @@ static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
* Virtual Frame Buffer Specific ioctls
*/
-static int virtual_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con)
+static int vfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
{
return -EINVAL;
}
-__initfunc(void vfb_video_setup(char *options, int *ints))
+__initfunc(void vfb_setup(char *options, int *ints))
{
char *this_opt;
fb_info.fontname[0] = '\0';
+ vfb_enable = 1;
+
if (!options || !*options)
return;
@@ -369,10 +417,13 @@ __initfunc(void vfb_video_setup(char *options, int *ints))
* Initialisation
*/
-__initfunc(unsigned long virtual_fb_init(unsigned long mem_start))
+__initfunc(unsigned long vfb_init(unsigned long mem_start))
{
int err;
+ if (!vfb_enable)
+ return mem_start;
+
if (mem_start) {
videomemory = mem_start;
mem_start += videomemorysize;
@@ -382,40 +433,37 @@ __initfunc(unsigned long virtual_fb_init(unsigned long mem_start))
if (!videomemory)
return mem_start;
- strcpy(fb_info.modename, virtual_fb_name);
+ strcpy(fb_info.modename, vfb_name);
fb_info.changevar = NULL;
fb_info.node = -1;
- fb_info.fbops = &virtual_fb_ops;
- fb_info.fbvar_num = NUM_TOTAL_MODES;
- fb_info.fbvar = virtual_fb_predefined;
+ fb_info.fbops = &vfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &vfbcon_switch;
fb_info.updatevar = &vfbcon_updatevar;
fb_info.blank = &vfbcon_blank;
- fb_info.setcmap = &vfbcon_setcmap;
err = register_framebuffer(&fb_info);
if (err < 0)
return mem_start;
- virtual_fb_set_var(&virtual_fb_predefined[0], -1);
+ vfb_set_var(&vfb_default, -1, &fb_info);
- printk("Virtual frame buffer device, using %ldK of video memory\n",
- videomemorysize>>10);
+ printk("fb%d: Virtual frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), videomemorysize>>10);
return mem_start;
}
-static int vfbcon_switch(int con)
+static int vfbcon_switch(int con, struct fb_info *info)
{
/* 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,
- vfb_getcolreg);
+ vfb_getcolreg, info);
currcon = con;
/* Install new colormap */
- do_install_cmap(con);
+ do_install_cmap(con, info);
return 0;
}
@@ -423,7 +471,7 @@ static int vfbcon_switch(int con)
* Update the `var' structure (called by fbcon.c)
*/
-static int vfbcon_updatevar(int con)
+static int vfbcon_updatevar(int con, struct fb_info *info)
{
/* Nothing */
return 0;
@@ -433,21 +481,11 @@ static int vfbcon_updatevar(int con)
* Blank the display.
*/
-static void vfbcon_blank(int blank)
+static void vfbcon_blank(int blank, struct fb_info *info)
{
/* Nothing */
}
- /*
- * Set the colormap
- */
-
-static int vfbcon_setcmap(struct fb_cmap *cmap, int con)
-{
- return(virtual_fb_set_cmap(cmap, 1, con));
-}
-
-
static u_long get_line_length(int xres_virtual, int bpp)
{
u_long length;
@@ -462,7 +500,7 @@ static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
struct fb_var_screeninfo *var)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, virtual_fb_name);
+ strcpy(fix->id, vfb_name);
fix->smem_start = (caddr_t)videomemory;
fix->smem_len = videomemorysize;
fix->type = FB_TYPE_PACKED_PIXELS;
@@ -471,6 +509,8 @@ static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
case 1:
fix->visual = FB_VISUAL_MONO01;
break;
+ case 2:
+ case 4:
case 8:
fix->visual = FB_VISUAL_PSEUDOCOLOR;
break;
@@ -544,7 +584,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var)
*/
static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
+ u_int *transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -562,7 +602,7 @@ static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
*/
static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
+ u_int transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -573,23 +613,23 @@ static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
}
-static void do_install_cmap(int con)
+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,
- vfb_setcolreg);
+ vfb_setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, vfb_setcolreg);
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, vfb_setcolreg, info);
}
#ifdef MODULE
int init_module(void)
{
- return(virtual_fb_init(NULL));
+ return(vfb_init(NULL));
}
void cleanup_module(void)
diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c
index 83a908a09..623ea799d 100644
--- a/drivers/video/vgacon.c
+++ b/drivers/video/vgacon.c
@@ -87,16 +87,16 @@
static unsigned long vgacon_startup(unsigned long kmem_start,
const char **display_desc);
static void vgacon_init(struct vc_data *conp);
-static int vgacon_deinit(struct vc_data *conp);
-static int vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width);
-static int vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos);
-static int vgacon_putcs(struct vc_data *conp, const char *s, int count,
- int ypos, int xpos);
-static int vgacon_cursor(struct vc_data *conp, int mode);
-static int vgacon_scroll(struct vc_data *conp, int t, int b,
- int dir, int count);
-static int vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+static void vgacon_deinit(struct vc_data *conp);
+static void vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
+ int width);
+static void vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos);
+static void vgacon_putcs(struct vc_data *conp, const char *s, int count,
+ int ypos, int xpos);
+static void vgacon_cursor(struct vc_data *conp, int mode);
+static void vgacon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count);
+static void vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
int height, int width);
static int vgacon_switch(struct vc_data *conp);
static int vgacon_blank(int blank);
@@ -104,6 +104,7 @@ static int vgacon_get_font(struct vc_data *conp, int *w, int *h, char *data);
static int vgacon_set_font(struct vc_data *conp, int w, int h, char *data);
static int vgacon_set_palette(struct vc_data *conp, unsigned char *table);
static int vgacon_scrolldelta(int lines);
+static int vgacon_set_mode(struct vc_data *conp, int mode);
/*
@@ -215,25 +216,6 @@ __initfunc(static unsigned long vgacon_startup(unsigned long kmem_start,
unsigned short saved;
unsigned short *p;
- /*
- * Find out if there is a graphics card present.
- * Are there smarter methods around?
- */
- p = (unsigned short *)(((ORIG_VIDEO_MODE == 7) ? 0xb0000 : 0xb8000) +
- + VGA_OFFSET);
- saved = vga_readw(p);
- vga_writew(0xAA55, p);
- if (vga_readw(p) != 0xAA55) {
- vga_writew(saved, p);
- return kmem_start;
- }
- vga_writew(0x55AA, p);
- if (vga_readw(p) != 0x55AA) {
- vga_writew(saved, p);
- return kmem_start;
- }
- vga_writew(saved, p);
-
vga_video_num_lines = ORIG_VIDEO_LINES;
vga_video_num_columns = ORIG_VIDEO_COLS;
vga_video_size_row = 2 * ORIG_VIDEO_COLS;
@@ -327,6 +309,24 @@ __initfunc(static unsigned long vgacon_startup(unsigned long kmem_start,
}
}
+ /*
+ * Find out if there is a graphics card present.
+ * Are there smarter methods around?
+ */
+ p = (unsigned short *)vga_video_mem_base;
+ saved = vga_readw(p);
+ vga_writew(0xAA55, p);
+ if (vga_readw(p) != 0xAA55) {
+ vga_writew(saved, p);
+ return kmem_start;
+ }
+ vga_writew(0x55AA, p);
+ if (vga_readw(p) != 0x55AA) {
+ vga_writew(saved, p);
+ return kmem_start;
+ }
+ vga_writew(saved, p);
+
vga_hardscroll_enabled = (vga_hardscroll_disabled_by_init ? 0 :
(vga_video_type == VIDEO_TYPE_EGAC
|| vga_video_type == VIDEO_TYPE_VGAC
@@ -358,22 +358,21 @@ static void vgacon_init(struct vc_data *conp)
conp->vc_can_do_color = vga_can_do_color;
}
-static int vgacon_deinit(struct vc_data *conp)
+static void vgacon_deinit(struct vc_data *conp)
{
- return 0;
}
/* ====================================================================== */
-static int vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width)
+static void vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
+ int width)
{
int rows;
unsigned long dest;
if (console_blanked)
- return 0;
+ return;
dest = vga_video_mem_base + sy*vga_video_size_row + sx*2;
if (sx == 0 && width == vga_video_num_columns)
@@ -381,41 +380,38 @@ static int vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
else
for (rows = height; rows-- ; dest += vga_video_size_row)
vga_memsetw((void *)dest, conp->vc_video_erase_char, width);
- return 0;
}
-static int vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+static void vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos)
{
- u_short *p;
+ u16 *p;
if (console_blanked)
- return 0;
+ return;
- p = (u_short *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2);
+ p = (u16 *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2);
vga_writew(conp->vc_attr << 8 | c, p);
- return 0;
}
-static int vgacon_putcs(struct vc_data *conp, const char *s, int count,
- int ypos, int xpos)
+static void vgacon_putcs(struct vc_data *conp, const char *s, int count,
+ int ypos, int xpos)
{
- u_short *p;
- u_short sattr;
+ u16 *p;
+ u16 sattr;
if (console_blanked)
- return 0;
+ return;
- p = (u_short *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2);
+ p = (u16 *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2);
sattr = conp->vc_attr << 8;
while (count--)
vga_writew(sattr | *s++, p++);
- return 0;
}
-static int vgacon_cursor(struct vc_data *conp, int mode)
+static void vgacon_cursor(struct vc_data *conp, int mode)
{
switch (mode) {
case CM_ERASE:
@@ -427,14 +423,14 @@ static int vgacon_cursor(struct vc_data *conp, int mode)
write_vga(14, conp->vc_y*vga_video_num_columns+conp->vc_x);
break;
}
- return 0;
}
-static int vgacon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+static void vgacon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count)
{
if (console_blanked)
- return 0;
+ return;
vgacon_cursor(conp, CM_ERASE);
@@ -469,19 +465,17 @@ static int vgacon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
vgacon_clear(conp, 0, t, conp->vc_rows, count);
break;
}
-
- return 0;
}
-static int vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width)
+static void vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+ int height, int width)
{
unsigned long src, dst;
int rows;
if (console_blanked)
- return 0;
+ return;
if (sx == 0 && dx == 0 && width == vga_video_num_columns) {
src = vga_video_mem_base + sy * vga_video_size_row;
@@ -505,7 +499,6 @@ static int vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
dst -= vga_video_size_row;
}
}
- return 0;
}
@@ -522,7 +515,7 @@ static int vgacon_blank(int blank)
return 0;
} else {
/* Tell console.c that it has to restore the screen itself */
- return(1);
+ return 1;
}
return 0;
}
@@ -564,6 +557,11 @@ static int vgacon_scrolldelta(int lines)
return -ENOSYS;
}
+static int vgacon_set_mode(struct vc_data *conp, int mode)
+{
+ return -ENOSYS;
+}
+
__initfunc(static int vgacon_show_logo( void ))
{
@@ -587,5 +585,5 @@ struct consw vga_con = {
vgacon_startup, vgacon_init, vgacon_deinit, vgacon_clear, vgacon_putc,
vgacon_putcs, vgacon_cursor, vgacon_scroll, vgacon_bmove, vgacon_switch,
vgacon_blank, vgacon_get_font, vgacon_set_font, vgacon_set_palette,
- vgacon_scrolldelta
+ vgacon_scrolldelta, vgacon_set_mode
};
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
new file mode 100644
index 000000000..d08e4a722
--- /dev/null
+++ b/drivers/video/virgefb.c
@@ -0,0 +1,1190 @@
+/*
+ * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device
+ *
+ * Copyright (C) 1997 André Heynatz
+ *
+ *
+ * This file is based on the CyberVision frame buffer device (cyberfb.c):
+ *
+ * Copyright (C) 1996 Martin Apel
+ * Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+#undef VIRGEFBDEBUG
+
+#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/zorro.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+
+#include "s3blit.h"
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+
+
+#ifdef VIRGEFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+#if 1
+#define vgawb_3d(reg,dat) \
+ (*((unsigned char *)(CyberVGARegs + (reg ^ 3))) = dat)
+#define vgaww_3d(reg,dat) \
+ (*((unsigned word *)(CyberVGARegs + (reg ^ 2))) = swab16(dat))
+#define vgawl_3d(reg,dat) \
+ (*((unsigned long *)(CyberVGARegs + reg)) = swab32(dat))
+#else
+ /*
+ * Dunno why this doesn't work at the moment - we'll have to look at
+ * it later.
+ */
+#define vgawb_3d(reg,dat) \
+ (*((unsigned char *)(CyberRegs + 0x8000 + reg)) = dat)
+#define vgaww_3d(reg,dat) \
+ (*((unsigned word *)(CyberRegs + 0x8000 + reg)) = dat)
+#define vgawl_3d(reg,dat) \
+ (*((unsigned long *)(CyberRegs + 0x8000 + reg)) = dat)
+#endif
+
+ /*
+ * We asume P5 mapped the big-endian version of these registers.
+ */
+#define wb_3d(reg,dat) \
+ (*((unsigned char volatile *)(CyberRegs + reg)) = dat)
+#define ww_3d(reg,dat) \
+ (*((unsigned word volatile *)(CyberRegs + reg)) = dat)
+#define wl_3d(reg,dat) \
+ (*((unsigned long volatile *)(CyberRegs + reg)) = dat)
+
+#define rl_3d(reg) \
+ (*((unsigned long volatile *)(CyberRegs + reg)))
+
+
+
+
+
+
+struct virgefb_par {
+ int xres;
+ int yres;
+ int bpp;
+};
+
+static struct virgefb_par current_par;
+
+static int current_par_valid = 0;
+static int currcon = 0;
+
+static struct display disp;
+static struct fb_info fb_info;
+
+
+/*
+ * Switch for Chipset Independency
+ */
+
+static struct fb_hwswitch {
+
+ /* Initialisation */
+
+ int (*init)(void);
+
+ /* Display Control */
+
+ int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par);
+ int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
+ int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
+ int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+ int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+ void (*blank)(int blank);
+} *fbhw;
+
+
+/*
+ * Frame Buffer Name
+ */
+
+static char virgefb_name[16] = "Cybervision/3D";
+
+
+/*
+ * Cybervision Graphics Board
+ */
+
+#define VIRGE8_WIDTH 1152
+#define VIRGE8_HEIGHT 886
+#define VIRGE8_PIXCLOCK 12500 /* ++Geert: Just a guess */
+
+#if 0
+#define VIRGE16_WIDTH 800
+#define VIRGE16_HEIGHT 600
+#endif
+#define VIRGE16_PIXCLOCK 25000 /* ++Geert: Just a guess */
+
+
+static unsigned int CyberKey = 0;
+static unsigned char Cyber_colour_table [256][4];
+static unsigned long CyberMem;
+static unsigned long CyberSize;
+static volatile char *CyberRegs;
+static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+
+
+/*
+ * Predefined Video Modes
+ */
+
+static struct fb_videomode virgefb_predefined[] __initdata = {
+ {
+ "640x480-8", { /* Cybervision 8 bpp */
+ 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, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "800x600-8", { /* Cybervision 8 bpp */
+ 800, 600, 800, 600, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1024x768-8", { /* Cybervision 8 bpp */
+ 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, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1152x886-8", { /* Cybervision 8 bpp */
+ 1152, 886, 1152, 886, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1280x1024-8", { /* Cybervision 8 bpp */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "1600x1200-8", { /* Cybervision 8 bpp */
+ 1600, 1200, 1600, 1200, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }, {
+ "800x600-16", { /* Cybervision 16 bpp */
+ 800, 600, 800, 600, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, 0, -1, -1, FB_ACCEL_NONE, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+ FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+ }
+ }
+};
+
+
+#define NUM_TOTAL_MODES arraysize(virgefb_predefined)
+
+
+static int Cyberfb_inverse = 0;
+#if 0
+static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */
+static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */
+#endif
+
+/*
+ * Some default modes
+ */
+
+#define VIRGE8_DEFMODE (0)
+#define VIRGE16_DEFMODE (6)
+
+static struct fb_var_screeninfo virgefb_default;
+
+
+/*
+ * Interface used by the world
+ */
+
+void virgefb_setup(char *options, int *ints);
+
+static int virgefb_open(struct fb_info *info);
+static int virgefb_release(struct fb_info *info);
+static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, struct
+fb_info *info);
+static int virgefb_get_var(struct fb_var_screeninfo *var, int con, struct
+fb_info *info);
+static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct
+fb_info *info);
+static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int virgefb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int virgefb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+
+
+/*
+ * Interface to the low level console driver
+ */
+
+unsigned long virgefb_init(unsigned long mem_start);
+static int Cyberfb_switch(int con, struct fb_info *info);
+static int Cyberfb_updatevar(int con, struct fb_info *info);
+static void Cyberfb_blank(int blank, struct fb_info *info);
+
+
+/*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static struct display_switch fbcon_virge8;
+#endif
+
+
+/*
+ * Hardware Specific Routines
+ */
+
+static int Cyber_init(void);
+static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
+ struct virgefb_par *par);
+static int Cyber_decode_var(struct fb_var_screeninfo *var,
+ struct virgefb_par *par);
+static int Cyber_encode_var(struct fb_var_screeninfo *var,
+ struct virgefb_par *par);
+static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+static void Cyber_blank(int blank);
+
+
+/*
+ * Internal routines
+ */
+
+static void virgefb_get_par(struct virgefb_par *par);
+static void virgefb_set_par(struct virgefb_par *par);
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static void do_install_cmap(int con, struct fb_info *info);
+static void virgefb_set_disp(int con, struct fb_info *info);
+static int get_video_mode(const char *name);
+
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+
+/*
+ * Initialization
+ *
+ * Set the default video mode for this chipset. If a video mode was
+ * specified on the command line, it will override the default mode.
+ */
+
+static int Cyber_init(void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ Cyber_colour_table [i][0] = i;
+ Cyber_colour_table [i][1] = i;
+ Cyber_colour_table [i][2] = i;
+ Cyber_colour_table [i][3] = 0;
+ }
+
+ /*
+ * Just clear the thing for the biggest mode.
+ *
+ * ++Andre, TODO: determine size first, then clear all memory
+ * (the 3D penguin might need texture memory :-) )
+ */
+
+ memset ((char*)CyberMem, 0, 1600 * 1200);
+
+ /* Disable hardware cursor */
+ CyberSize = 0x00400000; /* 4 MB */
+
+ vgawb_3d(0x3c8, 255);
+ vgawb_3d(0x3c9, 56);
+ vgawb_3d(0x3c9, 100);
+ vgawb_3d(0x3c9, 160);
+
+ vgawb_3d(0x3c8, 254);
+ vgawb_3d(0x3c9, 0);
+ vgawb_3d(0x3c9, 0);
+ vgawb_3d(0x3c9, 0);
+
+ /* Disable hardware cursor */
+ vgawb_3d(S3_CRTC_ADR, S3_REG_LOCK2);
+ vgawb_3d(S3_CRTC_DATA, 0xa0);
+ vgawb_3d(S3_CRTC_ADR, S3_HGC_MODE);
+ vgawb_3d(S3_CRTC_DATA, 0x00);
+ vgawb_3d(S3_CRTC_ADR, S3_HWGC_DX);
+ vgawb_3d(S3_CRTC_DATA, 0x00);
+ vgawb_3d(S3_CRTC_ADR, S3_HWGC_DY);
+ vgawb_3d(S3_CRTC_DATA, 0x00);
+
+ return 0; /* TODO: hardware cursor for CV64/3D */
+}
+
+
+/*
+ * This function should fill in the `fix' structure based on the
+ * values in the `par' structure.
+ */
+
+static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
+ struct virgefb_par *par)
+{
+ int i;
+
+ strcpy(fix->id, virgefb_name);
+ fix->smem_start = (caddr_t)CyberMem;
+ fix->smem_len = CyberSize;
+ fix->mmio_start = (unsigned char *)CyberRegs;
+ fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ if (par->bpp == 8)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_DIRECTCOLOR;
+
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+ fix->line_length = 0;
+
+ for (i = 0; i < arraysize(fix->reserved); i++)
+ fix->reserved[i] = 0;
+
+ return(0);
+}
+
+
+/*
+ * Get the video params out of `var'. If a value doesn't fit, round
+ * it up, if it's too big, return -EINVAL.
+ */
+
+static int Cyber_decode_var(struct fb_var_screeninfo *var,
+ struct virgefb_par *par)
+{
+#if 1
+ par->xres = var->xres;
+ par->yres = var->yres;
+ par->bpp = var->bits_per_pixel;
+#else
+ if (Cyberfb_Cyber8) {
+ par->xres = VIRGE8_WIDTH;
+ par->yres = VIRGE8_HEIGHT;
+ par->bpp = 8;
+ } else {
+ par->xres = VIRGE16_WIDTH;
+ par->yres = VIRGE16_HEIGHT;
+ par->bpp = 16;
+ }
+#endif
+ return(0);
+}
+
+
+/*
+ * Fill the `var' structure based on the values in `par' and maybe
+ * other values read out of the hardware.
+ */
+
+static int Cyber_encode_var(struct fb_var_screeninfo *var,
+ struct virgefb_par *par)
+{
+ int i;
+
+ var->xres = par->xres;
+ var->yres = par->yres;
+ var->xres_virtual = par->xres;
+ var->yres_virtual = par->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+
+ var->bits_per_pixel = par->bpp;
+ var->grayscale = 0;
+
+ if (par->bpp == 8) {
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->red.msb_right = 0;
+ var->blue = var->green = var->red;
+ } else {
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->red.msb_right = 0;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->green.msb_right = 0;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->blue.msb_right = 0;
+ }
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+
+ var->nonstd = 0;
+ var->activate = 0;
+
+ var->height = -1;
+ var->width = -1;
+
+ var->accel = FB_ACCEL_S3VIRGE;
+ DPRINTK("accel CV64/3D\n");
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ /* Dummy values */
+
+ if (par->bpp == 8)
+ var->pixclock = VIRGE8_PIXCLOCK;
+ else
+ var->pixclock = VIRGE16_PIXCLOCK;
+ var->sync = 0;
+ var->left_margin = 64;
+ var->right_margin = 96;
+ var->upper_margin = 35;
+ var->lower_margin = 12;
+ var->hsync_len = 112;
+ var->vsync_len = 2;
+
+ for (i = 0; i < arraysize(var->reserved); i++)
+ var->reserved[i] = 0;
+
+ return(0);
+}
+
+
+/*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ if (regno > 255)
+ {
+ return (1);
+ }
+
+ /*
+ * No colors on the CV3D yet.
+ */
+
+ vgawb_3d(0x3c8, (unsigned char) regno);
+ Cyber_colour_table [regno][0] = red & 0xff;
+ Cyber_colour_table [regno][1] = green & 0xff;
+ Cyber_colour_table [regno][2] = blue & 0xff;
+ Cyber_colour_table [regno][3] = transp;
+
+ vgawb_3d(0x3c9, ((red & 0xff) >> 2));
+ vgawb_3d(0x3c9, ((green & 0xff) >> 2));
+ vgawb_3d(0x3c9, ((blue & 0xff) >> 2));
+
+ return (0);
+}
+
+
+/*
+ * Read a single color register and split it into
+ * colors/transparent. Return != 0 for invalid regno.
+ */
+
+static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info)
+{
+ if (regno >= 256)
+ return (1);
+ *red = Cyber_colour_table [regno][0];
+ *green = Cyber_colour_table [regno][1];
+ *blue = Cyber_colour_table [regno][2];
+ *transp = Cyber_colour_table [regno][3];
+ return (0);
+}
+
+
+/*
+ * (Un)Blank the screen
+ */
+
+void Cyber_blank(int blank)
+{
+ int i;
+
+ if (blank)
+ {
+ for (i = 0; i < 256; i++)
+ {
+ vgawb_3d(0x3c8, (unsigned char) i);
+ vgawb_3d(0x3c9, 0);
+ vgawb_3d(0x3c9, 0);
+ vgawb_3d(0x3c9, 0);
+ }
+ }
+ else
+ {
+ for (i = 0; i < 256; i++)
+ {
+ vgawb_3d(0x3c8, (unsigned char) i);
+ vgawb_3d(0x3c9, Cyber_colour_table[i][0] >> 2);
+ vgawb_3d(0x3c9, Cyber_colour_table[i][1] >> 2);
+ vgawb_3d(0x3c9, Cyber_colour_table[i][2] >> 2);
+ }
+ }
+}
+
+/*
+ * CV3D low-level support
+ */
+
+#define Cyber3D_WaitQueue(v) { do { while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); } while (0); }
+
+static inline void Cyber3D_WaitBusy(void)
+{
+unsigned long status;
+
+ do {
+ status = rl_3d(0x8504);
+ } while (!(status & (1 << 13)));
+}
+
+#define S3V_BITBLT (0x0 << 27)
+#define S3V_RECTFILL (0x2 << 27)
+#define S3V_AUTOEXE 0x01
+#define S3V_HWCLIP 0x02
+#define S3V_DRAW 0x20
+#define S3V_DST_8BPP 0x00
+#define S3V_DST_16BPP 0x04
+#define S3V_DST_24BPP 0x08
+#define S3V_MONO_PAT 0x100
+
+#define S3V_BLT_COPY (0xcc<<17)
+#define S3V_BLT_CLEAR (0x00<<17)
+#define S3V_BLT_SET (0xff<<17)
+
+ /*
+ * BitBLT - Through the Plane
+ */
+
+static void Cyber3D_BitBLT(u_short curx, u_short cury, u_short destx,
+ u_short desty, u_short width, u_short height)
+{
+ unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_DST_8BPP;
+
+ blitcmd |= S3V_BLT_COPY;
+
+ /* Set drawing direction */
+ /* -Y, X maj, -X (default) */
+ if (curx > destx)
+ {
+ blitcmd |= (1 << 25); /* Drawing direction +X */
+ }
+ else
+ {
+ curx += (width - 1);
+ destx += (width - 1);
+ }
+
+ if (cury > desty)
+ {
+ blitcmd |= (1 << 26); /* Drawing direction +Y */
+ }
+ else
+ {
+ cury += (height - 1);
+ desty += (height - 1);
+ }
+
+ wl_3d(0xa4f4, 1); /* pattern fb color */
+
+ wl_3d(0xa4e8, ~0); /* mono pat 0 */
+ wl_3d(0xa4ec, ~0); /* mono pat 1 */
+
+ wl_3d(0xa504, ((width << 16) | height)); /* rwidth_height */
+ wl_3d(0xa508, ((curx << 16) | cury)); /* rsrc_xy */
+ wl_3d(0xa50c, ((destx << 16) | desty)); /* rdest_xy */
+
+ wl_3d(0xa500, blitcmd); /* GO! */
+
+ Cyber3D_WaitBusy();
+}
+
+/*
+ * Rectangle Fill Solid
+ */
+
+static void Cyber3D_RectFill(u_short x, u_short y, u_short width,
+ u_short height, u_short color)
+{
+ unsigned int tmp;
+ unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | S3V_DST_8BPP |
+ S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
+
+ tmp = color & 0xff;
+ wl_3d(0xa4f4, tmp);
+
+ wl_3d(0xa504, ((width << 16) | height)); /* rwidth_height */
+ wl_3d(0xa50c, ((x << 16) | y)); /* rdest_xy */
+
+ wl_3d(0xa500, blitcmd); /* GO! */
+ Cyber3D_WaitBusy();
+}
+
+
+/**************************************************************
+ * Move cursor to x, y
+ */
+static void Cyber_MoveCursor (u_short x, u_short y)
+{
+ printk("Yuck .... MoveCursor on a 3D\n");
+ return;
+}
+
+
+/* -------------------- Interfaces to hardware functions -------------------- */
+
+
+static struct fb_hwswitch Cyber_switch = {
+ Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
+ Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
+};
+
+
+/* -------------------- Generic routines ------------------------------------ */
+
+
+/*
+ * Fill the hardware's `par' structure.
+ */
+
+static void virgefb_get_par(struct virgefb_par *par)
+{
+ if (current_par_valid)
+ {
+ *par = current_par;
+ }
+ else
+ {
+ fbhw->decode_var(&virgefb_default, par);
+ }
+}
+
+
+static void virgefb_set_par(struct virgefb_par *par)
+{
+ current_par = *par;
+ current_par_valid = 1;
+}
+
+
+static void virge_set_video(struct fb_var_screeninfo *var)
+{
+ /* Set clipping rectangle to current screen size */
+
+ unsigned int clip;
+
+ clip = ((0 << 16) | (var->xres - 1));
+ wl_3d(0xa4dc, clip);
+ clip = ((0 << 16) | (var->yres - 1));
+ wl_3d(0xa4e0, clip);
+}
+
+
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+ int err, activate;
+ struct virgefb_par par;
+
+ if ((err = fbhw->decode_var(var, &par)))
+ return(err);
+ activate = var->activate;
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
+ virgefb_set_par(&par);
+ fbhw->encode_var(var, &par);
+ var->activate = activate;
+
+ virge_set_video(var);
+ 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,
+ fbhw->setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, fbhw->setcolreg, info);
+}
+
+
+/*
+ * Open/Release the frame buffer device
+ */
+
+static int virgefb_open(struct fb_info *info)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int virgefb_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+
+/*
+ * Get the Fixed Part of the Display
+ */
+
+static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct virgefb_par par;
+ int error = 0;
+
+ if (con == -1)
+ virgefb_get_par(&par);
+ else
+ error = fbhw->decode_var(&fb_display[con].var, &par);
+ return(error ? error : fbhw->encode_fix(fix, &par));
+}
+
+
+/*
+ * Get the User Defined Part of the Display
+ */
+
+static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct virgefb_par par;
+ int error = 0;
+
+ if (con == -1)
+ {
+ virgefb_get_par(&par);
+ error = fbhw->encode_var(var, &par);
+ disp.var = *var; /* ++Andre: don't know if this is the right place */
+ }
+ else
+ {
+ *var = fb_display[con].var;
+ }
+
+ return(error);
+}
+
+
+static void virgefb_set_disp(int con, struct fb_info *info)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ virgefb_get_fix(&fix, con, info);
+ if (con == -1)
+ con = 0;
+ display->screen_base = (u_char *)fix.smem_start;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->can_soft_blank = 1;
+ display->inverse = Cyberfb_inverse;
+ switch (display->var.bits_per_pixel) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_virge8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
+}
+
+
+/*
+ * Set the User Defined Part of the Display
+ */
+
+static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+
+ if ((err = do_fb_set_var(var, con == currcon)))
+ return(err);
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ oldxres = fb_display[con].var.xres;
+ oldyres = fb_display[con].var.yres;
+ oldvxres = fb_display[con].var.xres_virtual;
+ oldvyres = fb_display[con].var.yres_virtual;
+ oldbpp = fb_display[con].var.bits_per_pixel;
+ fb_display[con].var = *var;
+ if (oldxres != var->xres || oldyres != var->yres ||
+ oldvxres != var->xres_virtual ||
+ oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel) {
+ virgefb_set_disp(con, info);
+ (*fb_info.changevar)(con);
+ fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
+ do_install_cmap(con, info);
+ }
+ }
+ var->activate = 0;
+ return(0);
+}
+
+
+/*
+ * Get the Colormap
+ */
+
+static int virgefb_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, fbhw->getcolreg, info));
+ 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);
+ return(0);
+}
+
+
+/*
+ * Set the Colormap
+ */
+
+static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ 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)))
+ return(err);
+ }
+ if (con == currcon) /* current console? */
+ return(fb_set_cmap(cmap, &fb_display[con].var,
+ kspc, fbhw->setcolreg, info));
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return(0);
+}
+
+
+/*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+
+static int virgefb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ return(-EINVAL);
+}
+
+
+/*
+ * Cybervision Frame Buffer Specific ioctls
+ */
+
+static int virgefb_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg, int con, struct fb_info *info)
+{
+ return(-EINVAL);
+}
+
+
+static struct fb_ops virgefb_ops = {
+ virgefb_open, virgefb_release, virgefb_get_fix, virgefb_get_var,
+ virgefb_set_var, virgefb_get_cmap, virgefb_set_cmap,
+ virgefb_pan_display, NULL, virgefb_ioctl
+};
+
+
+__initfunc(void virgefb_setup(char *options, int *ints))
+{
+ char *this_opt;
+
+ fb_info.fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
+ if (!strcmp(this_opt, "inverse")) {
+ Cyberfb_inverse = 1;
+ fb_invert_cmaps();
+ } else if (!strncmp(this_opt, "font:", 5))
+ strcpy(fb_info.fontname, this_opt+5);
+ else if (!strcmp (this_opt, "virge8")){
+ virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
+ }
+ else if (!strcmp (this_opt, "virge16")){
+ virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var;
+ }
+ else
+ get_video_mode(this_opt);
+
+ DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",virgefb_default.xres,
+ virgefb_default.yres,
+ virgefb_default.bits_per_pixel);
+}
+
+
+/*
+ * Initialization
+ */
+
+__initfunc(unsigned long virgefb_init(unsigned long mem_start))
+{
+ int err;
+ struct virgefb_par par;
+ unsigned long board_addr;
+ const struct ConfigDev *cd;
+
+ if (!(CyberKey = zorro_find(ZORRO_PROD_PHASE5_CYBERVISION64_3D, 0, 0)))
+ return mem_start;
+
+ cd = zorro_get_board (CyberKey);
+ zorro_config_board (CyberKey, 0);
+ board_addr = (unsigned long)cd->cd_BoardAddr;
+
+ /* This includes the video memory as well as the S3 register set */
+ if ((unsigned long)cd->cd_BoardAddr < 0x01000000)
+ {
+ /*
+ * Ok we got the board running in Z2 space.
+ */
+
+ CyberMem = ZTWO_VADDR(board_addr);
+ printk("CV3D detected running in Z2 mode ... not yet supported!\n");
+ return -ENODEV;
+ }
+ else
+ {
+ CyberVGARegs = kernel_map(board_addr +0x0c000000,
+ 0x00010000,
+ KERNELMAP_NOCACHE_SER,
+ &mem_start);
+ CyberRegs = (char *)kernel_map(board_addr +0x05000000,
+ 0x00010000,
+ KERNELMAP_NOCACHE_SER,
+ &mem_start);
+ CyberMem = kernel_map(board_addr + 0x04800000,
+ 0x00400000,
+ KERNELMAP_NOCACHE_SER,
+ &mem_start);
+ printk("CV3D detected running in Z3 mode\n");
+ }
+
+ fbhw = &Cyber_switch;
+
+ strcpy(fb_info.modename, virgefb_name);
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &virgefb_ops;
+ fb_info.disp = &disp;
+ fb_info.switch_con = &Cyberfb_switch;
+ fb_info.updatevar = &Cyberfb_updatevar;
+ fb_info.blank = &Cyberfb_blank;
+
+ err = register_framebuffer(&fb_info);
+ if (err < 0)
+ return mem_start;
+
+ fbhw->init();
+ fbhw->decode_var(&virgefb_default, &par);
+ fbhw->encode_var(&virgefb_default, &par);
+
+ do_fb_set_var(&virgefb_default, 1);
+ virgefb_get_var(&fb_display[0].var, -1, &fb_info);
+ virgefb_set_disp(-1, &fb_info);
+ do_install_cmap(0, &fb_info);
+
+ printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
+
+ /* TODO: This driver cannot be unloaded yet */
+ MOD_INC_USE_COUNT;
+
+ return mem_start;
+}
+
+
+static int Cyberfb_switch(int con, struct fb_info *info)
+{
+ /* 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,
+ fbhw->getcolreg, info);
+
+ do_fb_set_var(&fb_display[con].var, 1);
+ currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, info);
+ return(0);
+}
+
+
+/*
+ * Update the `var' structure (called by fbcon.c)
+ *
+ * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ * Since it's called by a kernel driver, no range checking is done.
+ */
+
+static int Cyberfb_updatevar(int con, struct fb_info *info)
+{
+ return(0);
+}
+
+
+/*
+ * Blank the display.
+ */
+
+static void Cyberfb_blank(int blank, struct fb_info *info)
+{
+ fbhw->blank(blank);
+}
+
+
+/*
+ * Get a Video Mode
+ */
+
+__initfunc(static int get_video_mode(const char *name))
+{
+ int i;
+
+ for (i = 0; i < NUM_TOTAL_MODES; i++) {
+ if (!strcmp(name, virgefb_predefined[i].name)) {
+ virgefb_default = virgefb_predefined[i].var;
+ return(i);
+ }
+ }
+ /* ++Andre: set virgefb default mode */
+ virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
+ return(0);
+}
+
+
+/*
+ * Text console acceleration
+ */
+
+#ifdef CONFIG_FBCON_CFB8
+static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width)
+{
+ sx *= 8; dx *= 8; width *= 8;
+ Cyber3D_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
+ (u_short)(dy*p->fontheight), (u_short)width,
+ (u_short)(height*p->fontheight));
+}
+
+static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
+{
+ unsigned char bg;
+
+ sx *= 8; width *= 8;
+ bg = attr_bgcol_ec(p,conp);
+ Cyber3D_RectFill((u_short)sx, (u_short)(sy*p->fontheight),
+ (u_short)width, (u_short)(height*p->fontheight),
+ (u_short)bg);
+}
+
+static struct display_switch fbcon_virge8 = {
+ fbcon_cfb8_setup, fbcon_virge8_bmove, fbcon_virge8_clear, fbcon_cfb8_putc,
+ fbcon_cfb8_putcs, fbcon_cfb8_revc
+};
+#endif
+
+
+#ifdef MODULE
+int init_module(void)
+{
+ return(virgefb_init(NULL));
+}
+
+void cleanup_module(void)
+{
+ /* Not reached because the usecount will never be
+ decremented to zero */
+ unregister_framebuffer(&fb_info);
+ /* TODO: clean up ... */
+}
+#endif /* MODULE */