diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
commit | 4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch) | |
tree | cddb50a81d7d1a628cc400519162080c6d87868e /drivers | |
parent | 36ea5120664550fae6d31f1c6f695e4f8975cb06 (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')
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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; #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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 = ¤tpar; + struct amifb_par *par = ¤tpar; 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 *)¤t_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 *)¤t_par, (void *)arg, - sizeof(struct atari_fb_par))) + sizeof(struct atafb_par))) return -EFAULT; - atari_fb_set_par(¤t_par); + atafb_set_par(¤t_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 = ¤t_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(¤t_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 */ |