2003-03-09 03:42:48

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3

This is the patchset to support NEC PC-9800 subarchitecture
against 2.5.64-ac3.

You can download archived patchset from URL bellow.
http://downloads.sourceforge.jp/linux98/2575/linux98-2.5.64-ac3.patch.tar.bz2
Patchset against vanilla 2.5.64 is also available.
http://downloads.sourceforge.jp/linux98/2574/linux98-2.5.64.patch.tar.bz2

Comments and test reports are wellcome.

Description:
o boot98-update.patch (1/20)
Updates arch/i386/boot98/* in 2.5.64-ac3.
o char_device-update.patch (2/20)
Updates drivers/char/* in 2.5.64-ac3.
o console.patch (3/20)
PC98 Standard console support (without japanese kanji character).
o core-misc.patch (4/20)
Small patches for PC98 support core.
o core-update.patch (5/20)
Updates PC98 core files in 2.5.64-ac3.
o dma.patch (6/20)
DMA support for PC98.
o ide.patch (7/20)
PC98 standard IDE I/F support.
o input-update.patch (8/20)
Updates drivers/input/* in 2.5.64-ac3.
o kanji.patch (9/20)
japanese kanji character support for PC98 console.
o kconfig.patch (10/20)
Add selection for CONFIG_X86_PC9800.
o network_card.patch (11/20)
C-bus(PC98's legacy bus like ISA) network cards support.
o parport.patch (12/20)
Parallel port support.
o pci.patch (13/20)
Small changes for PCI support.
o pcmcia.patch (14/20)
Small change for PCMCIA (16bits) support.
o rtc.patch (15/20)
Support RTC for PC98, using mach-* scheme.
o scsi.patch (16/20)
SCSI host adapter support.
o serial.patch (17/20)
Serial port support for PC98.
o setup.patch (18/20)
Support difference of IO port/memory address, using mach-* scheme.
o smp.patch (19/20)
SMP support for PC98.
o timer.patch (20/20)
Support difference of timer, using mach-* scheme.

Regards,
Osamu Tomita <[email protected]>


2003-03-09 04:02:07

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (1/20) boot98 update

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (1/20)

Updates for files under arch/i386/boot98 directory.

Regards,
Osamu Tomita

diff -Nru linux-2.5.64-ac1/arch/i386/boot98/Makefile linux98-2.5.64-ac1/arch/i386/boot98/Makefile
--- linux-2.5.64-ac1/arch/i386/boot98/Makefile 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.64-ac1/arch/i386/boot98/Makefile 2003-03-05 13:23:00.000000000 +0900
@@ -32,10 +32,6 @@

host-progs := tools/build

-# Default
-
-boot: bzImage
-
# ---------------------------------------------------------------------------

$(obj)/zImage: IMAGE_OFFSET := 0x1000

2003-03-09 04:06:19

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (4/20) misc core

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (4/20)

Small patches for PC98 core support.
io.h: Using ioport 0x5f to wait is recomended by vendor.
irq.h: Cascade IRQ is 7 for PC98 not 2.
pc98*.h: Add macros to access BIOS parameters.
kernel.h: define "pc98" for other files.
I think these are small and clean.

Regards,
Osamu Tomita

diff -Nru linux/include/asm-i386/io.h linux98/include/asm-i386/io.h
--- linux/include/asm-i386/io.h 2002-10-12 13:22:45.000000000 +0900
+++ linux98/include/asm-i386/io.h 2002-10-12 19:25:19.000000000 +0900
@@ -27,6 +27,8 @@
* Linus
*/

+#include <linux/config.h>
+
/*
* Bit simplified and optimized by Jan Hubicka
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
@@ -288,7 +290,11 @@
#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO "jmp 1f; 1: jmp 1f; 1:"
#else
+#ifdef CONFIG_X86_PC9800
+#define __SLOW_DOWN_IO "outb %%al,$0x5f;"
+#else
#define __SLOW_DOWN_IO "outb %%al,$0x80;"
+#endif
#endif

static inline void slow_down_io(void) {
diff -Nru linux/include/asm-i386/irq.h linux98/include/asm-i386/irq.h
--- linux/include/asm-i386/irq.h 2002-09-21 00:20:16.000000000 +0900
+++ linux98/include/asm-i386/irq.h 2002-09-21 07:17:56.000000000 +0900
@@ -17,7 +17,11 @@

static __inline__ int irq_cannonicalize(int irq)
{
+#ifdef CONFIG_X86_PC9800
+ return ((irq == 7) ? 11 : irq);
+#else
return ((irq == 2) ? 9 : irq);
+#endif
}

extern void disable_irq(unsigned int);
diff -Nru linux/include/asm-i386/pc9800.h linux98/include/asm-i386/pc9800.h
--- linux/include/asm-i386/pc9800.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/pc9800.h 2002-08-17 21:50:18.000000000 +0900
@@ -0,0 +1,27 @@
+/*
+ * PC-9800 machine types.
+ *
+ * Copyright (C) 1999 TAKAI Kosuke <[email protected]>
+ * (Linux/98 Project)
+ */
+
+#ifndef _ASM_PC9800_H_
+#define _ASM_PC9800_H_
+
+#include <asm/pc9800_sca.h>
+#include <asm/types.h>
+
+#define __PC9800SCA(type, pa) (*(type *) phys_to_virt(pa))
+#define __PC9800SCA_TEST_BIT(pa, n) \
+ ((__PC9800SCA(u8, pa) & (1U << (n))) != 0)
+
+#define PC9800_HIGHRESO_P() __PC9800SCA_TEST_BIT(PC9800SCA_BIOS_FLAG, 3)
+#define PC9800_8MHz_P() __PC9800SCA_TEST_BIT(PC9800SCA_BIOS_FLAG, 7)
+
+ /* 0x2198 is 98 21 on memory... */
+#define PC9800_9821_P() (__PC9800SCA(u16, PC9821SCA_ROM_ID) == 0x2198)
+
+/* Note PC9821_...() are valid only when PC9800_9821_P() was true. */
+#define PC9821_IDEIF_DOUBLE_P() __PC9800SCA_TEST_BIT(PC9821SCA_ROM_FLAG4, 4)
+
+#endif
diff -Nru linux/include/linux/kernel.h linux98/include/linux/kernel.h
--- linux/include/linux/kernel.h 2003-01-14 14:58:03.000000000 +0900
+++ linux98/include/linux/kernel.h 2003-01-14 23:11:42.000000000 +0900
@@ -224,4 +224,10 @@
#define __FUNCTION__ (__func__)
#endif

+#ifdef CONFIG_X86_PC9800
+#define pc98 1
+#else
+#define pc98 0
+#endif
+
#endif

2003-03-09 04:05:23

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (3/20) console

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (3/20)

PC98 Standard console support (without japanese kanji character).
Text mode video card on PC98 is useing 2bytes of VRAM by 1 character to
support japanese kanji character. VRAM for attributes is mapped another
address (+0x2000).
Character codes 0x80-0xff are diffrent with standerd PC.

Regards,
Osamu Tomita


diff -Nru linux-2.5.60/drivers/char/Makefile linux98-2.5.60/drivers/char/Makefile
--- linux-2.5.60/drivers/char/Makefile 2003-02-18 11:10:03.000000000 +0900
+++ linux98-2.5.60/drivers/char/Makefile 2003-02-20 09:16:30.000000000 +0900
@@ -5,7 +5,11 @@
#
# This file contains the font map for the default (hardware) font
#
+ifeq ($(CONFIG_X86_PC9800),y)
+FONTMAPFILE = pc9800.uni
+else
FONTMAPFILE = cp437.uni
+endif

obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o

diff -Nru linux/drivers/char/console_macros.h linux98/drivers/char/console_macros.h
--- linux/drivers/char/console_macros.h Sat Oct 19 13:01:17 2002
+++ linux98/drivers/char/console_macros.h Mon Oct 28 16:53:39 2002
@@ -55,6 +55,10 @@
#define s_reverse (vc_cons[currcons].d->vc_s_reverse)
#define ulcolor (vc_cons[currcons].d->vc_ulcolor)
#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
+#define def_attr (vc_cons[currcons].d->vc_def_attr)
+#define ul_attr (vc_cons[currcons].d->vc_ul_attr)
+#define half_attr (vc_cons[currcons].d->vc_half_attr)
+#define bold_attr (vc_cons[currcons].d->vc_bold_attr)
#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
#define palette (vc_cons[currcons].d->vc_palette)
#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)
diff -Nru linux/drivers/char/console_pc9800.h linux98/drivers/char/console_pc9800.h
--- linux/drivers/char/console_pc9800.h Thu Jan 1 09:00:00 1970
+++ linux98/drivers/char/console_pc9800.h Mon Oct 28 11:48:10 2002
@@ -0,0 +1,14 @@
+#ifndef __CONSOLE_PC9800_H
+#define __CONSOLE_PC9800_H
+
+#define BLANK_ATTR 0x00E1
+
+#define JIS_CODE 0x01
+#define EUC_CODE 0x00
+#define SJIS_CODE 0x02
+#define JIS_CODE_ASCII 0x00
+#define JIS_CODE_78 0x01
+#define JIS_CODE_83 0x02
+#define JIS_CODE_90 0x03
+
+#endif /* __CONSOLE_PC9800_H */
diff -Nru linux/drivers/char/consolemap.c linux98/drivers/char/consolemap.c
--- linux/drivers/char/consolemap.c 2002-12-10 11:46:14.000000000 +0900
+++ linux98/drivers/char/consolemap.c 2002-12-16 11:27:23.000000000 +0900
@@ -23,7 +23,7 @@
#include <linux/consolemap.h>
#include <linux/vt_kern.h>

-static unsigned short translations[][256] = {
+unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
@@ -163,7 +163,59 @@
0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
- }
+ },
+ /* JIS X0201 mapped to Unicode */
+ /* code marked with ** is not defined in JIS X0201.
+ So 0x00 - 0x1f are mapped to same to Laten1,
+ and others are mapped to PC-9800 internal font# directry */
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+/* ** ** ** ** ** ** ** ** */
+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+/* ** ** ** ** ** ** ** ** */
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+/* ** ** ** ** ** ** ** ** */
+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+/* ** ** ** ** ** ** ** ** */
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x00a5, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x203e, 0xf07f,
+/* ** */
+ 0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
+/* ** ** ** ** ** ** ** ** */
+ 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
+/* ** ** ** ** ** ** ** ** */
+ 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
+/* ** ** ** ** ** ** ** ** */
+ 0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
+/* ** ** ** ** ** ** ** ** */
+ 0xf0a0, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67,
+/* ** */
+ 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
+ 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77,
+ 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f,
+ 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87,
+ 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f,
+ 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97,
+ 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f,
+ 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
+/* ** ** ** ** ** ** ** ** */
+ 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
+/* ** ** ** ** ** ** ** ** */
+ 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
+/* ** ** ** ** ** ** ** ** */
+ 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
+/* ** ** ** ** ** ** ** ** */
+ },
};

/* The standard kernel character-to-font mappings are not invertible
@@ -177,7 +229,7 @@
u16 **uni_pgdir[32];
unsigned long refcount;
unsigned long sum;
- unsigned char *inverse_translations[4];
+ unsigned char *inverse_translations[5];
int readonly;
};

diff -Nru linux/drivers/char/pc9800.uni linux98/drivers/char/pc9800.uni
--- linux/drivers/char/pc9800.uni Thu Jan 1 09:00:00 1970
+++ linux98/drivers/char/pc9800.uni Fri Aug 17 21:50:17 2001
@@ -0,0 +1,260 @@
+#
+# Unicode table for PC-9800 console.
+# Copyright (C) 1998,2001 Linux/98 project (project Seraphim)
+# Kyoto University Microcomputer Club (KMC).
+#
+
+# Kore ha unicode wo 98 no ROM no font ni taio saseru tame no
+# map desu.
+
+# Characters for control codes.
+# PC-9800 uses 2-char sequences while Unicode uses 3-char for some codes.
+0x00
+0x01 U+2401 # SH / SOH
+0x02 U+2402 # SX / SOX
+0x03 U+2403 # EX / ETX
+0x04 U+2404 # ET / EOT
+0x05 U+2405 # EQ / ENQ
+0x06 U+2406 # AK / ACK
+0x07 U+2407 # BL / BEL
+0x08 U+2408 # BS
+0x09 U+2409 # HT
+0x0a U+240a # LF
+0x0b # HM / (VT)
+0x0c # CL / (FF)
+0x0d U+240d # CR
+0x0e # SO / (SS)
+0x0f U+240f # SI
+0x10 U+2410 # DE / DLE
+0x11 U+2411 # D1 / DC1
+0x12 U+2412 # D2 / DC2
+0x13 U+2413 # D3 / DC3
+0x14 U+2414 # D4 / DC4
+0x15 U+2415 # NK / NAK
+0x16 U+2416 # SN / SYN
+0x17 U+2417 # EB / ETB
+0x18 U+2418 # CN / CAN
+0x19 U+2419 # EM
+0x1a U+241a # SB / SUB
+0x1b U+241b # EC / ESC
+
+# arrow
+0x1c U+2192 U+ffeb # right
+0x1d U+2190 U+ffe9 # left
+0x1e U+2191 U+ffea # up
+0x1f U+2193 U+ffec # down
+
+#
+# The ASCII range is identity-mapped, but some of the characters also
+# have to act as substitutes, especially the upper-case characters.
+#
+0x20 U+0020
+0x21 U+0021
+# U+00a8 is Latin-1 Supplement DIAELESIS.
+0x22 U+0022 U+00a8
+0x23 U+0023
+0x24 U+0024
+0x25 U+0025
+0x26 U+0026
+0x26 U+2019 # General Punctuation "RIGHT SINGLE QUOTATION MARK"
+0x27 U+0027 U+2032
+0x28 U+0028
+0x29 U+0029
+0x2a U+002a
+0x2b U+002b
+# U+00b8 is Latin-1 Supplement CEDILLA.
+0x2c U+002c U+00b8
+# U+00b8 is Latin-1 Supplement SOFT HYPHEN.
+0x2d U+002d U+00ad
+0x2d U+2212 # Mathematical Operators "MINUS SIGN"
+0x2e U+002e
+0x2f U+002f
+0x2f U+2044 # General Punctuation "FRACTION SLASH"
+0x2f U+2215 # Mathematical Operators "DIVISION SLASH"
+0x30 U+0030
+0x31 U+0031
+0x32 U+0032
+0x33 U+0033
+0x34 U+0034
+0x35 U+0035
+0x36 U+0036
+0x37 U+0037
+0x38 U+0038
+0x39 U+0039
+0x3a U+003a
+0x3a U+003a # Mathematical Operators "RATIO"
+0x3b U+003b
+0x3c U+003c
+0x3d U+003d
+0x3e U+003e
+0x3f U+003f
+0x40 U+0040
+0x41 U+0041 U+00c0 U+00c1 U+00c2 U+00c3
+0x42 U+0042
+# U+00a9 is Latin-1 Supplement COPYRIGHT SIGN.
+0x43 U+0043 U+00a9
+0x44 U+0044
+0x45 U+0045 U+00c8 U+00ca U+00cb
+0x46 U+0046
+0x47 U+0047
+0x48 U+0048
+0x49 U+0049 U+00cc U+00cd U+00ce U+00cf
+0x4a U+004a
+# U+212a: Letterlike Symbols "KELVIN SIGN"
+0x4b U+004b U+212a
+0x4c U+004c
+0x4d U+004d
+0x4e U+004e
+0x4f U+004f U+00d2 U+00d3 U+00d4 U+00d5
+0x50 U+0050
+0x51 U+0051
+# U+00ae: Latin-1 Supplement "REGISTERED SIGN"
+0x52 U+0052 U+00ae
+0x53 U+0053
+0x54 U+0054
+0x55 U+0055 U+00d9 U+00da U+00db
+0x56 U+0056
+0x57 U+0057
+0x58 U+0058
+0x59 U+0059 U+00dd
+0x5a U+005a
+0x5b U+005b
+0x5c U+00a5 # Latin-1 Supplement "YEN SIGN"
+0x5d U+005d
+0x5e U+005e
+0x5f U+005f U+f804
+0x60 U+0060 U+2035
+0x61 U+0061 U+00e3
+0x62 U+0062
+0x63 U+0063
+0x64 U+0064
+0x65 U+0065
+0x66 U+0066
+0x67 U+0067
+0x68 U+0068
+0x69 U+0069
+0x6a U+006a
+0x6b U+006b
+0x6c U+006c
+0x6d U+006d
+0x6e U+006e
+0x6f U+006f U+00f5
+0x70 U+0070
+0x71 U+0071
+0x72 U+0072
+0x73 U+0073
+0x74 U+0074
+0x75 U+0075
+0x76 U+0076
+0x77 U+0077
+0x78 U+0078 U+00d7
+0x79 U+0079 U+00fd
+0x7a U+007a
+0x7b U+007b
+# U+00a6: Latin-1 Supplement "BROKEN (VERTICAL) BAR"
+0x7c U+007c U+00a6
+0x7d U+007d
+0x7e U+007e
+
+# kuhaku
+0x7f # U+2302
+
+# Block Elements.
+0x80 U+2581 # LOWER ONE EIGHTH BLOCK
+0x81 U+2582 # LOWER ONE QUARTER BLOCK
+0x82 U+2583 # LOWER THREE EIGHTHS BLOCK
+0x83 U+2584 # LOWER HALF BLOCK
+0x84 U+2585 # LOWER FIVE EIGHTHS BLOCK
+0x85 U+2586 # LOWER THREE QUARTERS BLOCK
+0x86 U+2587 # LOWER SEVEN EIGHTHS BLOCK
+0x87 U+2588 # FULL BLOCK
+0x88 U+258f # LEFT ONE EIGHTH BLOCK
+0x89 U+258e # LEFT ONE QUARTER BLOCK
+0x8a U+258d # LEFT THREE EIGHTHS BLOCK
+0x8b U+258c # LEFT HALF BLOCK
+0x8c U+258b # LEFT FIVE EIGHTHS BLOCK
+0x8d U+258a # LEFT THREE QUARTERS BLOCK
+0x8e U+2589 # LEFT SEVEN EIGHTHS BLOCK
+
+# Box Drawing.
+0x8f U+253c
+0x90 U+2534
+0x91 U+252c
+0x92 U+2524
+0x93 U+251c
+0x94 U+203e # General Punctuation "OVERLINE" (= "SPACING OVERSCORE")
+0x95 U+2500 # Box Drawing "BOX DRAWING LIGHT HORIZONTAL"
+0x96 U+2502 # Box Drawing "BOX DRAWING LIGHT VERTICAL"
+0x96 U+ffe8 # Halfwidth symbol variants "HALFWIDTH FORMS LIGHT VERTICAL"
+0x97 U+2595 # Block Elements "RIGHT ONE EIGHTH BLOCK"
+0x98 U+250c
+0x99 U+2510
+0x9a U+2514
+0x9b U+2518
+
+0x9c U+256d # "BOX DRAWING LIGHT ARC DOWN AND RIGHT"
+0x9d U+256e # "BOX DRAWING LIGHT ARC DOWN AND LEFT"
+0x9e U+2570 # "BOX DRAWING LIGHT ARC UP AND RIGHT"
+0x9f U+256f # "BOX DRAWING LIGHT ARC UP AND LEFT"
+
+0xa0 # another whitespace
+
+# Halfwidth CJK punctuation
+0xa1 - 0xa4 U+ff61 - U+ff64
+
+# Halfwidth Katakana variants
+0xa5 - 0xdf U+ff65 - U+ff9f
+0xa5 U+00b7 # Latin-1 Supplement "MIDDLE DOT"
+0xdf U+00b0 # Latin-1 Supplement "DEGREE SIGN"
+
+# Box Drawing
+0xe0 U+2550 # "BOX DRAWING DOUBLE HORIZONTAL"
+0xe1 U+255e # "BOX DRAWING VERTICAL SINGLE AND RIGHT DOUBLE"
+0xe2 U+256a # "BOX DRAWING VERTICAL SINGLE AND HORIZONTAL DOUBLE"
+0xe3 U+2561 # "BOX DRAWING VERTICAL SINGLE AND LEFT DOUBLE"
+
+# Geometric Shapes
+0xe4 U+25e2 # "BLACK LOWER RIGHT TRIANGLE"
+0xe5 U+25e3 # "BLACK LOWER LEFT TRIANGLE"
+0xe6 U+25e5 # "BLACK UPPER RIGHT TRIANGLE"
+0xe7 U+25e4 # "BLACK UPPER LEFT TRIANGLE"
+
+# Playing card symbols
+0xe8 U+2660 # "BLACK SPADE SUIT"
+0xe9 U+2665 # "BLACK HEART SUIT"
+0xea U+2666 # "BLACK DIAMOND SUIT"
+0xeb U+2663 # "BLACK CLUB SUIT"
+
+# Geometric Shapes
+0xec U+25cf # "BLACK CIRCLE"
+0xed U+25cb U+25ef # "WHITE CIRCLE", "LARGE CIRCLE"
+
+# Box Drawing
+0xee U+2571 # "BOX DRAWING LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT"
+0xef U+2572 # "BOX DRAWING LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT"
+0xf0 U+2573 # "BOX DRAWING LIGHT DIAGONAL CROSS"
+
+# CJK Unified Ideographs (XXX - should these be here?)
+0xf1 U+5186
+0xf2 U+5e74
+0xf3 U+6708
+0xf4 U+65e5
+0xf5 U+6642
+0xf6 U+5206
+0xf7 U+79d2
+
+# unassigned
+0xf8
+0xf9
+0xfa
+0xfb
+
+0xfc U+005c # "REVERSE SOLIDUS" / "BACKSLASH"
+0xfc U+2216 # Mathematical Operators "SET MINUS"
+
+# unassigned
+0xfd
+0xfe
+0xff
+
+# End of pc9800.uni
diff -Nru linux-2.5.64-ac1/drivers/char/vt.c linux98-2.5.64-ac1/drivers/char/vt.c
--- linux-2.5.64-ac1/drivers/char/vt.c 2003-03-07 08:52:02.000000000 +0900
+++ linux98-2.5.64-ac1/drivers/char/vt.c 2003-03-07 11:00:07.000000000 +0900
@@ -107,6 +107,10 @@

#include "console_macros.h"

+#ifdef CONFIG_X86_PC9800
+#include "console_pc9800.h"
+extern unsigned short translations[][256];
+#endif

const struct consw *conswitchp;

@@ -301,7 +305,7 @@
xx = nxx; yy = nyy;
}
for(;;) {
- u16 attrib = scr_readw(p) & 0xff00;
+ vram_char_t attrib = scr_readw(p) & 0xff00;
int startx = xx;
u16 *q = p;
while (xx < video_num_columns && count) {
@@ -387,6 +391,8 @@
{
attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
+ if (pc98 && decscnm)
+ video_erase_char |= 0x0400; /* reverse */
}

/* Note: inverting the screen twice should revert to the original state */
@@ -403,7 +409,7 @@
else {
u16 *q = p;
int cnt = count;
- u16 a;
+ vram_char_t a;

if (!can_do_color) {
while (cnt--) {
@@ -437,7 +443,7 @@
void complement_pos(int currcons, int offset)
{
static unsigned short *p;
- static unsigned short old;
+ static vram_char_t old;
static unsigned short oldx, oldy;

if (p) {
@@ -448,10 +454,15 @@
if (offset == -1)
p = NULL;
else {
- unsigned short new;
+ vram_char_t new;
p = screenpos(currcons, offset, 1);
old = scr_readw(p);
+#ifdef CONFIG_FB_EGC
+ new = (old & 0xff0000ff) | ((old & 0xf000) >> 4)
+ | ((old & 0xf00) << 4);
+#else
new = old ^ complement_mask;
+#endif
scr_writew(new, p);
if (DO_UPDATE) {
oldx = (offset >> 1) % video_num_columns;
@@ -510,7 +521,7 @@

static void add_softcursor(int currcons)
{
- int i = scr_readw((u16 *) pos);
+ vram_char_t i = scr_readw((u16 *) pos);
u32 type = cursor_type;

if (! (type & 0x10)) return;
@@ -646,8 +657,12 @@
complement_mask = 0;
can_do_color = 0;
sw->con_init(vc_cons[currcons].d, init);
- if (!complement_mask)
- complement_mask = can_do_color ? 0x7700 : 0x0800;
+ if (!complement_mask) {
+ if (pc98)
+ complement_mask = 0x0400;
+ else
+ complement_mask = can_do_color ? 0x7700 : 0x0800;
+ }
s_complement_mask = complement_mask;
video_size_row = video_num_columns<<1;
screenbuf_size = video_num_lines*video_size_row;
@@ -679,7 +694,7 @@
visual_init(currcons, 1);
if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
con_set_default_unimap(currcons);
- q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
+ q = (long)kmalloc(screenbuf_size + (pc98 ? screenbuf_size : 0), GFP_KERNEL);
if (!q) {
kfree((char *) p);
vc_cons[currcons].d = NULL;
@@ -736,7 +751,7 @@
if (err)
return err;

- newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER);
+ newscreen = (unsigned short *) kmalloc(new_screen_size + (pc98 ? new_screen_size : 0), GFP_USER);
if (!newscreen)
return -ENOMEM;

@@ -1261,6 +1276,10 @@
/* console_sem is held */
static void setterm_command(int currcons)
{
+ if (sw->con_setterm_command
+ && sw->con_setterm_command(vc_cons[currcons].d))
+ return;
+
switch(par[0]) {
case 1: /* set color for underline mode */
if (can_do_color && par[1] < 16) {
@@ -2427,9 +2446,17 @@
vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
}
- def_color = 0x07; /* white */
- ulcolor = 0x0f; /* bold white */
- halfcolor = 0x08; /* grey */
+ if (pc98) {
+ def_color = 0x07; /* white */
+ def_attr = 0xE1;
+ ul_attr = 0x08; /* underline */
+ half_attr = 0x00; /* ignore half color */
+ bold_attr = 0xC1; /* yellow */
+ } else {
+ def_color = 0x07; /* white */
+ ulcolor = 0x0f; /* bold white */
+ halfcolor = 0x08; /* grey */
+ }
init_waitqueue_head(&vt_cons[currcons]->paste_wait);
reset_terminal(currcons, do_clear);
}
@@ -2470,7 +2497,12 @@
vt_cons[currcons] = (struct vt_struct *)
alloc_bootmem(sizeof(struct vt_struct));
visual_init(currcons, 1);
+#if defined(CONFIG_X86_PC9800) || defined(CONFIG_FB)
+ screenbuf
+ = (unsigned short *) alloc_bootmem(screenbuf_size * 2);
+#else
screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
+#endif
kmalloced = 0;
vc_init(currcons, video_num_lines, video_num_columns,
currcons || !sw->con_save_screen);
@@ -2973,9 +3005,12 @@
/* used by selection */
u16 screen_glyph(int currcons, int offset)
{
- u16 w = scr_readw(screenpos(currcons, offset, 1));
+ vram_char_t w = scr_readw(screenpos(currcons, offset, 1));
u16 c = w & 0xff;

+ if (pc98)
+ return ((u16)(w >> 16) & 0xff00) | c;
+
if (w & hi_font_mask)
c |= 0x100;
return c;
@@ -3037,8 +3072,10 @@
EXPORT_SYMBOL(default_red);
EXPORT_SYMBOL(default_grn);
EXPORT_SYMBOL(default_blu);
+#ifndef CONFIG_X86_PC9800
EXPORT_SYMBOL(video_font_height);
EXPORT_SYMBOL(video_scan_lines);
+#endif
EXPORT_SYMBOL(vc_cons_allocated);
EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen);
diff -Nru linux/drivers/char/vt_ioctl.c linux98/drivers/char/vt_ioctl.c
--- linux/drivers/char/vt_ioctl.c 2002-12-10 11:46:13.000000000 +0900
+++ linux98/drivers/char/vt_ioctl.c 2002-12-16 13:15:34.000000000 +0900
@@ -63,9 +63,11 @@
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
#endif

+#ifndef CONFIG_X86_PC9800
unsigned int video_font_height;
unsigned int default_font_height;
unsigned int video_scan_lines;
+#endif

/*
* these are the valid i/o ports we're allowed to change. they map all the
@@ -637,6 +639,17 @@
return 0;
}

+#ifdef CONFIG_X86_PC9800
+ case VT_GDC_RESIZE:
+ {
+ if (!perm)
+ return -EPERM;
+/* con_adjust_height(0);*/
+ update_screen(console);
+ return 0;
+ }
+#endif
+
case VT_SETMODE:
{
struct vt_mode tmp;
@@ -830,7 +843,9 @@
__get_user(clin, &vtconsize->v_clin);
__get_user(vcol, &vtconsize->v_vcol);
__get_user(ccol, &vtconsize->v_ccol);
+#ifndef CONFIG_X86_PC9800
vlin = vlin ? vlin : video_scan_lines;
+#endif
if (clin) {
if (ll) {
if (ll != vlin/clin)
@@ -849,10 +864,12 @@
if (clin > 32)
return -EINVAL;

+#ifndef CONFIG_X86_PC9800
if (vlin)
video_scan_lines = vlin;
if (clin)
video_font_height = clin;
+#endif

for (i = 0; i < MAX_NR_CONSOLES; i++)
vc_resize(i, cc, ll);
@@ -1022,8 +1039,10 @@
vt_cons[new_console]->vt_mode.frsig = 0;
vt_cons[new_console]->vt_pid = -1;
vt_cons[new_console]->vt_newvt = -1;
+#ifndef CONFIG_X86_PC9800
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
reset_palette(new_console) ;
+#endif
}

/*
diff -Nru linux-2.5.59/drivers/video/console/Kconfig linux98-2.5.59/drivers/video/console/Kconfig
--- linux-2.5.59/drivers/video/console/Kconfig 2003-01-17 13:22:14.000000000 +0900
+++ linux98-2.5.59/drivers/video/console/Kconfig 2003-01-17 13:43:44.000000000 +0900
@@ -6,7 +6,7 @@

config VGA_CONSOLE
bool "VGA text console"
- depends on !ARCH_ACORN && !ARCH_EBSA110 || !4xx && !8xx
+ depends on !X86_PC9800 && !ARCH_ACORN && !ARCH_EBSA110 || !4xx && !8xx
help
Saying Y here will allow you to use Linux in text mode through a
display that complies with the generic VGA standard. Virtually
@@ -97,6 +97,18 @@
Say Y to build a console driver for Sun machines that uses the
terminal emulation built into their console PROMS.

+config GDC_CONSOLE
+ bool "PC-9800 GDC text console"
+ depends on X86_PC9800
+ default y
+ help
+ This enables support for PC-9800 standard text mode console.
+ If use NEC PC-9801/PC-9821, Say Y.
+
+config GDC_32BITACCESS
+ bool "Enable 32-bit access to text video RAM"
+ depends on GDC_CONSOLE
+
config DUMMY_CONSOLE
bool
depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y
diff -Nru linux/include/linux/console.h linux98/include/linux/console.h
--- linux/include/linux/console.h 2003-02-15 08:51:33.000000000 +0900
+++ linux98/include/linux/console.h 2003-02-20 09:47:41.000000000 +0900
@@ -17,6 +17,13 @@
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/spinlock.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_PC9800
+typedef __u32 vram_char_t;
+#else
+typedef __u16 vram_char_t;
+#endif

struct vc_data;
struct console_font_op;
@@ -32,7 +39,7 @@
void (*con_init)(struct vc_data *, int);
void (*con_deinit)(struct vc_data *);
void (*con_clear)(struct vc_data *, int, int, int, int);
- void (*con_putc)(struct vc_data *, int, int, int);
+ void (*con_putc)(struct vc_data *, int, vram_char_t, int);
void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
void (*con_cursor)(struct vc_data *, int);
int (*con_scroll)(struct vc_data *, int, int, int, int);
@@ -49,6 +56,7 @@
void (*con_invert_region)(struct vc_data *, u16 *, int);
u16 *(*con_screen_pos)(struct vc_data *, int);
unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
+ int (*con_setterm_command)(struct vc_data *);
};

extern const struct consw *conswitchp;
@@ -56,6 +64,7 @@
extern const struct consw dummy_con; /* dummy console buffer */
extern const struct consw fb_con; /* frame buffer based console */
extern const struct consw vga_con; /* VGA text console */
+extern const struct consw gdc_con; /* PC-9800 GDC text console */
extern const struct consw newport_con; /* SGI Newport console */
extern const struct consw prom_con; /* SPARC PROM console */

diff -Nru linux/include/linux/console_struct.h linux98/include/linux/console_struct.h
--- linux/include/linux/console_struct.h 2002-12-10 11:45:40.000000000 +0900
+++ linux98/include/linux/console_struct.h 2002-12-16 13:25:55.000000000 +0900
@@ -9,6 +9,9 @@
* to achieve effects such as fast scrolling by changing the origin.
*/

+#include <linux/config.h>
+#include <linux/console.h>
+
#define NPAR 16

struct vc_data {
@@ -25,10 +28,14 @@
unsigned char vc_s_color; /* Saved foreground & background */
unsigned char vc_ulcolor; /* Color for underline mode */
unsigned char vc_halfcolor; /* Color for half intensity mode */
+ unsigned char vc_def_attr; /* Default attributes */
+ unsigned char vc_ul_attr; /* Attribute for underline mode */
+ unsigned char vc_half_attr; /* Attribute for half intensity mode */
+ unsigned char vc_bold_attr; /* Attribute for bold mode */
unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
struct console_font_op vc_font; /* Current VC font set */
- unsigned short vc_video_erase_char; /* Background erase character */
+ vram_char_t vc_video_erase_char; /* Background erase character */
unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */
unsigned int vc_x, vc_y; /* Cursor position */
unsigned int vc_top, vc_bottom; /* Scrolling region */
@@ -106,6 +113,10 @@
#define CUR_HWMASK 0x0f
#define CUR_SWMASK 0xfff0

+#ifdef CONFIG_X86_PC9800
+#define CUR_DEFAULT CUR_BLOCK
+#else
#define CUR_DEFAULT CUR_UNDERLINE
+#endif

#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp)
diff -Nru linux/include/linux/tty.h linux98/include/linux/tty.h
--- linux/include/linux/tty.h Sat Oct 19 13:01:54 2002
+++ linux98/include/linux/tty.h Mon Oct 21 14:22:18 2002
@@ -123,6 +123,10 @@

#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */

+#define VIDEO_TYPE_98NORMAL 0xa4 /* NEC PC-9800 normal */
+#define VIDEO_TYPE_9840 0xa5 /* NEC PC-9800 normal 40 lines */
+#define VIDEO_TYPE_98HIRESO 0xa6 /* NEC PC-9800 hireso */
+
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
* a c_cc[] character, but indicates that a particular special character
diff -Nru linux/include/linux/vt.h linux98/include/linux/vt.h
--- linux/include/linux/vt.h Sat Oct 19 13:02:30 2002
+++ linux98/include/linux/vt.h Mon Oct 21 14:26:03 2002
@@ -50,5 +50,6 @@
#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */
#define VT_LOCKSWITCH 0x560B /* disallow vt switching */
#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */
+#define VT_GDC_RESIZE 0x5698

#endif /* _LINUX_VT_H */
diff -Nru linux/include/linux/vt_buffer.h linux98/include/linux/vt_buffer.h
--- linux/include/linux/vt_buffer.h Sat Oct 19 13:02:24 2002
+++ linux98/include/linux/vt_buffer.h Mon Oct 21 14:28:40 2002
@@ -19,6 +19,10 @@
#include <asm/vga.h>
#endif

+#ifdef CONFIG_GDC_CONSOLE
+#include <asm/gdc.h>
+#endif
+
#ifndef VT_BUF_HAVE_RW
#define scr_writew(val, addr) (*(addr) = (val))
#define scr_readw(addr) (*(addr))

2003-03-09 04:03:43

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (2/20) char dev update

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (2/20)

Updates real time clock driver and printer driver for PC98.
- drivers/char/lp_old98.c
used 'ndelay()' and some small cleanup.
- drivers/char/upd4990a.c
remove own BCD macros by using 'linux/bcd.h'.
C99 intializer.

Regards,
Osamu Tomita

diff -Nru linux-2.5.64-ac1/drivers/char/lp_old98.c linux98-2.5.64/drivers/char/lp_old98.c
--- linux-2.5.64-ac1/drivers/char/lp_old98.c 2003-03-07 08:52:01.000000000 +0900
+++ linux98-2.5.64/drivers/char/lp_old98.c 2003-03-05 13:23:48.000000000 +0900
@@ -68,7 +68,7 @@
.wait = LP_INIT_WAIT,
};

-static int dc1_check = 0;
+static int dc1_check;
static spinlock_t lp_old98_lock = SPIN_LOCK_UNLOCKED;


@@ -139,7 +139,7 @@
if (tmp < 0)
tmp = -tmp;
#endif
- __const_udelay(lp.wait * 4);
+ ndelay(lp.wait);

/* negate PSTB# (activate strobe) */
outb(LP_CONTROL_ASSERT_STROBE, LP_PORT_CONTROL);
@@ -150,7 +150,7 @@
lp.stats.chars ++;
#endif

- __const_udelay(lp.wait * 4);
+ ndelay(lp.wait);

/* assert PSTB# (deactivate strobe) */
outb(LP_CONTROL_NEGATE_STROBE, LP_PORT_CONTROL);
@@ -488,18 +488,18 @@
errmsg = "unable to register device";

release_region(LP_PORT_EXTMODE, 1);
- err5:
+err5:
release_region(LP_PORT_STROBE, 1);
- err4:
+err4:
release_region(LP_PORT_STATUS, 1);
- err3:
+err3:
release_region(LP_PORT_DATA, 1);
- err2:
+err2:
#ifdef PC98_HW_H98
if (pc98_hw_flags & PC98_HW_H98)
release_region(LP_PORT_H98MODE, 1);

- err1:
+err1:
#endif
printk(KERN_ERR "lp_old98: %s\n", errmsg);
return -EBUSY;
diff -Nru linux-2.5.64-ac1/drivers/char/upd4990a.c linux98-2.5.64/drivers/char/upd4990a.c
--- linux-2.5.64-ac1/drivers/char/upd4990a.c 2003-03-07 08:52:02.000000000 +0900
+++ linux98-2.5.64/drivers/char/upd4990a.c 2003-03-05 13:23:48.000000000 +0900
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/rtc.h>
+#include <linux/bcd.h>
#include <linux/upd4990a.h>
#include <linux/init.h>
#include <linux/poll.h>
@@ -34,9 +35,6 @@
#include <asm/uaccess.h>
#include <asm/system.h>

-#define BCD_TO_BINARY(val) (((val) >> 4) * 10 + ((val) & 0xF))
-#define BINARY_TO_BCD(val) ((((val) / 10) << 4) | ((val) % 10))
-
/*
* We sponge a minor off of the misc major. No need slurping
* up another valuable major dev number for this. If you add
@@ -137,7 +135,6 @@

if (data != 0)
break;
-
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
goto out;
@@ -178,7 +175,7 @@
case RTC_UIE_ON: /* Allow ints for RTC updates. */
spin_lock_irq(&rtc_lock);
rtc_irq_data = 0;
- if (!(rtc_status & RTC_UIE_TIMER_ON)){
+ if (!(rtc_status & RTC_UIE_TIMER_ON)) {
rtc_status |= RTC_UIE_TIMER_ON;
rtc_uie_timer.expires = jiffies + 1;
add_timer(&rtc_uie_timer);
@@ -194,10 +191,10 @@
upd4990a_get_time(&raw, 0);
spin_unlock_irq(&rtc_lock);

- wtime.tm_sec = BCD_TO_BINARY(raw.sec);
- wtime.tm_min = BCD_TO_BINARY(raw.min);
- wtime.tm_hour = BCD_TO_BINARY(raw.hour);
- wtime.tm_mday = BCD_TO_BINARY(raw.mday);
+ wtime.tm_sec = BCD2BIN(raw.sec);
+ wtime.tm_min = BCD2BIN(raw.min);
+ wtime.tm_hour = BCD2BIN(raw.hour);
+ wtime.tm_mday = BCD2BIN(raw.mday);
wtime.tm_mon = raw.mon - 1; /* convert to 0-base */
wtime.tm_wday = raw.wday;

@@ -205,7 +202,7 @@
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
*/
- if ((wtime.tm_year = BCD_TO_BINARY(raw.year)) < 95)
+ if ((wtime.tm_year = BCD2BIN(raw.year)) < 95)
wtime.tm_year += 100;

wtime.tm_isdst = 0;
@@ -244,13 +241,13 @@
if (wtime.tm_wday > 6)
return -EINVAL;

- raw.sec = BINARY_TO_BCD(wtime.tm_sec);
- raw.min = BINARY_TO_BCD(wtime.tm_min);
- raw.hour = BINARY_TO_BCD(wtime.tm_hour);
- raw.mday = BINARY_TO_BCD(wtime.tm_mday);
+ raw.sec = BIN2BCD(wtime.tm_sec);
+ raw.min = BIN2BCD(wtime.tm_min);
+ raw.hour = BIN2BCD(wtime.tm_hour);
+ raw.mday = BIN2BCD(wtime.tm_mday);
raw.mon = wtime.tm_mon + 1;
raw.wday = wtime.tm_wday;
- raw.year = BINARY_TO_BCD(wtime.tm_year % 100);
+ raw.year = BIN2BCD(wtime.tm_year % 100);

spin_lock_irq(&rtc_lock);
upd4990a_set_time(&raw, 0);
@@ -329,7 +326,6 @@

static struct file_operations rtc_fops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
.read = rtc_read,
.poll = rtc_poll,
.ioctl = rtc_ioctl,
@@ -340,9 +336,9 @@

static struct miscdevice rtc_dev=
{
- RTC_MINOR,
- "rtc",
- &rtc_fops
+ .minor = RTC_MINOR,
+ .name = "rtc",
+ .fops = &rtc_fops,
};

static int __init rtc_init(void)
@@ -370,7 +366,6 @@

module_init (rtc_init);

-#ifdef MODULE
static void __exit rtc_exit(void)
{
del_timer(&rtc_uie_timer);
@@ -380,7 +375,6 @@
}

module_exit (rtc_exit);
-#endif

/*
* Info exported via "/proc/driver/rtc".
@@ -400,14 +394,14 @@
* There is no way to tell if the luser has the RTC set for local
* time or for Universal Standard Time (GMT). Probably local though.
*/
- if ((year = BCD_TO_BINARY(data.year) + 1900) < 1995)
+ if ((year = BCD2BIN(data.year) + 1900) < 1995)
year += 100;
p += sprintf(p,
"rtc_time\t: %02d:%02d:%02d\n"
"rtc_date\t: %04d-%02d-%02d\n",
- BCD_TO_BINARY(data.hour), BCD_TO_BINARY(data.min),
- BCD_TO_BINARY(data.sec),
- year, data.mon, BCD_TO_BINARY(data.mday));
+ BCD2BIN(data.hour), BCD2BIN(data.min),
+ BCD2BIN(data.sec),
+ year, data.mon, BCD2BIN(data.mday));

return p - buf;
}

2003-03-09 04:07:21

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (5/20) core update

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (5/20)

Updates core patches for PC98.
- topology.c: remove NUMA code.
- setup_arch_pre.h: change tick_usec, tick_nsec to extern.

Regards,
Osamu Tomita


diff -Nru linux-2.5.64-ac1/arch/i386/mach-pc9800/topology.c linux98-2.5.64/arch/i386/mach-pc9800/topology.c
--- linux-2.5.64-ac1/arch/i386/mach-pc9800/topology.c 2003-03-07 08:51:59.000000000 +0900
+++ linux98-2.5.64/arch/i386/mach-pc9800/topology.c 2003-03-05 13:24:31.000000000 +0900
@@ -1,5 +1,5 @@
/*
- * arch/i386/mach-generic/topology.c - Populate driverfs with topology information
+ * arch/i386/mach-pc9800/topology.c - Populate driverfs with topology information
*
* Written by: Matthew Dobson, IBM Corporation
* Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL
@@ -23,7 +23,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <[email protected]>
+ * Modify for PC-9800 by Osamu Tomita <[email protected]>
+ *
*/
#include <linux/init.h>
#include <linux/smp.h>
@@ -31,29 +32,6 @@

struct i386_cpu cpu_devices[NR_CPUS];

-#ifdef CONFIG_NUMA
-#include <linux/mmzone.h>
-#include <asm/node.h>
-#include <asm/memblk.h>
-
-struct i386_node node_devices[MAX_NUMNODES];
-struct i386_memblk memblk_devices[MAX_NR_MEMBLKS];
-
-static int __init topology_init(void)
-{
- int i;
-
- for (i = 0; i < num_online_nodes(); i++)
- arch_register_node(i);
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_possible(i)) arch_register_cpu(i);
- for (i = 0; i < num_online_memblks(); i++)
- arch_register_memblk(i);
- return 0;
-}
-
-#else /* !CONFIG_NUMA */
-
static int __init topology_init(void)
{
int i;
@@ -63,6 +41,4 @@
return 0;
}

-#endif /* CONFIG_NUMA */
-
subsys_initcall(topology_init);
diff -Nru linux-2.5.64-ac1/include/asm-i386/mach-pc9800/setup_arch_pre.h linux98-2.5.64/include/asm-i386/mach-pc9800/setup_arch_pre.h
--- linux-2.5.64-ac1/include/asm-i386/mach-pc9800/setup_arch_pre.h 2003-03-07 08:52:10.000000000 +0900
+++ linux98-2.5.64/include/asm-i386/mach-pc9800/setup_arch_pre.h 2003-03-05 16:32:02.000000000 +0900
@@ -10,8 +10,8 @@
#include <asm/pc9800_sca.h>

int CLOCK_TICK_RATE;
-unsigned long tick_usec; /* ACTHZ period (usec) */
-unsigned long tick_nsec; /* USER_HZ period (nsec) */
+extern unsigned long tick_usec; /* ACTHZ period (usec) */
+extern unsigned long tick_nsec; /* USER_HZ period (nsec) */
unsigned char pc9800_misc_flags;
/* (bit 0) 1:High Address Video ram exists 0:otherwise */

2003-03-09 04:10:57

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (8/20) input update

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (8/20)

Updates drivers for PC98 standard keyboard.

Regards,
Osamu Tomita

diff -Nru linux-2.5.64-ac1/drivers/input/keyboard/98kbd.c linux98-2.5.64/drivers/input/keyboard/98kbd.c
--- linux-2.5.64-ac1/drivers/input/keyboard/98kbd.c 2003-03-07 08:52:02.000000000 +0900
+++ linux98-2.5.64/drivers/input/keyboard/98kbd.c 2003-03-06 10:37:36.000000000 +0900
@@ -109,7 +109,8 @@
struct jis_kbd_conv jis[16];
};

-void kbd98_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+void kbd98_interrupt(struct serio *serio, unsigned char data,
+ unsigned int flags, struct pt_regs *regs)
{
struct kbd98 *kbd98 = serio->private;
unsigned char scancode, keycode;

2003-03-09 04:18:48

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (14/20) PCMCIA

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (14/20)

Small change for PCMCIA (16bits) support.
For fix usable IRQ number.

Regards,
Osamu Tomita


diff -Nru linux-2.5.62-ac1/drivers/pcmcia/i82365.c linux98-2.5.62-ac1/drivers/pcmcia/i82365.c
--- linux-2.5.62-ac1/drivers/pcmcia/i82365.c 2003-02-18 07:56:55.000000000 +0900
+++ linux98-2.5.62-ac1/drivers/pcmcia/i82365.c 2003-02-21 11:14:30.000000000 +0900
@@ -188,7 +188,11 @@
};

/* Default ISA interrupt mask */
+#ifndef CONFIG_X86_PC9800
#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */
+#else
+#define I365_MASK 0xd668 /* irq 15,14,12,10,9,6,5,3 */
+#endif

#ifdef CONFIG_ISA
static int grab_irq;

2003-03-09 04:13:53

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (10/20) kconfig

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (10/20)

Add selection CONFIG_X86_PC9800.

Regards,
Osamu Tomita

diff -Nru linux-2.5.64/arch/i386/Kconfig linux98-2.5.64/arch/i386/Kconfig
--- linux-2.5.64/arch/i386/Kconfig 2003-03-05 11:22:25.000000000 +0900
+++ linux98-2.5.64/arch/i386/Kconfig 2003-03-05 11:43:32.000000000 +0900
@@ -104,6 +104,12 @@
A kernel compiled for the Visual Workstation will not run on PCs
and vice versa. See <file:Documentation/sgi-visws.txt> for details.

+config X86_PC9800
+ bool "PC-9800 (NEC)"
+ help
+ To make kernel for NEC PC-9801/PC-9821 sub-architecture, say Y.
+ If say Y, kernel works -ONLY- on PC-9800 architecture.
+
endchoice


@@ -1073,7 +1079,7 @@

config EISA
bool "EISA support"
- depends on ISA
+ depends on ISA && !X86_PC9800
---help---
The Extended Industry Standard Architecture (EISA) bus was
developed as an open alternative to the IBM MicroChannel bus.
@@ -1091,7 +1097,7 @@

config MCA
bool "MCA support"
- depends on !(X86_VISWS || X86_VOYAGER)
+ depends on !(X86_VISWS || X86_VOYAGER || X86_PC9800)
help
MicroChannel Architecture is found in some IBM PS/2 machines and
laptops. It is a bus system similar to PCI or ISA. See

2003-03-09 04:18:43

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (13/20) PCI

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (13/20)

Small changes for PCI support.
Fix for difference of IRQ numbers and IO addresses.

Regards,
Osamu Tomita


diff -Nru linux/arch/i386/pci/irq.c linux98/arch/i386/pci/irq.c
--- linux/arch/i386/pci/irq.c 2002-10-12 13:22:46.000000000 +0900
+++ linux98/arch/i386/pci/irq.c 2002-10-12 14:18:52.000000000 +0900
@@ -5,6 +5,7 @@
*/

#include <linux/config.h>
+#include <linux/pci_ids.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -25,6 +26,7 @@

static struct irq_routing_table *pirq_table;

+#ifndef CONFIG_X86_PC9800
/*
* Never use: 0, 1, 2 (timer, keyboard, and cascade)
* Avoid using: 13, 14 and 15 (FP error and IDE).
@@ -36,6 +38,20 @@
1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
0, 0, 0, 0, 1000, 100000, 100000, 100000
};
+#else
+/*
+ * Never use: 0, 1, 2, 7 (timer, keyboard, CRT VSYNC and cascade)
+ * Avoid using: 8, 9 and 15 (FP error and IDE).
+ * Penalize: 4, 5, 11, 12, 13, 14 (known ISA uses: serial, floppy, sound, mouse
+ * and parallel)
+ */
+unsigned int pcibios_irq_mask = 0xff78;
+
+static int pirq_penalty[16] = {
+ 1000000, 1000000, 1000000, 0, 1000, 1000, 0, 1000000,
+ 100000, 100000, 0, 1000, 1000, 1000, 1000, 100000
+};
+#endif

struct irq_router {
char *name;
@@ -612,6 +628,17 @@
r->set(pirq_router_dev, dev, pirq, 11);
}

+#ifdef CONFIG_X86_PC9800
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+ if (pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82439TX, NULL) != NULL) {
+ if (mask & 0x0040) {
+ mask &= 0x0040; /* assign IRQ 6 only */
+ printk("pci-irq: Use IRQ6 for CardBus controller\n");
+ }
+ }
+ }
+#endif
/*
* Find the best IRQ to assign: use the one
* reported by the device if possible.
diff -Nru linux/drivers/pcmcia/yenta.c linux98/drivers/pcmcia/yenta.c
--- linux/drivers/pcmcia/yenta.c 2002-11-18 13:29:48.000000000 +0900
+++ linux98/drivers/pcmcia/yenta.c 2002-11-19 11:02:09.000000000 +0900
@@ -8,6 +8,7 @@
* Dynamically adjust the size of the bridge resource
*
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>
@@ -510,6 +511,7 @@
add_timer(&socket->poll_timer);
}

+#ifndef CONFIG_X86_PC9800
/*
* Only probe "regular" interrupts, don't
* touch dangerous spots like the mouse irq,
@@ -520,6 +522,10 @@
* Default to 11, 10, 9, 7, 6, 5, 4, 3.
*/
static u32 isa_interrupts = 0x0ef8;
+#else
+/* Default to 12, 10, 6, 5, 3. */
+static u32 isa_interrupts = 0x1468;
+#endif

static unsigned int yenta_probe_irq(pci_socket_t *socket, u32 isa_irq_mask)
{
diff -Nru linux/include/asm-i386/pci.h linux98/include/asm-i386/pci.h
--- linux/include/asm-i386/pci.h 2002-06-09 14:29:24.000000000 +0900
+++ linux98/include/asm-i386/pci.h 2002-06-10 20:49:15.000000000 +0900
@@ -17,7 +17,11 @@
#endif

extern unsigned long pci_mem_start;
+#ifdef CONFIG_X86_PC9800
+#define PCIBIOS_MIN_IO 0x4000
+#else
#define PCIBIOS_MIN_IO 0x1000
+#endif
#define PCIBIOS_MIN_MEM (pci_mem_start)

void pcibios_config_init(void);

2003-03-09 04:16:44

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (11/20) NIC

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (11/20)

C-bus(PC98's legacy bus like ISA) network cards support.
Change IO port and IRQ assign.
Add auto detect function for some cards.
PCI netwwork card works fine without patch.

Regards,
Osamu Tomita


diff -Nru linux-2.5.64/drivers/net/3c509.c linux98-2.5.64/drivers/net/3c509.c
--- linux-2.5.64/drivers/net/3c509.c 2003-03-05 11:22:46.000000000 +0900
+++ linux98-2.5.64/drivers/net/3c509.c 2003-03-05 11:45:08.000000000 +0900
@@ -56,6 +56,10 @@
v1.19b 08Nov2002 Marc Zyngier <[email protected]>
- Introduce driver model for EISA cards.
*/
+/*
+ FIXES for PC-9800:
+ Shu Iwanaga: 3c569B(PC-9801 C-bus) support
+*/

#define DRV_NAME "3c509"
#define DRV_VERSION "1.19b"
@@ -257,7 +261,7 @@
};
#endif /* CONFIG_MCA */

-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -350,7 +354,7 @@
if (lp->pmdev)
pm_unregister(lp->pmdev);
#endif
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (lp->type == EL3_PNP)
pnp_device_detach(to_pnp_dev(lp->dev));
#endif
@@ -368,12 +372,12 @@
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
static int pnp_cards;
struct pnp_dev *idev = NULL;
#endif /* __ISAPNP__ */

-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (nopnp == 1)
goto no_pnp;

@@ -421,6 +425,9 @@
no_pnp:
#endif /* __ISAPNP__ */

+#ifdef CONFIG_X86_PC9800
+ id_port = 0x71d0;
+#else
/* Select an open I/O location at 0x1*0 to do contention select. */
for ( ; id_port < 0x200; id_port += 0x10) {
if (check_region(id_port, 1))
@@ -435,6 +442,7 @@
printk(" WARNING: No I/O port available for 3c509 activation.\n");
return -ENODEV;
}
+#endif /* CONFIG_X86_PC9800 */
/* Next check for all ISA bus boards by sending the ID sequence to the
ID_PORT. We find cards past the first by setting the 'current_tag'
on cards as they are found. Cards with their tag set will not
@@ -465,7 +473,7 @@
phys_addr[i] = htons(id_read_eeprom(i));
}

-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
if (nopnp == 0) {
/* The ISA PnP 3c509 cards respond to the ID sequence.
This check is needed in order not to register them twice. */
@@ -490,9 +498,19 @@
{
unsigned int iobase = id_read_eeprom(8);
if_port = iobase >> 14;
+#ifdef CONFIG_X86_PC9800
+ ioaddr = 0x40d0 + ((iobase & 0x1f) << 8);
+#else
ioaddr = 0x200 + ((iobase & 0x1f) << 4);
+#endif
}
irq = id_read_eeprom(9) >> 12;
+#ifdef CONFIG_X86_PC9800
+ if (irq == 7)
+ irq = 6;
+ else if (irq == 15)
+ irq = 13;
+#endif

if (!(dev = init_etherdev(NULL, sizeof(struct el3_private))))
return -ENOMEM;
@@ -522,7 +540,11 @@
outb(0xd0 + ++current_tag, id_port);

/* Activate the adaptor at the EEPROM location. */
+#ifdef CONFIG_X86_PC9800
+ outb((ioaddr >> 8) | 0xe0, id_port);
+#else
outb((ioaddr >> 4) | 0xe0, id_port);
+#endif

EL3WINDOW(0);
if (inw(ioaddr) != 0x6d50) {
@@ -534,7 +556,7 @@
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);

-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
found: /* PNP jumps here... */
#endif /* __ISAPNP__ */

@@ -543,7 +565,7 @@
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
lp->dev = &idev->dev;
#endif

@@ -1388,6 +1410,12 @@
outw(0x0001, ioaddr + 4);

/* Set the IRQ line. */
+#ifdef CONFIG_X86_PC9800
+ if (dev->irq == 6)
+ dev->irq = 7;
+ else if (dev->irq == 13)
+ dev->irq = 15;
+#endif
outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);

/* Set the station address in window 2 each time opened. */
@@ -1550,7 +1578,7 @@
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");
MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#ifdef __ISAPNP__
+#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
MODULE_PARM(nopnp, "i");
MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
diff -Nru linux-2.5.42/drivers/net/8390.h linux98-2.5.42/drivers/net/8390.h
--- linux-2.5.42/drivers/net/8390.h 2002-10-12 13:22:14.000000000 +0900
+++ linux98-2.5.42/drivers/net/8390.h 2002-10-15 23:03:22.000000000 +0900
@@ -123,7 +123,8 @@
#define inb_p(port) in_8(port)
#define outb_p(val,port) out_8(port,val)

-#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) || \
+ defined(CONFIG_NET_CBUS)
#define EI_SHIFT(x) (ei_local->reg_offset[x])
#else
#define EI_SHIFT(x) (x)
diff -Nru linux-2.5.62-ac1/drivers/net/Kconfig linux98-2.5.62-ac1/drivers/net/Kconfig
--- linux-2.5.62-ac1/drivers/net/Kconfig 2003-02-18 07:56:53.000000000 +0900
+++ linux98-2.5.62-ac1/drivers/net/Kconfig 2003-02-21 11:07:56.000000000 +0900
@@ -663,7 +663,7 @@
as <file:Documentation/networking/net-modules.txt>.

config EL3
- tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
+ tristate "3c509/3c529 (MCA)/3c569B (98)/3c579 \"EtherLink III\" support"
depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
---help---
If you have a network (Ethernet) card belonging to the 3Com
@@ -932,7 +932,7 @@
source "drivers/net/tulip/Kconfig"

config AT1700
- tristate "AT1700/1720 support (EXPERIMENTAL)"
+ tristate "AT1700/1720/RE1000Plus(C-Bus) support (EXPERIMENTAL)"
depends on NET_ETHERNET && (ISA || MCA) && EXPERIMENTAL
---help---
If you have a network (Ethernet) card of this type, say Y and read
@@ -978,7 +978,7 @@

config NET_ISA
bool "Other ISA cards"
- depends on NET_ETHERNET && ISA
+ depends on NET_ETHERNET && ISA && !X86_PC9800
---help---
If your network (Ethernet) card hasn't been mentioned yet and its
bus system (that's the way the cards talks to the other components
@@ -1176,6 +1176,55 @@
the Ethernet-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.

+config NET_CBUS
+ bool "NEC PC-9800 C-bus cards"
+ depends on NET_ETHERNET && ISA && X86_PC9800
+ ---help---
+ If your network (Ethernet) card hasn't been mentioned yet and its
+ bus system (that's the way the cards talks to the other components
+ of your computer) is NEC PC-9800 C-Bus, say Y.
+
+config NE2K_CBUS
+ tristate "Most NE2000-based Ethernet support"
+ depends on NET_CBUS
+
+config NE2K_CBUS_EGY98
+ bool "Melco EGY-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_LGY98
+ bool "Melco LGY-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_ICM
+ bool "ICM IF-27xxET support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_IOLA98
+ bool "I-O DATA LA-98 support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL
+ bool "Contec C-NET(98)E/L support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_CNET98EL_IO_BASE
+ hex "C-NET(98)E/L I/O base address (0xaaed or 0x55ed)"
+ depends on NE2K_CBUS_CNET98EL
+ default "0xaaed"
+
+config NE2K_CBUS_ATLA98
+ bool "Allied Telesis LA-98 Support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_BDN
+ bool "ELECOM Laneed LD-BDN[123]A Support"
+ depends on NE2K_CBUS
+
+config NE2K_CBUS_NEC108
+ bool "NEC PC-9801-108 Support"
+ depends on NE2K_CBUS
+
config SKMC
tristate "SKnet MCA support"
depends on NET_ETHERNET && MCA
diff -Nru linux-2.5.63/drivers/net/Makefile linux98-2.5.63/drivers/net/Makefile
--- linux-2.5.63/drivers/net/Makefile 2003-02-25 13:54:39.000000000 +0900
+++ linux98-2.5.63/drivers/net/Makefile 2003-02-25 16:14:35.000000000 +0900
@@ -81,6 +81,7 @@
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390.o
obj-$(CONFIG_NE2000) += ne.o 8390.o
+obj-$(CONFIG_NE2K_CBUS) += ne.o 8390.o
obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
obj-$(CONFIG_HPLAN) += hp.o 8390.o
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
diff -Nru linux-2.5.42/drivers/net/Makefile.lib linux98-2.5.42/drivers/net/Makefile.lib
--- linux-2.5.42/drivers/net/Makefile.lib 2002-10-12 13:22:18.000000000 +0900
+++ linux98-2.5.42/drivers/net/Makefile.lib 2002-10-15 23:03:22.000000000 +0900
@@ -19,6 +19,7 @@
obj-$(CONFIG_MACMACE) += crc32.o
obj-$(CONFIG_MIPS_AU1000_ENET) += crc32.o
obj-$(CONFIG_NATSEMI) += crc32.o
+obj-$(CONFIG_NE2K_CBUS) += crc32.o
obj-$(CONFIG_PCMCIA_FMVJ18X) += crc32.o
obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o
obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o
diff -Nru linux-2.5.64-ac1/drivers/net/Space.c linux98-2.5.64-ac1/drivers/net/Space.c
--- linux-2.5.64-ac1/drivers/net/Space.c 2003-03-07 08:52:03.000000000 +0900
+++ linux98-2.5.64-ac1/drivers/net/Space.c 2003-03-07 13:30:51.000000000 +0900
@@ -229,7 +229,7 @@
#ifdef CONFIG_E2100 /* Cabletron E21xx series. */
{e2100_probe, 0},
#endif
-#ifdef CONFIG_NE2000 /* ISA (use ne2k-pci for PCI cards) */
+#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS) /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
{ne_probe, 0},
#endif
#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */
diff -Nru linux-2.5.57/drivers/net/at1700.c linux98-2.5.57/drivers/net/at1700.c
--- linux-2.5.57/drivers/net/at1700.c 2003-01-14 09:31:51.000000000 +0900
+++ linux98-2.5.57/drivers/net/at1700.c 2003-01-14 09:55:53.000000000 +0900
@@ -34,6 +34,10 @@
only is it difficult to detect, it also moves around in I/O space in
response to inb()s from other device probes!
*/
+/*
+ 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa
+ 99/12/30 port to 2.3.35 by K.Takai
+*/

#include <linux/config.h>
#include <linux/errno.h>
@@ -76,10 +80,17 @@
* ISA
*/

+#ifndef CONFIG_X86_PC9800
static int at1700_probe_list[] __initdata = {
0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
};

+#else /* CONFIG_X86_PC9800 */
+static int at1700_probe_list[] __initdata = {
+ 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0
+};
+
+#endif /* CONFIG_X86_PC9800 */
/*
* MCA
*/
@@ -122,6 +133,7 @@


/* Offsets from the base address. */
+#ifndef CONFIG_X86_PC9800
#define STATUS 0
#define TX_STATUS 0
#define RX_STATUS 1
@@ -136,6 +148,7 @@
#define TX_START 10
#define COL16CNTL 11 /* Controll Reg for 16 collisions */
#define MODE13 13
+#define RX_CTRL 14
/* Configuration registers only on the '865A/B chips. */
#define EEPROM_Ctrl 16
#define EEPROM_Data 17
@@ -144,8 +157,39 @@
#define IOCONFIG 18 /* Either read the jumper, or move the I/O. */
#define IOCONFIG1 19
#define SAPROM 20 /* The station address PROM, if no EEPROM. */
+#define MODE24 24
#define RESET 31 /* Write to reset some parts of the chip. */
#define AT1700_IO_EXTENT 32
+#define PORT_OFFSET(o) (o)
+#else /* CONFIG_X86_PC9800 */
+#define STATUS (0x0000)
+#define TX_STATUS (0x0000)
+#define RX_STATUS (0x0001)
+#define TX_INTR (0x0200)/* Bit-mapped interrupt enable registers. */
+#define RX_INTR (0x0201)
+#define TX_MODE (0x0400)
+#define RX_MODE (0x0401)
+#define CONFIG_0 (0x0600)/* Misc. configuration settings. */
+#define CONFIG_1 (0x0601)
+/* Run-time register bank 2 definitions. */
+#define DATAPORT (0x0800)/* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START (0x0a00)
+#define COL16CNTL (0x0a01)/* Controll Reg for 16 collisions */
+#define MODE13 (0x0c01)
+#define RX_CTRL (0x0e00)
+/* Configuration registers only on the '865A/B chips. */
+#define EEPROM_Ctrl (0x1000)
+#define EEPROM_Data (0x1200)
+#define CARDSTATUS 16 /* FMV-18x Card Status */
+#define CARDSTATUS1 17 /* FMV-18x Card Status */
+#define IOCONFIG (0x1400)/* Either read the jumper, or move the I/O. */
+#define IOCONFIG1 (0x1600)
+#define SAPROM 20 /* The station address PROM, if no EEPROM. */
+#define MODE24 (0x1800)/* The station address PROM, if no EEPROM. */
+#define RESET (0x1e01)/* Write to reset some parts of the chip. */
+#define PORT_OFFSET(o) ({ int _o_ = (o); (_o_ & ~1) * 0x100 + (_o_ & 1); })
+#endif /* CONFIG_X86_PC9800 */
+

#define TX_TIMEOUT 10

@@ -225,8 +269,20 @@
int slot, ret = -ENODEV;
struct net_local *lp;

+#ifndef CONFIG_X86_PC9800
if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
return -EBUSY;
+#else
+ for (i = 0; i < 0x2000; i += 0x0200) {
+ if (!request_region(ioaddr + i, 2, dev->name)) {
+ while (i > 0) {
+ i -= 0x0200;
+ release_region(ioaddr + i, 2);
+ }
+ return -EBUSY;
+ }
+ }
+#endif

/* Resetting the chip doesn't reset the ISA interface, so don't bother.
That means we have to be careful with the register values we probe for.
@@ -317,10 +373,17 @@
/* Reset the internal state machines. */
outb(0, ioaddr + RESET);

- if (is_at1700)
+ if (is_at1700) {
+#ifndef CONFIG_X86_PC9800
irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
| (read_eeprom(ioaddr, 0)>>14)];
- else {
+#else
+ {
+ char re1000plus_irqmap[4] = {3, 5, 6, 12};
+ irq = re1000plus_irqmap[inb(ioaddr + IOCONFIG1) >> 6];
+ }
+#endif
+ } else {
/* Check PnP mode for FMV-183/184/183A/184A. */
/* This PnP routine is very poor. IO and IRQ should be known. */
if (inb(ioaddr + CARDSTATUS1) & 0x20) {
@@ -392,18 +455,22 @@
/* Set the station address in bank zero. */
outb(0x00, ioaddr + CONFIG_1);
for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + 8 + i);
+ outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));

/* Switch to bank 1 and set the multicast table to accept none. */
outb(0x04, ioaddr + CONFIG_1);
for (i = 0; i < 8; i++)
- outb(0x00, ioaddr + 8 + i);
+ outb(0x00, ioaddr + PORT_OFFSET(8 + i));


/* Switch to bank 2 */
/* Lock our I/O address, and set manual processing mode for 16 collisions. */
outb(0x08, ioaddr + CONFIG_1);
+#ifndef CONFIG_X86_PC9800
outb(dev->if_port, ioaddr + MODE13);
+#else
+ outb(0, ioaddr + MODE13);
+#endif
outb(0x00, ioaddr + COL16CNTL);

if (net_debug)
@@ -447,7 +514,12 @@
kfree(dev->priv);
dev->priv = NULL;
err_out:
+#ifndef CONFIG_X86_PC9800
release_region(ioaddr, AT1700_IO_EXTENT);
+#else
+ for (i = 0; i < 0x2000; i += 0x0200)
+ release_region(ioaddr + i, 2);
+#endif
return ret;
}

@@ -459,7 +531,11 @@
#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */

/* Delay between EEPROM clock transitions. */
+#ifndef CONFIG_X86_PC9800
#define eeprom_delay() do { } while (0)
+#else
+#define eeprom_delay() __asm__ ("out%B0 %%al,%0" :: "N"(0x5f))
+#endif

/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
@@ -542,12 +618,12 @@
inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
? "IRQ conflict" : "network cable problem");
printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
- dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4),
- inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
- inw (ioaddr + 12), inw (ioaddr + 14));
+ dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
+ inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
+ inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
- outw (0xffff, ioaddr + 24);
+ outw(0xffff, ioaddr + MODE24);
outw (0xffff, ioaddr + TX_STATUS);
outb (0x5a, ioaddr + CONFIG_0);
outb (0xe8, ioaddr + CONFIG_1);
@@ -704,7 +780,7 @@
dev->name, inb(ioaddr + RX_MODE), status);
#ifndef final_version
if (status == 0) {
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
break;
}
#endif
@@ -724,7 +800,7 @@
dev->name, pkt_len);
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
lp->stats.rx_errors++;
break;
}
@@ -734,7 +810,7 @@
dev->name, pkt_len);
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
lp->stats.rx_dropped++;
break;
}
@@ -761,7 +837,7 @@
if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
break;
inw(ioaddr + DATAPORT); /* dummy status read */
- outb(0x05, ioaddr + 14);
+ outb(0x05, ioaddr + RX_CTRL);
}

if (net_debug > 5)
@@ -851,7 +927,7 @@
/* Switch to bank 1 and set the multicast table. */
outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
for (i = 0; i < 8; i++)
- outb(mc_filter[i], ioaddr + 8 + i);
+ outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
outw(saved_bank, ioaddr + CONFIG_0);
}
@@ -861,7 +937,12 @@

#ifdef MODULE
static struct net_device dev_at1700;
+#ifndef CONFIG_X86_PC9800
static int io = 0x260;
+#else
+static int io = 0xd0;
+#endif
+
static int irq;

MODULE_PARM(io, "i");
@@ -901,7 +982,15 @@

/* If we don't do this, we can't re-insmod it later. */
free_irq(dev_at1700.irq, NULL);
+#ifndef CONFIG_X86_PC9800
release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
+#else
+ {
+ int i;
+ for (i = 0; i < 0x2000; i += 0x200)
+ release_region(dev_at1700.base_addr + i, 2);
+ }
+#endif
}
#endif /* MODULE */
MODULE_LICENSE("GPL");
diff -Nru linux-2.5.61/drivers/net/ne.c linux98-2.5.61/drivers/net/ne.c
--- linux-2.5.61/drivers/net/ne.c 2003-02-15 08:51:42.000000000 +0900
+++ linux98-2.5.61/drivers/net/ne.c 2003-02-16 11:49:42.000000000 +0900
@@ -109,6 +109,10 @@
{"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
{"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
{"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
+ {"LA/T-98?", "LA/T-98", {0x00, 0xa0, 0xb0}}, /* I/O Data */
+ {"EGY-98?", "EGY-98", {0x00, 0x40, 0x26}}, /* Melco EGY98 */
+ {"ICM?", "ICM-27xx-ET", {0x00, 0x80, 0xc8}}, /* ICM IF-27xx-ET */
+ {"CNET-98/EL?", "CNET(98)E/L", {0x00, 0x80, 0x4C}}, /* Contec CNET-98/EL */
{0,}
};
#endif
@@ -116,9 +120,10 @@
/* ---- No user-serviceable parts below ---- */

#define NE_BASE (dev->base_addr)
-#define NE_CMD 0x00
-#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
-#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
+#define NE_CMD EI_SHIFT(0x00)
+#define NE_DATAPORT EI_SHIFT(0x10) /* NatSemi-defined port window offset. */
+#define NE_RESET EI_SHIFT(0x1f) /* Issue a read to reset, a write to clear. */
+
#define NE_IO_EXTENT 0x20

#define NE1SM_START_PG 0x20 /* First page of TX buffer */
@@ -126,9 +131,15 @@
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */

+#ifdef CONFIG_NET_CBUS
+#include "ne2k_cbus.h"
+#endif
+
int ne_probe(struct net_device *dev);
static int ne_probe1(struct net_device *dev, int ioaddr);
+#ifndef CONFIG_NET_CBUS
static int ne_probe_isapnp(struct net_device *dev);
+#endif

static int ne_open(struct net_device *dev);
static int ne_close(struct net_device *dev);
@@ -163,6 +174,8 @@
E2010 starts at 0x100 and ends at 0x4000.
E2010-x starts at 0x100 and ends at 0xffff. */

+#ifndef CONFIG_NET_CBUS
+
int __init ne_probe(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
@@ -236,6 +249,116 @@
return -ENODEV;
}

+#else /* CONFIG_NET_CBUS */
+
+int __init ne_probe(struct net_device *dev)
+{
+ unsigned int base_addr = dev->base_addr;
+
+ SET_MODULE_OWNER(dev);
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): entered.\n");
+
+ /* If CONFIG_NET_CBUS,
+ we need dev->priv->reg_offset BEFORE to probe */
+ if (ne2k_cbus_init(dev) != 0) {
+ return -ENOMEM;
+ }
+
+ /* First check any supplied i/o locations. User knows best. <cough> */
+ if (base_addr > 0) {
+ int result;
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr);
+
+ result = ne_probe_cbus(dev, hw, base_addr);
+ if (result != 0)
+ ne2k_cbus_destroy(dev);
+
+ return result;
+ }
+
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): base_addr is not specified.\n");
+
+#ifndef MODULE
+ /* Last resort. The semi-risky C-Bus auto-probe. */
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe(): auto-probe start.\n");
+
+ {
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+
+ if (hw && hw->hwtype) {
+ const unsigned short *plist;
+ for (plist = hw->portlist; *plist; plist++) {
+ const struct ne2k_cbus_region *rlist;
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ if (check_region(*plist+rlist->start, rlist->range))
+ break;
+ }
+ if (rlist->range) {
+ /* check_region() failed */
+ continue; /* try next base port */
+ }
+ /* check_region() succeeded */
+ if (ne_probe_cbus(dev,hw,*plist) == 0)
+ return 0;
+ }
+ } else {
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ const unsigned short *plist;
+ for(plist=hw->portlist; *plist; plist++){
+ const struct ne2k_cbus_region *rlist;
+
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ if (check_region(*plist+rlist->start, rlist->range))
+ break;
+ }
+ if (rlist->range) {
+ /* check_region() failed */
+ continue; /* try next base port */
+ }
+ /* check_region() succeeded */
+ if (ne_probe_cbus(dev,hw,*plist) == 0)
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+
+ ne2k_cbus_destroy(dev);
+
+ return -ENODEV;
+}
+
+static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+ if (ei_debug > 2)
+ printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n",
+ __builtin_return_address(0));
+
+ if (hw && hw->hwtype) {
+ ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+ return ne_probe1(dev, ioaddr);
+ } else {
+ /* auto detect */
+
+ printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n");
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ ne2k_cbus_set_hwtype(dev, hw, ioaddr);
+ if (ne_probe1(dev, ioaddr)==0)
+ return 0;
+ }
+ }
+ return ENODEV;
+}
+#endif /* !CONFIG_NET_CBUS */
+
static int __init ne_probe1(struct net_device *dev, int ioaddr)
{
int i;
@@ -243,30 +366,62 @@
int wordlength = 2;
const char *name = NULL;
int start_page, stop_page;
- int neX000, ctron, copam, bad_card;
+ int neX000, bad_card;
+#ifndef CONFIG_NET_CBUS
+ int ctron, copam;
+#endif
int reg0, ret;
static unsigned version_printed;
+#ifdef CONFIG_NET_CBUS
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ outb_p(0, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+ /* udelay(5000); */
+ outb_p(1, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE);
+ /* udelay(5000); */
+ outb_p((ioaddr & 0xf000) >> 8 | 0x08 | 0x01, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE + 2);
+ /* udelay(5000); */
+ }
+#endif

+#ifndef CONFIG_NET_CBUS
if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
return -EBUSY;
+#else /* CONFIG_NET_CBUS */
+ {
+ const struct ne2k_cbus_region *rlist;
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ if (!request_region(ioaddr + rlist->start,
+ rlist->range, dev->name))
+ return -EBUSY;
+ }
+ }
+#endif /* !CONFIG_NET_CBUS */

- reg0 = inb_p(ioaddr);
+ reg0 = inb_p(ioaddr + EI_SHIFT(0));
if (reg0 == 0xFF) {
ret = -ENODEV;
goto err_out;
}

/* Do a preliminary verification that we have a 8390. */
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype != NE2K_CBUS_HARDWARE_TYPE_CNET98EL)
+#endif
{
int regd;
outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
- regd = inb_p(ioaddr + 0x0d);
- outb_p(0xff, ioaddr + 0x0d);
+ regd = inb_p(ioaddr + EI_SHIFT(0x0d));
+ outb_p(0xff, ioaddr + EI_SHIFT(0x0d));
outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
outb_p(reg0, ioaddr);
- outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */
+ outb_p(regd, ioaddr + EI_SHIFT(0x0d)); /* Restore the old values. */
ret = -ENODEV;
goto err_out;
}
@@ -290,6 +445,11 @@
{
unsigned long reset_start_time = jiffies;

+#ifdef CONFIG_NET_CBUS
+ /* derived from CNET98EL-patch for bad clones */
+ outb_p(E8390_NODMA | E8390_STOP, ioaddr+E8390_CMD);
+#endif
+
/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);

@@ -308,15 +468,86 @@
outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
}

+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ static const char pat[32] ="AbcdeFghijKlmnoPqrstUvwxyZ789012";
+ char buf[32];
+ int maxwait = 200;
+
+ if (ei_debug > 2) {
+ printk(" [CNET98EL-specific initialize...");
+ }
+ outb_p(E8390_NODMA | E8390_STOP, ioaddr+E8390_CMD); /* 0x20|0x1 */
+ i=inb(ioaddr);
+ if ((i & ~0x2) != (0x20 | 0x01))
+ return ENODEV;
+ if ((inb(ioaddr + 0x7) & 0x80) != 0x80)
+ return ENODEV;
+ outb_p(E8390_RXOFF, ioaddr+EN0_RXCR); /* out(ioaddr+0xc, 0x20) */
+ /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */
+ outb_p(ENDCFG_WTS|0x48, ioaddr+EN0_DCFG); /* 0x49 */
+ outb_p(CNET98EL_START_PG, ioaddr+EN0_STARTPG);
+ outb_p(CNET98EL_STOP_PG, ioaddr+EN0_STOPPG);
+ if (ei_debug > 2) {
+ printk("memory check");
+ }
+ for (i = 0; i < 65536; i += 1024) {
+ if (ei_debug > 2) {
+ printk(" %04x",i);
+ }
+ ne2k_cbus_writemem(dev,ioaddr, i, pat, 32);
+ while (((inb(ioaddr + EN0_ISR) & ENISR_RDC) != ENISR_RDC) && --maxwait)
+ ;
+ ne2k_cbus_readmem(dev, ioaddr, i, buf, 32);
+ if (memcmp(pat, buf, 32)) {
+ if (ei_debug > 2) {
+ printk(" failed.");
+ }
+ break;
+ }
+ }
+ if (i != 16384) {
+ if (ei_debug > 2) {
+ printk("] ");
+ }
+ printk("memory failure at %x\n", i);
+ return ENODEV;
+ }
+ if (ei_debug > 2) {
+ printk(" good...");
+ }
+ if (!dev->irq) {
+ if (ei_debug > 2) {
+ printk("] ");
+ }
+ printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n");
+ return ENODEV;
+ }
+ outb((dev->irq>5) ? (dev->irq&4):(dev->irq>>1), ioaddr + (0x2 | 0x400));
+ outb(0x7e, ioaddr + (0x4 | 0x400));
+ ne2k_cbus_readmem(dev, ioaddr, 16384, SA_prom, 32);
+ outb(0xff, ioaddr + EN0_ISR);
+ if (ei_debug > 2) {
+ printk("done]");
+ }
+ } else
+#endif /* CONFIG_NE2K_CBUS_CNET98EL */
/* Read the 16 bytes of station address PROM.
We must first initialize registers, similar to NS8390_init(eifdev, 0).
We can't reliably read the SAPROM address without this.
(I learned the hard way!). */
{
- struct {unsigned char value, offset; } program_seq[] =
+ struct {unsigned char value; unsigned short offset;} program_seq[] =
{
{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+#ifndef CONFIG_NET_CBUS
{0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
+#else
+ /* NEC PC-9800: some board can only handle word-wide access? */
+ {0x48 | ENDCFG_WTS, EN0_DCFG}, /* Set word-wide (0x48) access. */
+ {16384 / 256, EN0_STARTPG},
+ {32768 / 256, EN0_STOPPG},
+#endif
{0x00, EN0_RCNTLO}, /* Clear the count regs. */
{0x00, EN0_RCNTHI},
{0x00, EN0_IMR}, /* Mask completion irq. */
@@ -332,29 +563,42 @@

for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
-
- }
+#ifndef CONFIG_NET_CBUS
for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
SA_prom[i] = inb(ioaddr + NE_DATAPORT);
SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
if (SA_prom[i] != SA_prom[i+1])
wordlength = 1;
}
+#else
+ insw(ioaddr + NE_DATAPORT, SA_prom, 32 >> 1);
+#endif
+
+ }

if (wordlength == 2)
{
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
+#ifndef CONFIG_NET_CBUS
/* We must set the 8390 for word mode. */
outb_p(0x49, ioaddr + EN0_DCFG);
+#endif
start_page = NESM_START_PG;
stop_page = NESM_STOP_PG;
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) {
+ start_page = CNET98EL_START_PG;
+ stop_page = CNET98EL_STOP_PG;
+ }
+#endif
} else {
start_page = NE1SM_START_PG;
stop_page = NE1SM_STOP_PG;
}

neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
+#ifndef CONFIG_NET_CBUS
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);

@@ -368,6 +612,11 @@
start_page = 0x01;
stop_page = (wordlength == 2) ? 0x40 : 0x20;
}
+#else
+ if (neX000) {
+ name = "C-Bus-NE2K-compat";
+ }
+#endif
else
{
#ifdef SUPPORT_NE_BAD_CLONES
@@ -414,10 +663,18 @@
dev->irq = probe_irq_off(cookie);
if (ei_debug > 2)
printk(" autoirq is %d\n", dev->irq);
- } else if (dev->irq == 2)
+ } else
+#ifndef CONFIG_X86_PC9800
+ if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
+#else
+ if (dev->irq == 7)
+ /* Fixup for users that don't know that IRQ 7 is really IRQ 11,
+ or don't know which one to set. */
+ dev->irq = 11;
+#endif

if (! dev->irq) {
printk(" failed to detect IRQ line.\n");
@@ -448,8 +705,13 @@
dev->dev_addr[i] = SA_prom[i];
}

+#ifndef CONFIG_NET_CBUS
printk("\n%s: %s found at %#x, using IRQ %d.\n",
dev->name, name, ioaddr, dev->irq);
+#else
+ printk("\n%s: %s found at %#x, hardware type %d(%s), using IRQ %d.\n",
+ dev->name, name, ioaddr, hw->hwtype, hw->hwident, dev->irq);
+#endif

ei_status.name = name;
ei_status.tx_start_page = start_page;
@@ -473,10 +735,23 @@
return 0;

err_out_kfree:
+#ifndef CONFIG_NET_CBUS
kfree(dev->priv);
dev->priv = NULL;
+#else
+ ne2k_cbus_destroy(dev);
+#endif
err_out:
+#ifndef CONFIG_NET_CBUS
release_region(ioaddr, NE_IO_EXTENT);
+#else
+ {
+ const struct ne2k_cbus_region *rlist;
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ release_region(ioaddr + rlist->start, rlist->range);
+ }
+ }
+#endif
return ret;
}

@@ -500,10 +775,18 @@
static void ne_reset_8390(struct net_device *dev)
{
unsigned long reset_start_time = jiffies;
+#ifdef CONFIG_NET_CBUS
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+#endif

if (ei_debug > 1)
printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);

+#ifdef CONFIG_NET_CBUS
+ /* derived from CNET98EL-patch for bad clones... */
+ outb_p(E8390_NODMA | E8390_STOP, NE_BASE + E8390_CMD); /* 0x20 | 0x1 */
+#endif
+
/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);

@@ -526,6 +809,9 @@
static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
int nic_base = dev->base_addr;
+#ifdef CONFIG_NET_CBUS
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+#endif

/* This *shouldn't* happen. If it does, it's the last thing you'll see */

@@ -568,6 +854,9 @@
#endif
int nic_base = dev->base_addr;
char *buf = skb->data;
+#ifdef CONFIG_NET_CBUS
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+#endif

/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing)
@@ -578,6 +867,12 @@
return;
}
ei_status.dmaing |= 0x01;
+
+#ifdef CONFIG_NET_CBUS
+ /* round up count to a word (derived from ICM-patch) */
+ count = (count + 1) & ~1;
+#endif
+
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
@@ -635,6 +930,9 @@
#ifdef NE_SANITY_CHECK
int retries = 0;
#endif
+#ifdef CONFIG_NET_CBUS
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+#endif

/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
@@ -738,13 +1036,22 @@
static int io[MAX_NE_CARDS];
static int irq[MAX_NE_CARDS];
static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */
+#ifdef CONFIG_NET_CBUS
+static int hwtype[MAX_NE_CARDS] = { 0, }; /* board type */
+#endif

MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+#ifdef CONFIG_NET_CBUS
+MODULE_PARM(hwtype, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+#endif
MODULE_PARM_DESC(io, "I/O base address(es),required");
MODULE_PARM_DESC(irq, "IRQ number(s)");
MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+#ifdef CONFIG_NET_CBUS
+MODULE_PARM_DESC(hwtype, "Board type of PC-9800 C-Bus NIC");
+#endif
MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
MODULE_LICENSE("GPL");

@@ -762,6 +1069,9 @@
dev->irq = irq[this_dev];
dev->mem_end = bad[this_dev];
dev->base_addr = io[this_dev];
+#ifdef CONFIG_NET_CBUS
+ dev->mem_start = hwtype[this_dev];
+#endif
dev->init = ne_probe;
if (register_netdev(dev) == 0) {
found++;
@@ -791,9 +1101,23 @@
if (idev)
pnp_device_detach(idev);
free_irq(dev->irq, dev);
+#ifndef CONFIG_NET_CBUS
release_region(dev->base_addr, NE_IO_EXTENT);
+#else /* CONFIG_NET_CBUS */
+ {
+ const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+ const struct ne2k_cbus_region *rlist;
+ for (rlist = hw->regionlist; rlist->range; rlist++) {
+ release_region(dev->base_addr + rlist->start, rlist->range);
+ }
+ }
+#endif /* !CONFIG_NET_CBUS */
unregister_netdev(dev);
+#ifndef CONFIG_NET_CBUS
kfree(priv);
+#else
+ ne2k_cbus_destroy(dev);
+#endif
}
}
}
diff -Nru linux-2.5.50/drivers/net/ne2k_cbus.h linux98-2.5.50/drivers/net/ne2k_cbus.h
--- linux-2.5.42/drivers/net/ne2k_cbus.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.42/drivers/net/ne2k_cbus.h 2002-12-15 10:56:15.000000000 +0900
@@ -0,0 +1,481 @@
+/* ne2k_cbus.h:
+ vender-specific information definition for NEC PC-9800
+ C-bus Ethernet Cards
+ Used in ne.c
+
+ (C)1998,1999 KITAGWA Takurou & Linux/98 project
+*/
+
+#include <linux/config.h>
+
+#undef NE_RESET
+#define NE_RESET EI_SHIFT(0x11) /* Issue a read to reset, a write to clear. */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef CONFIG_NE2K_CBUS_CNET98EL_IO_BASE
+#warning CONFIG_NE2K_CBUS_CNET98EL_IO_BASE is not defined(config error?)
+#warning use 0xaaed as default
+#define CONFIG_NE2K_CBUS_CNET98EL_IO_BASE 0xaaed /* or 0x55ed */
+#endif
+#define CNET98EL_START_PG 0x00
+#define CNET98EL_STOP_PG 0x40
+#endif
+
+/* Hardware type definition (derived from *BSD) */
+#define NE2K_CBUS_HARDWARE_TYPE_MASK 0xff
+
+/* 0: reserved for auto-detect */
+/* 1: (not tested)
+ Allied Telesis CentreCom LA-98-T */
+#define NE2K_CBUS_HARDWARE_TYPE_ATLA98 1
+/* 2: (not tested)
+ ELECOM Laneed
+ LD-BDN[123]A
+ PLANET SMART COM 98 EN-2298-C
+ MACNICA ME98 */
+#define NE2K_CBUS_HARDWARE_TYPE_BDN 2
+/* 3:
+ Melco EGY-98
+ Contec C-NET(98)E*A/L*A,C-NET(98)P */
+#define NE2K_CBUS_HARDWARE_TYPE_EGY98 3
+/* 4:
+ Melco LGY-98,IND-SP,IND-SS
+ MACNICA NE2098 */
+#define NE2K_CBUS_HARDWARE_TYPE_LGY98 4
+/* 5:
+ ICM DT-ET-25,DT-ET-T5,IF-2766ET,IF-2771ET
+ PLANET SMART COM 98 EN-2298-T,EN-2298P-T
+ D-Link DE-298PT,DE-298PCAT
+ ELECOM Laneed LD-98P */
+#define NE2K_CBUS_HARDWARE_TYPE_ICM 5
+/* 6: (reserved for SIC-98, which is not supported in this driver.) */
+/* 7: (unused in *BSD?)
+ <Original NE2000 compatible>
+ <for PCI/PCMCIA cards>
+*/
+#define NE2K_CBUS_HARDWARE_TYPE_NE2K 7
+/* 8:
+ NEC PC-9801-108 */
+#define NE2K_CBUS_HARDWARE_TYPE_NEC108 8
+/* 9:
+ I-O DATA LA-98,LA/T-98 */
+#define NE2K_CBUS_HARDWARE_TYPE_IOLA98 9
+/* 10: (reserved for C-NET(98), which is not supported in this driver.) */
+/* 11:
+ Contec C-NET(98)E,L */
+#define NE2K_CBUS_HARDWARE_TYPE_CNET98EL 11
+
+#define NE2K_CBUS_HARDWARE_TYPE_MAX 11
+
+/* HARDWARE TYPE ID 12-31: reserved */
+
+struct ne2k_cbus_offsetinfo {
+ unsigned short skip;
+ unsigned short offset8; /* +0x8 - +0xf */
+ unsigned short offset10; /* +0x10 */
+ unsigned short offset1f; /* +0x1f */
+};
+
+struct ne2k_cbus_region {
+ unsigned short start;
+ short range;
+};
+
+struct ne2k_cbus_hwinfo {
+ const unsigned short hwtype;
+ const unsigned char *hwident;
+#ifndef MODULE
+ const unsigned short *portlist;
+#endif
+ const struct ne2k_cbus_offsetinfo *offsetinfo;
+ const struct ne2k_cbus_region *regionlist;
+};
+
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+#ifndef MODULE
+static unsigned short atla98_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+#define atla98_offsetinfo ne2k_offsetinfo
+#define atla98_regionlist ne2k_regionlist
+#endif /* CONFIG_NE2K_CBUS_ATLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_BDN
+#ifndef MODULE
+static unsigned short bdn_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo bdn_offsetinfo __initdata = {
+#if 0
+ /* comes from FreeBSD(98) ed98.h */
+ 0x1000, 0x8000, 0x100, 0xc200 /* ??? */
+#else
+ /* comes from NetBSD/pc98 if_ne_isa.c */
+ 0x1000, 0x8000, 0x100, 0x7f00 /* ??? */
+#endif
+};
+static struct ne2k_cbus_region bdn_regionlist[] __initdata = {
+ {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000,1},
+ {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+ {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+ {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+ {0x100, 1}, {0x7f00, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_BDN */
+
+#ifdef CONFIG_NE2K_CBUS_EGY98
+#ifndef MODULE
+static unsigned short egy98_portlist[] __initdata = {
+ 0xd0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo egy98_offsetinfo __initdata = {
+ 0x02, 0x100, 0x200, 0x300
+};
+static struct ne2k_cbus_region egy98_regionlist[] __initdata = {
+ {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+ {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+ {0x100, 1}, {0x102, 1}, {0x104, 1}, {0x106, 1},
+ {0x108, 1}, {0x10a, 1}, {0x10c, 1}, {0x10e, 1},
+ {0x200, 1}, {0x300, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_EGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_LGY98
+#ifndef MODULE
+static unsigned short lgy98_portlist[] __initdata = {
+ 0xd0, 0x10d0, 0x20d0, 0x30d0, 0x40d0, 0x50d0, 0x60d0, 0x70d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo lgy98_offsetinfo __initdata = {
+ 0x01, 0x08, 0x200, 0x300
+};
+static struct ne2k_cbus_region lgy98_regionlist[] __initdata = {
+ {0x0, 16}, {0x200, 1}, {0x300, 1},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_LGY98 */
+
+#ifdef CONFIG_NE2K_CBUS_ICM
+#ifndef MODULE
+static unsigned short icm_portlist[] __initdata = {
+ /* ICM */
+ 0x56d0,
+ /* LD-98PT */
+ 0x46d0, 0x66d0, 0x76d0, 0x86d0, 0x96d0, 0xa6d0, 0xb6d0, 0xc6d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo icm_offsetinfo __initdata = {
+ 0x01, 0x08, 0x100, 0x10f
+};
+static struct ne2k_cbus_region icm_regionlist[] __initdata = {
+ {0x0, 16}, {0x100, 16},
+ {0x0, 0}
+};
+#endif /* CONFIG_NE2K_CBUS_ICM */
+
+#if defined(CONFIG_NE2K_CBUS_NE2K) && !defined(MODULE)
+static unsigned short ne2k_portlist[] __initdata = {
+ 0xd0, 0x300, 0x280, 0x320, 0x340, 0x360, 0x380,
+ 0
+};
+#endif
+#if defined(CONFIG_NE2K_CBUS_NE2K) || defined(CONFIG_NE2K_CBUS_ATLA98)
+static struct ne2k_cbus_offsetinfo ne2k_offsetinfo __initdata = {
+ 0x01, 0x08, 0x10, 0x1f
+};
+static struct ne2k_cbus_region ne2k_regionlist[] __initdata = {
+ {0x0, 32},
+ {0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_NEC108
+#ifndef MODULE
+static unsigned short nec108_portlist[] __initdata = {
+ 0x770, 0x2770, 0x4770, 0x6770,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo nec108_offsetinfo __initdata = {
+ 0x02, 0x1000, 0x888, 0x88a
+};
+static struct ne2k_cbus_region nec108_regionlist[] __initdata = {
+ {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1},
+ {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1},
+ {0x1000, 1}, {0x1002, 1}, {0x1004, 1}, {0x1006, 1},
+ {0x1008, 1}, {0x100a, 1}, {0x100c, 1}, {0x100e, 1},
+ {0x888, 1}, {0x88a, 1}, {0x88c, 1}, {0x88e, 1},
+ {0x0, 0}
+};
+#endif
+
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+#ifndef MODULE
+static unsigned short iola98_portlist[] __initdata = {
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo iola98_offsetinfo __initdata = {
+ 0x1000, 0x8000, 0x100, 0xf100
+};
+static struct ne2k_cbus_region iola98_regionlist[] __initdata = {
+ {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000, 1},
+ {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1},
+ {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1},
+ {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1},
+ {0x100, 1}, {0xf100, 1},
+ {0x0,0}
+};
+#endif /* CONFIG_NE2K_CBUS_IOLA98 */
+
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+#ifndef MODULE
+static unsigned short cnet98el_portlist[] __initdata = {
+ 0x3d0, 0x13d0, 0x23d0, 0x33d0, 0x43d0, 0x53d0, 0x60d0, 0x70d0,
+ 0
+};
+#endif
+static struct ne2k_cbus_offsetinfo cnet98el_offsetinfo __initdata = {
+ 0x01, 0x08, 0x40e, 0x400
+};
+static struct ne2k_cbus_region cnet98el_regionlist[] __initdata = {
+ {0x0, 16}, {0x400, 16},
+ {0x0, 0}
+};
+#endif
+
+
+/* port information table (for ne.c initialize/probe process) */
+
+static struct ne2k_cbus_hwinfo ne2k_cbus_hwinfo_list[] __initdata = {
+#ifdef CONFIG_NE2K_CBUS_ATLA98
+/* NOT TESTED */
+ {
+ NE2K_CBUS_HARDWARE_TYPE_ATLA98,
+ "LA-98-T",
+#ifndef MODULE
+ atla98_portlist,
+#endif
+ &atla98_offsetinfo, atla98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_BDN
+/* NOT TESTED */
+ {
+ NE2K_CBUS_HARDWARE_TYPE_BDN,
+ "LD-BDN[123]A",
+#ifndef MODULE
+ bdn_portlist,
+#endif
+ &bdn_offsetinfo, bdn_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_ICM
+ {
+ NE2K_CBUS_HARDWARE_TYPE_ICM,
+ "IF-27xxET",
+#ifndef MODULE
+ icm_portlist,
+#endif
+ &icm_offsetinfo, icm_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_NE2K
+ {
+ NE2K_CBUS_HARDWARE_TYPE_NE2K,
+ "NE2000 compat.",
+#ifndef MODULE
+ ne2k_portlist,
+#endif
+ &ne2k_offsetinfo, ne2k_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ {
+ NE2K_CBUS_HARDWARE_TYPE_NEC108,
+ "PC-9801-108",
+#ifndef MODULE
+ nec108_portlist,
+#endif
+ &nec108_offsetinfo, nec108_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_IOLA98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_IOLA98,
+ "LA-98",
+#ifndef MODULE
+ iola98_portlist,
+#endif
+ &iola98_offsetinfo, iola98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_CNET98EL
+ {
+ NE2K_CBUS_HARDWARE_TYPE_CNET98EL,
+ "C-NET(98)E/L",
+#ifndef MODULE
+ cnet98el_portlist,
+#endif
+ &cnet98el_offsetinfo, cnet98el_regionlist
+ },
+#endif
+/* NOTE: LGY98 must be probed before EGY98, or system stalled!? */
+#ifdef CONFIG_NE2K_CBUS_LGY98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_LGY98,
+ "LGY-98",
+#ifndef MODULE
+ lgy98_portlist,
+#endif
+ &lgy98_offsetinfo, lgy98_regionlist
+ },
+#endif
+#ifdef CONFIG_NE2K_CBUS_EGY98
+ {
+ NE2K_CBUS_HARDWARE_TYPE_EGY98,
+ "EGY-98",
+#ifndef MODULE
+ egy98_portlist,
+#endif
+ &egy98_offsetinfo, egy98_regionlist
+ },
+#endif
+ {
+ 0,
+ "unsupported hardware",
+#ifndef MODULE
+ NULL,
+#endif
+ NULL, NULL
+ }
+};
+
+static int __init ne2k_cbus_init(struct net_device *dev)
+{
+ struct ei_device *ei_local;
+ if (dev->priv == NULL) {
+ ei_local = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+ if (ei_local == NULL)
+ return -ENOMEM;
+ memset(ei_local, 0, sizeof(struct ei_device));
+ ei_local->reg_offset = kmalloc(sizeof(typeof(*ei_local->reg_offset))*18, GFP_KERNEL);
+ if (ei_local->reg_offset == NULL) {
+ kfree(ei_local);
+ return -ENOMEM;
+ }
+ spin_lock_init(&ei_local->page_lock);
+ dev->priv = ei_local;
+ }
+ return 0;
+}
+
+static void ne2k_cbus_destroy(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ if (ei_local != NULL) {
+ if (ei_local->reg_offset)
+ kfree(ei_local->reg_offset);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
+}
+
+static const struct ne2k_cbus_hwinfo * __init ne2k_cbus_get_hwinfo(int hwtype)
+{
+ const struct ne2k_cbus_hwinfo *hw;
+
+ for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) {
+ if (hw->hwtype == hwtype) break;
+ }
+ return hw;
+}
+
+static void __init ne2k_cbus_set_hwtype(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ int i;
+ int hwtype_old = dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+ if (!ei_local)
+ panic("Gieee! ei_local == NULL!! (from %p)",
+ __builtin_return_address(0));
+
+ dev->mem_start &= ~NE2K_CBUS_HARDWARE_TYPE_MASK;
+ dev->mem_start |= hw->hwtype & NE2K_CBUS_HARDWARE_TYPE_MASK;
+
+ if (ei_debug > 2) {
+ printk(KERN_DEBUG "hwtype changed: %d -> %d\n",hwtype_old,(int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK));
+ }
+
+ if (hw->offsetinfo) {
+ for (i = 0; i < 8; i++) {
+ ei_local->reg_offset[i] = hw->offsetinfo->skip * i;
+ }
+ for (i = 8; i < 16; i++) {
+ ei_local->reg_offset[i] =
+ hw->offsetinfo->skip*(i-8) + hw->offsetinfo->offset8;
+ }
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_NEC108) {
+ int adj = (ioaddr & 0xf000) /2;
+ ei_local->reg_offset[16] =
+ (hw->offsetinfo->offset10 | adj) - ioaddr;
+ ei_local->reg_offset[17] =
+ (hw->offsetinfo->offset1f | adj) - ioaddr;
+ } else {
+#endif /* CONFIG_NE2K_CBUS_NEC108 */
+ ei_local->reg_offset[16] = hw->offsetinfo->offset10;
+ ei_local->reg_offset[17] = hw->offsetinfo->offset1f;
+#ifdef CONFIG_NE2K_CBUS_NEC108
+ }
+#endif
+ } else {
+ /* make dummmy offset list */
+ for (i = 0; i < 16; i++) {
+ ei_local->reg_offset[i] = i;
+ }
+ ei_local->reg_offset[16] = 0x10;
+ ei_local->reg_offset[17] = 0x1f;
+ }
+}
+
+#if defined(CONFIG_NE2K_CBUS_ICM) || defined(CONFIG_NE2K_CBUS_CNET98EL)
+static void __init ne2k_cbus_readmem(struct net_device *dev, int ioaddr, unsigned short memaddr, char *buf, unsigned short len)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+ outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+ outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+ outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+ outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+ outb_p(E8390_RREAD | E8390_START, ioaddr+E8390_CMD);
+ insw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+static void __init ne2k_cbus_writemem(struct net_device *dev, int ioaddr, unsigned short memaddr, const char *buf, unsigned short len)
+{
+ struct ei_device *ei_local = (struct ei_device *)(dev->priv);
+ outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD);
+ outb_p(ENISR_RDC, ioaddr+EN0_ISR);
+ outb_p(len & 0xff, ioaddr+EN0_RCNTLO);
+ outb_p(len >> 8, ioaddr+EN0_RCNTHI);
+ outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO);
+ outb_p(memaddr >> 8, ioaddr+EN0_RSARHI);
+ outb_p(E8390_RWRITE | E8390_START, ioaddr+E8390_CMD);
+ outsw(ioaddr+NE_DATAPORT, buf, len >> 1);
+}
+#endif
+
+static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr);
+/* End of ne2k_cbus.h */

2003-03-09 04:08:57

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (6/20) DMA

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (6/20)

DMA support for PC98.
For fix differences of IO port assign and memory addressing.
PC98 has 'page register' to expand DMA accesible address.

Regards,
Osamu Tomita


diff -Nru linux/include/asm-i386/dma.h linux98/include/asm-i386/dma.h
--- linux/include/asm-i386/dma.h 2002-07-21 04:52:59.000000000 +0900
+++ linux98/include/asm-i386/dma.h 2002-08-17 22:15:06.000000000 +0900
@@ -10,6 +10,9 @@

#include <linux/config.h>
#include <linux/spinlock.h> /* And spinlocks */
+#ifdef CONFIG_X86_PC9800
+#include <asm/pc9800_dma.h>
+#else /* !CONFIG_X86_PC9800 */
#include <asm/io.h> /* need byte IO */
#include <linux/delay.h>

@@ -72,8 +75,10 @@

#define MAX_DMA_CHANNELS 8

+#ifndef CONFIG_X86_PC9800
/* The maximum address that we can perform a DMA transfer to on this platform */
#define MAX_DMA_ADDRESS (PAGE_OFFSET+0x1000000)
+#endif

/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
@@ -295,4 +300,6 @@
#define isa_dma_bridge_buggy (0)
#endif

+#endif /* CONFIG_X86_PC9800 */
+
#endif /* _ASM_DMA_H */
diff -Nru linux/include/asm-i386/pc9800_dma.h linux98/include/asm-i386/pc9800_dma.h
--- linux/include/asm-i386/pc9800_dma.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/pc9800_dma.h 2002-08-17 21:15:01.000000000 +0900
@@ -0,0 +1,238 @@
+/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ */
+
+#ifndef _ASM_PC9800_DMA_H
+#define _ASM_PC9800_DMA_H
+
+#include <linux/config.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/delay.h>
+
+
+#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#define dma_outb outb_p
+#else
+#define dma_outb outb
+#endif
+
+#define dma_inb inb
+
+/*
+ * NOTES about DMA transfers:
+ *
+ * controller 1: channels 0-3, byte operations, ports 00-1F
+ * controller 2: channels 4-7, word operations, ports C0-DF
+ *
+ * - ALL registers are 8 bits only, regardless of transfer size
+ * - channel 4 is not used - cascades 1 into 2.
+ * - channels 0-3 are byte - addresses/counts are for physical bytes
+ * - channels 5-7 are word - addresses/counts are for physical words
+ * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
+ * - transfer count loaded to registers is 1 less than actual count
+ * - controller 2 offsets are all even (2x offsets for controller 1)
+ * - page registers for 5-7 don't use data bit 0, represent 128K pages
+ * - page registers for 0-3 use bit 0, represent 64K pages
+ *
+ * DMA transfers are limited to the lower 16MB of _physical_ memory.
+ * Note that addresses loaded into registers must be _physical_ addresses,
+ * not logical addresses (which may differ if paging is active).
+ *
+ * Address mapping for channels 0-3:
+ *
+ * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses)
+ * | ... | | ... | | ... |
+ * | ... | | ... | | ... |
+ * | ... | | ... | | ... |
+ * P7 ... P0 A7 ... A0 A7 ... A0
+ * | Page | Addr MSB | Addr LSB | (DMA registers)
+ *
+ * Address mapping for channels 5-7:
+ *
+ * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses)
+ * | ... | \ \ ... \ \ \ ... \ \
+ * | ... | \ \ ... \ \ \ ... \ (not used)
+ * | ... | \ \ ... \ \ \ ... \
+ * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0
+ * | Page | Addr MSB | Addr LSB | (DMA registers)
+ *
+ * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
+ * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
+ * the hardware level, so odd-byte transfers aren't possible).
+ *
+ * Transfer count (_not # bytes_) is limited to 64K, represented as actual
+ * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more,
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation.
+ *
+ */
+
+#define MAX_DMA_CHANNELS 4
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+#define MAX_DMA_ADDRESS (~0UL)
+
+/* 8237 DMA controllers */
+#define IO_DMA_BASE 0x01
+
+/* DMA controller registers */
+#define DMA_CMD_REG ((IO_DMA_BASE)+0x10) /* command register (w) */
+#define DMA_STAT_REG ((IO_DMA_BASE)+0x10) /* status register (r) */
+#define DMA_REQ_REG ((IO_DMA_BASE)+0x12) /* request register (w) */
+#define DMA_MASK_REG ((IO_DMA_BASE)+0x14) /* single-channel mask (w) */
+#define DMA_MODE_REG ((IO_DMA_BASE)+0x16) /* mode register (w) */
+#define DMA_CLEAR_FF_REG ((IO_DMA_BASE)+0x18) /* clear pointer flip-flop (w) */
+#define DMA_TEMP_REG ((IO_DMA_BASE)+0x1A) /* Temporary Register (r) */
+#define DMA_RESET_REG ((IO_DMA_BASE)+0x1A) /* Master Clear (w) */
+#define DMA_CLR_MASK_REG ((IO_DMA_BASE)+0x1C) /* Clear Mask */
+#define DMA_MASK_ALL_REG ((IO_DMA_BASE)+0x1E) /* all-channels mask (w) */
+
+#define DMA_PAGE_0 0x27 /* DMA page registers */
+#define DMA_PAGE_1 0x21
+#define DMA_PAGE_2 0x23
+#define DMA_PAGE_3 0x25
+
+#define DMA_Ex_PAGE_0 0xe05 /* DMA Extended page reg base */
+#define DMA_Ex_PAGE_1 0xe07
+#define DMA_Ex_PAGE_2 0xe09
+#define DMA_Ex_PAGE_3 0xe0b
+
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_AUTOINIT 0x10
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+ dma_outb(dmanr, DMA_MASK_REG);
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+ dma_outb(dmanr | 4, DMA_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while holding the DMA lock ! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+ dma_outb(0, DMA_CLEAR_FF_REG);
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+ dma_outb(mode | dmanr, DMA_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, unsigned int pagenr)
+{
+ unsigned char low=pagenr&0xff;
+ unsigned char hi=pagenr>>8;
+
+ switch(dmanr) {
+ case 0:
+ dma_outb(low, DMA_PAGE_0);
+ dma_outb(hi, DMA_Ex_PAGE_0);
+ break;
+ case 1:
+ dma_outb(low, DMA_PAGE_1);
+ dma_outb(hi, DMA_Ex_PAGE_1);
+ break;
+ case 2:
+ dma_outb(low, DMA_PAGE_2);
+ dma_outb(hi, DMA_Ex_PAGE_2);
+ break;
+ case 3:
+ dma_outb(low, DMA_PAGE_3);
+ dma_outb(hi, DMA_Ex_PAGE_3);
+ break;
+ }
+}
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ set_dma_page(dmanr, a>>16);
+ dma_outb( a & 0xff, ((dmanr&3)<<2) + IO_DMA_BASE );
+ dma_outb( (a>>8) & 0xff, ((dmanr&3)<<2) + IO_DMA_BASE );
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ count--;
+ dma_outb( count & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA_BASE );
+ dma_outb( (count>>8) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA_BASE );
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+ /* using short to get 16-bit wrap around */
+ unsigned short count;
+
+ count = 1 + dma_inb(((dmanr&3)<<2) + 2 + IO_DMA_BASE);
+ count += dma_inb(((dmanr&3)<<2) + 2 + IO_DMA_BASE) << 8;
+
+ return count;
+}
+
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr); /* release it again */
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy (0)
+#endif
+
+#endif /* _ASM_PC9800_DMA_H */
diff -Nru linux/include/asm-i386/scatterlist.h linux98/include/asm-i386/scatterlist.h
--- linux/include/asm-i386/scatterlist.h 2002-04-15 04:18:52.000000000 +0900
+++ linux98/include/asm-i386/scatterlist.h 2002-04-17 10:37:22.000000000 +0900
@@ -1,6 +1,8 @@
#ifndef _I386_SCATTERLIST_H
#define _I386_SCATTERLIST_H

+#include <linux/config.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
@@ -8,6 +10,10 @@
unsigned int length;
};

+#ifdef CONFIG_X86_PC9800
+#define ISA_DMA_THRESHOLD (0xffffffff)
+#else
#define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif

#endif /* !(_I386_SCATTERLIST_H) */
diff -Nru linux/kernel/dma.c linux98/kernel/dma.c
--- linux/kernel/dma.c 2002-08-11 10:41:22.000000000 +0900
+++ linux98/kernel/dma.c 2002-08-21 09:53:59.000000000 +0900
@@ -9,6 +9,7 @@
* [It also happened to remove the sizeof(char *) == sizeof(int)
* assumption introduced because of those /proc/dma patches. -- Hennus]
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -62,10 +63,12 @@
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
+#ifndef CONFIG_X86_PC9800
{ 1, "cascade" },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
+#endif
};


2003-03-09 04:21:40

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (15/20) RTC

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (15/20)

Support RTC for PC98, using mach-* scheme.
Replace set_rtc_mmss() and get_cmos_time().

Regards,
Osamu Tomita


diff -Nru linux-2.5.63/arch/i386/kernel/time.c linux98-2.5.63/arch/i386/kernel/time.c
--- linux-2.5.63/arch/i386/kernel/time.c 2003-02-25 04:05:32.000000000 +0900
+++ linux98-2.5.63/arch/i386/kernel/time.c 2003-03-04 20:51:39.000000000 +0900
@@ -55,12 +55,15 @@
#include <asm/processor.h>
#include <asm/timer.h>

-#include <linux/mc146818rtc.h>
+#include "mach_time.h"
+
#include <linux/timex.h>
#include <linux/config.h>

#include <asm/arch_hooks.h>

+#include "io_ports.h"
+
extern spinlock_t i8259A_lock;
int pit_latch_buggy; /* extern */

@@ -138,69 +141,13 @@
clock_was_set();
}

-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you'll only notice that after reboot!
- */
static int set_rtc_mmss(unsigned long nowtime)
{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- unsigned char save_control, save_freq_select;
+ int retval;

/* gets recalled with irq locally disabled */
spin_lock(&rtc_lock);
- save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- cmos_minutes = CMOS_READ(RTC_MINUTES);
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- BCD_TO_BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- }
- CMOS_WRITE(real_seconds,RTC_SECONDS);
- CMOS_WRITE(real_minutes,RTC_MINUTES);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ retval = mach_set_rtc_mmss(nowtime);
spin_unlock(&rtc_lock);

return retval;
@@ -226,9 +173,9 @@
* on an 82489DX-based system.
*/
spin_lock(&i8259A_lock);
- outb(0x0c, 0x20);
+ outb(0x0c, PIC_MASTER_OCW3);
/* Ack the IRQ; AEOI will end it automatically. */
- inb(0x20);
+ inb(PIC_MASTER_POLL);
spin_unlock(&i8259A_lock);
}
#endif
@@ -242,14 +189,16 @@
*/
if ((time_status & STA_UNSYNC) == 0 &&
xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+ (xtime.tv_nsec / 1000)
+ >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
+ (xtime.tv_nsec / 1000)
+ <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
-
+
#ifdef CONFIG_MCA
if( MCA_bus ) {
/* The PS/2 uses level-triggered interrupts. You can't
@@ -330,43 +279,15 @@
/* not static: needed by APM */
unsigned long get_cmos_time(void)
{
- unsigned int year, mon, day, hour, min, sec;
- int i;
+ unsigned long retval;

spin_lock(&rtc_lock);
- /* The Linux interpretation of the CMOS clock register contents:
- * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
- * RTC registers show the second which has precisely just started.
- * Let's hope other operating systems interpret the RTC the same way.
- */
- /* read RTC exactly on falling edge of update flag */
- for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
- if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
- break;
- for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
- if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
- break;
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
- } while (sec != CMOS_READ(RTC_SECONDS));
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
+
+ retval = mach_get_cmos_time();
+
spin_unlock(&rtc_lock);
- if ((year += 1900) < 1970)
- year += 100;
- return mktime(year, mon, day, hour, min, sec);
+
+ return retval;
}

/* XXX this driverfs stuff should probably go elsewhere later -john */
diff -Nru linux/include/asm-i386/mach-default/mach_time.h linux98/include/asm-i386/mach-default/mach_time.h
--- linux/include/asm-i386/mach-default/mach_time.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-default/mach_time.h 2003-03-04 20:52:21.000000000 +0900
@@ -0,0 +1,122 @@
+/*
+ * include/asm-i386/mach-default/mach_time.h
+ *
+ * Machine specific set RTC function for generic.
+ * Split out from time.c by Osamu Tomita <[email protected]>
+ */
+#ifndef _MACH_TIME_H
+#define _MACH_TIME_H
+
+#include <linux/mc146818rtc.h>
+
+/* for check timing call set_rtc_mmss() 500ms */
+/* used in arch/i386/time.c::do_timer_interrupt() */
+#define USEC_AFTER 500000
+#define USEC_BEFORE 500000
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you'll only notice that after reboot!
+ */
+static inline int mach_set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+}
+
+static inline unsigned long mach_get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+#endif /* !_MACH_TIME_H */
diff -Nru linux/include/asm-i386/mach-pc9800/mach_time.h linux98/include/asm-i386/mach-pc9800/mach_time.h
--- linux/include/asm-i386/mach-pc9800/mach_time.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/mach_time.h 2003-03-04 20:52:02.000000000 +0900
@@ -0,0 +1,100 @@
+/*
+ * include/asm-i386/mach-pc9800/mach_time.h
+ *
+ * Machine specific set RTC function for PC-9800.
+ * Written by Osamu Tomita <[email protected]>
+ */
+#ifndef _MACH_TIME_H
+#define _MACH_TIME_H
+
+#include <linux/bcd.h>
+#include <linux/upd4990a.h>
+
+/* for check timing call set_rtc_mmss() */
+/* used in arch/i386/time.c::do_timer_interrupt() */
+/*
+ * Because PC-9800's RTC (NEC uPD4990A) does not allow setting
+ * time partially, we always have to read-modify-write the
+ * entire time (including year) so that set_rtc_mmss() will
+ * take quite much time to execute. You may want to relax
+ * RTC resetting interval (currently ~11 minuts)...
+ */
+#define USEC_AFTER 1000000
+#define USEC_BEFORE 0
+
+static inline int mach_set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ struct upd4990a_raw_data data;
+
+ upd4990a_get_time(&data, 1);
+ cmos_minutes = BCD2BIN(data.min);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ u8 temp_seconds = (real_seconds / 10) * 16 + real_seconds % 10;
+ u8 temp_minutes = (real_minutes / 10) * 16 + real_minutes % 10;
+
+ if (data.sec != temp_seconds || data.min != temp_minutes) {
+ data.sec = temp_seconds;
+ data.min = temp_minutes;
+ upd4990a_set_time(&data, 1);
+ }
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* uPD4990A users' manual says we should issue Register Hold
+ * command after reading time, or future Time Read command
+ * may not work. When we have set the time, this also starts
+ * the clock.
+ */
+ upd4990a_serial_command(UPD4990A_REGISTER_HOLD);
+
+ return retval;
+}
+
+static inline unsigned long mach_get_cmos_time(void)
+{
+ int i;
+ u8 prev, cur;
+ unsigned int year;
+ struct upd4990a_raw_data data;
+
+ /* Connect uPD4990A's DATA OUT pin to its 1Hz reference clock. */
+ upd4990a_serial_command(UPD4990A_REGISTER_HOLD);
+
+ /* Catch rising edge of reference clock. */
+ prev = ~UPD4990A_READ_DATA();
+ for (i = 0; i < 1800000; i++) { /* may take up to 1 second... */
+ __asm__ ("outb %%al,%0" : : "N" (0x5f)); /* 0.6usec delay */
+ cur = UPD4990A_READ_DATA();
+ if (!(prev & cur & 1))
+ break;
+ prev = ~cur;
+ }
+
+ upd4990a_get_time(&data, 0);
+
+ if ((year = BCD2BIN(data.year) + 1900) < 1995)
+ year += 100;
+ return mktime(year, data.mon, BCD2BIN(data.mday), BCD2BIN(data.hour),
+ BCD2BIN(data.min), BCD2BIN(data.sec));
+}
+
+#endif /* !_MACH_TIME_H */

2003-03-09 04:13:18

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (9/20) kanji

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (9/20)

Add japanese kanji character support to PC98 console.

Regards,
Osamu Tomita

diff -Nru linux/drivers/char/console_macros.h linux98/drivers/char/console_macros.h
--- linux/drivers/char/console_macros.h Sat Oct 19 13:01:17 2002
+++ linux98/drivers/char/console_macros.h Mon Oct 28 16:53:39 2002
@@ -64,6 +64,16 @@
#define complement_mask (vc_cons[currcons].d->vc_complement_mask)
#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask)
#define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask)
+#define kanji_mode (vc_cons[currcons].d->vc_kanji_mode)
+#define s_kanji_mode (vc_cons[currcons].d->vc_s_kanji_mode)
+#define kanji_char1 (vc_cons[currcons].d->vc_kanji_char1)
+#define translate_ex (vc_cons[currcons].d->vc_translate_ex)
+#define G0_charset_ex (vc_cons[currcons].d->vc_G0_charset_ex)
+#define G1_charset_ex (vc_cons[currcons].d->vc_G1_charset_ex)
+#define saved_G0_ex (vc_cons[currcons].d->vc_saved_G0_ex)
+#define saved_G1_ex (vc_cons[currcons].d->vc_saved_G1_ex)
+#define kanji_jis_mode (vc_cons[currcons].d->vc_kanji_jis_mode)
+#define s_kanji_jis_mode (vc_cons[currcons].d->vc_s_kanji_jis_mode)

#define vcmode (vt_cons[currcons]->vc_mode)

diff -Nru linux/drivers/char/vt.c linux98/drivers/char/vt.c
--- linux/drivers/char/vt.c 2002-12-16 11:08:16.000000000 +0900
+++ linux98/drivers/char/vt.c 2002-12-20 14:52:06.000000000 +0900
@@ -151,6 +151,10 @@
static void blank_screen(unsigned long dummy);
static void gotoxy(int currcons, int new_x, int new_y);
static void save_cur(int currcons);
+#ifdef CONFIG_KANJI
+static void save_cur_kanji(int currcons);
+static void restore_cur_kanji(int currcons);
+#endif
static void reset_terminal(int currcons, int do_clear);
static void con_flush_chars(struct tty_struct *tty);
static void set_vesa_blanking(unsigned long arg);
@@ -433,6 +437,25 @@
do_update_region(currcons, (unsigned long) p, count);
}

+#ifdef CONFIG_KANJI
+/* can called form keyboard.c */
+void do_change_kanji_mode(int currcons, unsigned long mode)
+{
+ switch (mode) {
+ case 0:
+ kanji_mode = EUC_CODE;
+ break;
+ case 1:
+ kanji_mode = JIS_CODE;
+ break;
+ case 2:
+ kanji_mode = SJIS_CODE;
+ break;
+ }
+ kanji_char1 = 0;
+}
+#endif /* CONFIG_KANJI */
+
/* used by selection: complement pointer position */
void complement_pos(int currcons, int offset)
{
@@ -1085,6 +1108,9 @@
translate = set_translate(charset == 0
? G0_charset
: G1_charset,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = (charset == 0 ? G0_charset_ex : G1_charset_ex);
+#endif
disp_ctrl = 0;
toggle_meta = 0;
break;
@@ -1093,6 +1119,9 @@
* chars < 32 be displayed as ROM chars.
*/
translate = set_translate(IBMPC_MAP,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = 0;
+#endif
disp_ctrl = 1;
toggle_meta = 0;
break;
@@ -1101,6 +1130,9 @@
* high bit before displaying as ROM char.
*/
translate = set_translate(IBMPC_MAP,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = 0;
+#endif
disp_ctrl = 1;
toggle_meta = 1;
break;
@@ -1310,6 +1342,22 @@
case 14: /* set vesa powerdown interval */
vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
break;
+#ifdef CONFIG_KANJI
+ case 98:
+ if (par[1] < 10) /* change kanji mode */
+ do_change_kanji_mode(currcons, par[1]); /* 0208 */
+ else if (par[1] == 10) { /* save restore kanji mode */
+ switch (par[2]) {
+ case 1:
+ save_cur_kanji(currcons);
+ break;
+ case 2:
+ restore_cur_kanji(currcons);
+ break;
+ }
+ }
+ break;
+#endif /* CONFIG_KANJI */
}
}

@@ -1387,8 +1435,26 @@
need_wrap = 0;
}

+#ifdef CONFIG_KANJI
+static void save_cur_kanji(int currcons)
+{
+ s_kanji_mode = kanji_mode;
+ s_kanji_jis_mode = kanji_jis_mode;
+}
+
+static void restore_cur_kanji(int currcons)
+{
+ kanji_mode = s_kanji_mode;
+ kanji_jis_mode = s_kanji_jis_mode;
+ kanji_char1 = 0;
+}
+#endif
+
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+#ifdef CONFIG_KANJI
+ ESsetJIS, ESsetJIS2,
+#endif
ESpalette };

/* console_sem is held (except via vc_init()) */
@@ -1398,9 +1464,18 @@
bottom = video_num_lines;
vc_state = ESnormal;
ques = 0;
+#ifdef CONFIG_KANJI
+ translate = set_translate(JP_MAP, currcons);
+ translate_ex = 0;
+ G0_charset = JP_MAP;
+ G0_charset_ex = 0;
+ G1_charset = GRAF_MAP;
+ G1_charset_ex = 0;
+#else
translate = set_translate(LAT1_MAP,currcons);
G0_charset = LAT1_MAP;
G1_charset = GRAF_MAP;
+#endif
charset = 0;
need_wrap = 0;
report_mouse = 0;
@@ -1442,6 +1517,12 @@
bell_pitch = DEFAULT_BELL_PITCH;
bell_duration = DEFAULT_BELL_DURATION;

+#ifdef CONFIG_KANJI
+ kanji_mode = EUC_CODE;
+ kanji_char1 = 0;
+ kanji_jis_mode = JIS_CODE_ASCII;
+#endif
+
gotoxy(currcons,0,0);
save_cur(currcons);
if (do_clear)
@@ -1484,11 +1565,17 @@
case 14:
charset = 1;
translate = set_translate(G1_charset,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = G1_charset_ex;
+#endif
disp_ctrl = 1;
return;
case 15:
charset = 0;
translate = set_translate(G0_charset,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = G0_charset_ex;
+#endif
disp_ctrl = 0;
return;
case 24: case 26:
@@ -1545,6 +1632,11 @@
case ')':
vc_state = ESsetG1;
return;
+#ifdef CONFIG_KANJI
+ case '$':
+ vc_state = ESsetJIS;
+ return;
+#endif
case '#':
vc_state = EShash;
return;
@@ -1794,8 +1886,25 @@
G0_charset = IBMPC_MAP;
else if (c == 'K')
G0_charset = USER_MAP;
- if (charset == 0)
+#ifdef CONFIG_KANJI
+ G0_charset_ex = 0;
+ if (c == 'J')
+ G0_charset = JP_MAP;
+ else if (c == 'I'){
+ G0_charset = JP_MAP;
+ G0_charset_ex = 1;
+ }
+#endif /* CONFIG_KANJI */
+ if (charset == 0) {
translate = set_translate(G0_charset,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = G0_charset_ex;
+#endif
+ }
+#ifdef CONFIG_KANJI
+ kanji_jis_mode = JIS_CODE_ASCII;
+ kanji_char1 = 0;
+#endif
vc_state = ESnormal;
return;
case ESsetG1:
@@ -1807,10 +1916,51 @@
G1_charset = IBMPC_MAP;
else if (c == 'K')
G1_charset = USER_MAP;
- if (charset == 1)
+#ifdef CONFIG_KANJI
+ G1_charset_ex = 0;
+ if (c == 'J')
+ G1_charset = JP_MAP;
+ else if (c == 'I') {
+ G1_charset = JP_MAP;
+ G1_charset_ex = 1;
+ }
+#endif /* CONFIG_KANJI */
+ if (charset == 1) {
translate = set_translate(G1_charset,currcons);
+#ifdef CONFIG_KANJI
+ translate_ex = G1_charset_ex;
+#endif
+ }
+#ifdef CONFIG_KANJI
+ kanji_jis_mode = JIS_CODE_ASCII;
+ kanji_char1 = 0;
+#endif
+ vc_state = ESnormal;
+ return;
+#ifdef CONFIG_KANJI
+ case ESsetJIS:
+ if (c == '@')
+ kanji_jis_mode = JIS_CODE_78;
+ else if (c == 'B')
+ kanji_jis_mode = JIS_CODE_83;
+ else if (c == '('){
+ vc_state = ESsetJIS2;
+ return;
+ } else {
+ vc_state = ESnormal;
+ return;
+ }
vc_state = ESnormal;
+ kanji_char1 = 0;
return;
+ case ESsetJIS2:
+ if (c == 'D'){
+ kanji_jis_mode = JIS_CODE_90;
+ kanji_char1 = 0;
+ }
+ vc_state = ESnormal;
+ return;
+#endif /* CONIFG_KANJI */
default:
vc_state = ESnormal;
}
@@ -1842,7 +1992,7 @@
}
#endif

- int c, tc, ok, n = 0, draw_x = -1;
+ int c, tc = 0, ok, n = 0, draw_x = -1;
unsigned int currcons;
unsigned long draw_from = 0, draw_to = 0;
struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
@@ -1899,48 +2049,151 @@
hide_cursor(currcons);

while (!tty->stopped && count) {
+ int realkanji = 0;
+ int kanjioverrun = 0;
c = *buf;
buf++;
n++;
count--;

- if (utf) {
- /* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
- if(c > 0x7f) {
- if (utf_count > 0 && (c & 0xc0) == 0x80) {
- utf_char = (utf_char << 6) | (c & 0x3f);
- utf_count--;
- if (utf_count == 0)
- tc = c = utf_char;
- else continue;
- } else {
- if ((c & 0xe0) == 0xc0) {
- utf_count = 1;
- utf_char = (c & 0x1f);
- } else if ((c & 0xf0) == 0xe0) {
- utf_count = 2;
- utf_char = (c & 0x0f);
- } else if ((c & 0xf8) == 0xf0) {
- utf_count = 3;
- utf_char = (c & 0x07);
- } else if ((c & 0xfc) == 0xf8) {
- utf_count = 4;
- utf_char = (c & 0x03);
- } else if ((c & 0xfe) == 0xfc) {
- utf_count = 5;
- utf_char = (c & 0x01);
- } else
- utf_count = 0;
- continue;
- }
- } else {
- tc = c;
- utf_count = 0;
- }
- } else { /* no utf */
- tc = translate[toggle_meta ? (c|0x80) : c];
- }
+#ifdef CONFIG_KANJI
+ if (vc_state == ESnormal && !disp_ctrl) {
+ switch (kanji_jis_mode) {
+ case JIS_CODE_78:
+ case JIS_CODE_83:
+ case JIS_CODE_90:
+ if (utf)
+ break;
+ if (c >= 127 || c <= 0x20) {
+ kanji_char1 = 0;
+ break;
+ }
+ if (kanji_char1) {
+ tc = (((unsigned int)kanji_char1) << 8) |
+ (((unsigned int)c) & 0x007f);
+ kanji_char1 = 0;
+ realkanji = 1;
+ } else {
+ kanji_char1 = ((unsigned int)c) & 0x007f;
+ continue;
+ }
+ break;
+ case JIS_CODE_ASCII:
+ default:
+ switch (kanji_mode) {
+ case SJIS_CODE:
+ if (kanji_char1) {
+ if ((0x40 <= c && c <= 0x7E) ||
+ (0x80 <= c && c <= 0xFC)) {
+ realkanji = 1;
+ /* SJIS to JIS */
+ kanji_char1 <<= 1; /* 81H-9FH --> 22H-3EH */
+ /* EOH-EFH --> C0H-DEH */
+ c -= 0x1f; /* 40H-7EH --> 21H-5FH */
+ /* 80H-9EH --> 61H-7FH */
+ /* 9FH-FCH --> 80H-DDH */
+ if (!(c & 0x80)) {
+ if (c < 0x61)
+ c++;
+ c += 0xde;
+ }
+ c &= 0xff;
+ c += 0xa1;
+ kanji_char1 += 0x1f;
+ tc = (kanji_char1 << 8) + c;
+ tc &= 0x7f7f;
+ kanji_char1 = 0;
+ }
+ } else {
+ if ((0x81 <= c && c <= 0x9f) ||
+ (0xE0 <= c && c <= 0xEF)) {
+ realkanji = 1;
+ kanji_char1 = c;
+ continue;
+ } else if (0xA1 <= c && c <= 0xDF) {
+ tc = (unsigned int)translations[JP_MAP][c];
+ goto hankana_skip;
+ }
+ }
+ break;
+ case EUC_CODE:
+ if (utf)
+ break;
+ if (c <= 0x7f) {
+ kanji_char1 = 0;
+ break;
+ }
+ if (kanji_char1) {
+ if (kanji_char1 == 0x8e) { /* SS2 */
+ /* realkanji ha tatenai */
+ tc = (unsigned int)translations[JP_MAP][c];
+ kanji_char1 = 0;
+ goto hankana_skip;
+ } else {
+ tc = (((unsigned int)kanji_char1) << 8) |
+ (((unsigned int)c) & 0x007f);
+ kanji_char1 = 0;
+ realkanji = 1;
+ }
+ } else {
+ kanji_char1 = (unsigned int)c;
+ continue;
+ }
+ break;
+ case JIS_CODE:
+ /* to be supported */
+ break;
+ } /* switch (kanji_mode) */
+ } /* switch (kanji_jis_mode) */
+ } /* if (vc_state == ESnormal) */
+
+#endif /* CONFIG_KANJI */
+ if (!realkanji) {
+ if (utf) {
+ /* Combine UTF-8 into Unicode */
+ /* Incomplete characters silently ignored */
+ if(c > 0x7f) {
+ if (utf_count > 0 && (c & 0xc0) == 0x80) {
+ utf_char = (utf_char << 6) | (c & 0x3f);
+ utf_count--;
+ if (utf_count == 0)
+ tc = c = utf_char;
+ else continue;
+ } else {
+ if ((c & 0xe0) == 0xc0) {
+ utf_count = 1;
+ utf_char = (c & 0x1f);
+ } else if ((c & 0xf0) == 0xe0) {
+ utf_count = 2;
+ utf_char = (c & 0x0f);
+ } else if ((c & 0xf8) == 0xf0) {
+ utf_count = 3;
+ utf_char = (c & 0x07);
+ } else if ((c & 0xfc) == 0xf8) {
+ utf_count = 4;
+ utf_char = (c & 0x03);
+ } else if ((c & 0xfe) == 0xfc) {
+ utf_count = 5;
+ utf_char = (c & 0x01);
+ } else
+ utf_count = 0;
+ continue;
+ }
+ } else {
+ tc = c;
+ utf_count = 0;
+ }
+ } else { /* no utf */
+#ifdef CONFIG_KANJI
+ tc = translate[(toggle_meta || translate_ex) ? (c | 0x80) : c];
+#else
+ tc = translate[toggle_meta ? (c|0x80) : c];
+#endif
+ }
+ } /* if (!realkanji) */
+#ifdef CONFIG_KANJI
+ hankana_skip:
+#endif

/* If the original code was a control character we
* only allow a glyph to be displayed if the code is
@@ -1957,43 +2210,71 @@
: CTRL_ACTION) >> c) & 1)))
&& (c != 127 || disp_ctrl)
&& (c != 128+27);
+ ok |= realkanji;

if (vc_state == ESnormal && ok) {
- /* Now try to find out how to display it */
- tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
- if ( tc == -4 ) {
+ if (!realkanji) {
+ /* Now try to find out how to display it */
+ tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
+ if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);

/* One reason for the -4 can be that we just
did a clear_unimap();
try at least to show something. */
- if (tc == -4)
- tc = c;
- } else if ( tc == -3 ) {
+ if (tc == -4)
+ tc = c;
+ } else if ( tc == -3 ) {
/* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~charmask)
- continue; /* Conversion failed */
+ tc = c;
+ }
+ if (tc & ~charmask)
+ continue; /* Conversion failed */
+ } /* !realkanji */

if (need_wrap || decim)
FLUSH
if (need_wrap) {
cr(currcons);
lf(currcons);
+ if (kanjioverrun) {
+ x++;
+ pos += 2;
+ kanjioverrun = 0;
+ }
}
if (decim)
insert_char(currcons, 1);
+#ifndef CONFIG_KANJI
scr_writew(himask ?
((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
(attr << 8) + tc,
(u16 *) pos);
+#else /* CONFIG_KANJI */
+ if (realkanji) {
+ tc = ((tc >> 8) & 0xff) | ((tc << 8) & 0xff00);
+ *((u16 *)pos) = (tc - 0x20) & 0xff7f;
+ *(pc9800_attr_offset((u16 *)pos)) = attr;
+ x ++;
+ pos += 2;
+ *((u16 *)pos) = (tc - 0x20) | 0x80;
+ *(pc9800_attr_offset((u16 *)pos)) = attr;
+ } else {
+ *((u16 *)pos) = tc & 0x00ff;
+ *(pc9800_attr_offset((u16 *)pos)) = attr;
+ }
+#endif /* !CONFIG_KANJI */
if (DO_UPDATE && draw_x < 0) {
draw_x = x;
draw_from = pos;
+ if (realkanji) {
+ draw_x --;
+ draw_from -= 2;
+ }
}
+#ifndef CONFIG_KANJI
if (x == video_num_columns - 1) {
need_wrap = decawm;
draw_to = pos+2;
@@ -2001,6 +2282,16 @@
x++;
draw_to = (pos+=2);
}
+#else /* CONFIG_KANJI */
+ if (x >= video_num_columns - 1) {
+ need_wrap = decawm;
+ kanjioverrun = x - video_num_columns + 1;
+ draw_to = pos + 2;
+ } else {
+ x++;
+ draw_to = (pos += 2);
+ }
+#endif /* !CONFIG_KANJI */
continue;
}
FLUSH
diff -Nru linux-2.5.61/drivers/video/console/Kconfig linux98-2.5.61/drivers/video/console/Kconfig
--- linux-2.5.61/drivers/video/console/Kconfig 2003-02-15 08:51:21.000000000 +0900
+++ linux98-2.5.61/drivers/video/console/Kconfig 2003-02-16 14:48:08.000000000 +0900
@@ -221,5 +221,9 @@
bool "Mini 4x6 font"
depends on !SPARC32 && !SPARC64 && FONTS

+config KANJI
+ bool "Japanese Kanji support"
+ depends on X86_PC9800
+
endmenu

diff -Nru linux/include/linux/console_struct.h linux98/include/linux/console_struct.h
--- linux/include/linux/console_struct.h 2002-12-10 11:45:40.000000000 +0900
+++ linux98/include/linux/console_struct.h 2002-12-16 13:25:55.000000000 +0900
@@ -83,6 +83,18 @@
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
unsigned long vc_uni_pagedir;
unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
+#ifdef CONFIG_KANJI
+ unsigned char vc_kanji_char1;
+ unsigned char vc_kanji_mode;
+ unsigned char vc_kanji_jis_mode;
+ unsigned char vc_s_kanji_mode;
+ unsigned char vc_s_kanji_jis_mode;
+ unsigned int vc_translate_ex;
+ unsigned char vc_G0_charset_ex;
+ unsigned char vc_G1_charset_ex;
+ unsigned char vc_saved_G0_ex;
+ unsigned char vc_saved_G1_ex;
+#endif /* CONFIG_KANJI */
/* additional information is in vt_kern.h */
};

diff -Nru linux/include/linux/consolemap.h linux98/include/linux/consolemap.h
--- linux/include/linux/consolemap.h Sat Oct 19 13:02:34 2002
+++ linux98/include/linux/consolemap.h Mon Oct 21 14:19:31 2002
@@ -7,6 +7,7 @@
#define GRAF_MAP 1
#define IBMPC_MAP 2
#define USER_MAP 3
+#define JP_MAP 4

struct vc_data;

2003-03-09 04:10:54

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (7/20) IDE

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (7/20)

PC98 standard IDE I/F support.
- Change default IO port address and IRQ.
- Add chipset "ide_pc9800".
- Add IDE0/1 select function becase PC98 uses common IO port to access them.
- Request region exactly for other optional cards.
- Get BIOS C/H/S parameter for PC98.

Regards,
Osamu Tomita


diff -Nru linux-2.5.63/drivers/ide/Kconfig linux98-2.5.63/drivers/ide/Kconfig
--- linux-2.5.63/drivers/ide/Kconfig 2003-02-25 13:54:34.000000000 +0900
+++ linux98-2.5.63/drivers/ide/Kconfig 2003-02-25 16:00:02.000000000 +0900
@@ -1053,6 +1053,11 @@

If unsure, say N.

+config BLK_DEV_IDE_PC9800
+ bool
+ depends on X86_PC9800
+ default y
+
##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then
## dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK
##else
diff -Nru linux-2.5.64-ac3/drivers/ide/ide-disk.c linux98-2.5.64-ac3/drivers/ide/ide-disk.c
--- linux-2.5.64-ac3/drivers/ide/ide-disk.c 2003-03-08 12:13:46.000000000 +0900
+++ linux98-2.5.64-ac3/drivers/ide/ide-disk.c 2003-03-08 12:29:29.000000000 +0900
@@ -1574,6 +1574,71 @@

(void) probe_lba_addressing(drive, 1);

+#ifdef CONFIG_X86_PC9800
+ /* XXX - need more checks */
+ if (!drive->nobios && !drive->scsi && !drive->removable) {
+ /* PC-9800's BIOS do pack drive numbers to be continuous,
+ so extra work is needed here. */
+
+ /* drive information passed from boot/setup.S */
+ struct drive_info_struct {
+ u16 cyl;
+ u8 sect, head;
+ u16 ssize;
+ } __attribute__ ((packed));
+ extern struct drive_info_struct drive_info[];
+
+ /* this pointer must be advanced only when *DRIVE is
+ really hard disk. */
+ static struct drive_info_struct *info = drive_info;
+
+ if (info < &drive_info[4] && info->cyl) {
+ drive->cyl = drive->bios_cyl = info->cyl;
+ drive->head = drive->bios_head = info->head;
+ drive->sect = drive->bios_sect = info->sect;
+ ++info;
+ }
+ }
+
+ /* =PC98 MEMO=
+ physical capacity =< 65535*8*17 sect. : H/S=8/17 (fixed)
+ physical capacity > 65535*8*17 sect. : use physical geometry
+ (65535*8*17 = 8912760 sectors)
+ */
+ printk("%s: CHS: physical %d/%d/%d, logical %d/%d/%d, BIOS %d/%d/%d\n",
+ drive->name,
+ id->cyls, id->heads, id->sectors,
+ id->cur_cyls, id->cur_heads, id->cur_sectors,
+ drive->bios_cyl, drive->bios_head,drive->bios_sect);
+ if (!drive->cyl || !drive->head || !drive->sect) {
+ drive->cyl = drive->bios_cyl = id->cyls;
+ drive->head = drive->bios_head = id->heads;
+ drive->sect = drive->bios_sect = id->sectors;
+ printk("%s: not BIOS-supported device.\n",drive->name);
+ }
+ /* calculate drive capacity, and select LBA if possible */
+ init_idedisk_capacity(drive);
+
+ /*
+ * if possible, give fdisk access to more of the drive,
+ * by correcting bios_cyls:
+ */
+ capacity = idedisk_capacity(drive);
+ if (capacity < 8912760 &&
+ (drive->head != 8 || drive->sect != 17)) {
+ drive->head = drive->bios_head = 8;
+ drive->sect = drive->bios_sect = 17;
+ drive->cyl = drive->bios_cyl =
+ capacity / (drive->bios_head * drive->bios_sect);
+ printk("%s: Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
+ drive->name,
+ id->cur_cyls,id->cur_heads,id->cur_sectors,
+ drive->bios_cyl,drive->bios_head,drive->bios_sect);
+ id->cur_cyls = drive->bios_cyl;
+ id->cur_heads = drive->bios_head;
+ id->cur_sectors = drive->bios_sect;
+ }
+#else /* !CONFIG_X86_PC9800 */
/* Extract geometry if we did not already have one for the drive */
if (!drive->cyl || !drive->head || !drive->sect) {
drive->cyl = drive->bios_cyl = id->cyls;
@@ -1607,6 +1672,8 @@
if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
(!drive->forced_geom) && drive->bios_sect && drive->bios_head)
drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+#endif /* CONFIG_X86_PC9800 */
+
printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);

/* Give size in megabytes (MB), not mebibytes (MiB). */
diff -Nru linux/drivers/ide/ide-probe.c linux98/drivers/ide/ide-probe.c
--- linux/drivers/ide/ide-probe.c 2003-02-21 10:00:56.000000000 +0900
+++ linux98/drivers/ide/ide-probe.c 2003-02-21 10:46:24.000000000 +0900
@@ -664,7 +664,7 @@

if (hwif->mmio == 2)
return 0;
- addr_errs = hwif_check_region(hwif, hwif->io_ports[IDE_DATA_OFFSET], 1);
+ addr_errs = hwif_check_region(hwif, hwif->io_ports[IDE_DATA_OFFSET], pc98 ? 2 : 1);
for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++)
addr_errs += hwif_check_region(hwif, hwif->io_ports[i], 1);
if (hwif->io_ports[IDE_CONTROL_OFFSET])
@@ -713,7 +713,9 @@
}

for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- hwif_request_region(hwif->io_ports[i], 1, hwif->name);
+ hwif_request_region(hwif->io_ports[i],
+ (pc98 && i == IDE_DATA_OFFSET) ? 2 : 1,
+ hwif->name);
}

//EXPORT_SYMBOL(hwif_register);
@@ -801,6 +803,9 @@
#if CONFIG_BLK_DEV_PDC4030
(hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
#endif /* CONFIG_BLK_DEV_PDC4030 */
+#if CONFIG_BLK_DEV_IDE_PC9800
+ (hwif->chipset != ide_pc9800 || !hwif->mate->present) &&
+#endif
(hwif_check_regions(hwif))) {
u16 msgout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -1150,7 +1155,7 @@
/* all CPUs; safe now that hwif->hwgroup is set up */
spin_unlock_irqrestore(&ide_lock, flags);

-#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__) && !defined(CONFIG_X86_PC9800)
printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET],
hwif->io_ports[IDE_DATA_OFFSET]+7,
@@ -1160,6 +1165,11 @@
hwif->io_ports[IDE_DATA_OFFSET],
hwif->io_ports[IDE_DATA_OFFSET]+7,
hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
+#elif defined(CONFIG_X86_PC9800)
+ printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
+ hwif->io_ports[IDE_DATA_OFFSET],
+ hwif->io_ports[IDE_DATA_OFFSET]+15,
+ hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
#else
printk("%s at %x on irq 0x%08x", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
diff -Nru linux-2.5.64-ac3/drivers/ide/ide-proc.c linux98-2.5.64-ac3/drivers/ide/ide-proc.c
--- linux-2.5.64-ac3/drivers/ide/ide-proc.c 2003-03-08 12:13:46.000000000 +0900
+++ linux98-2.5.64-ac3/drivers/ide/ide-proc.c 2003-03-08 12:29:29.000000000 +0900
@@ -365,6 +365,7 @@
case ide_cy82c693: name = "cy82c693"; break;
case ide_4drives: name = "4drives"; break;
case ide_pmac: name = "mac-io"; break;
+ case ide_pc9800: name = "pc9800"; break;
default: name = "(unknown)"; break;
}
len = sprintf(page, "%s\n", name);
diff -Nru linux-2.5.64-ac3/drivers/ide/ide.c linux98-2.5.64-ac3/drivers/ide/ide.c
--- linux-2.5.64-ac3/drivers/ide/ide.c 2003-03-08 12:13:46.000000000 +0900
+++ linux98-2.5.64-ac3/drivers/ide/ide.c 2003-03-08 12:29:29.000000000 +0900
@@ -549,7 +549,8 @@
}
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
if (hwif->io_ports[i]) {
- hwif_release_region(hwif->io_ports[i], 1);
+ hwif_release_region(hwif->io_ports[i],
+ (pc98 && i == IDE_DATA_OFFSET) ? 2 : 1);
}
}
}
@@ -2089,6 +2090,12 @@
}
#endif /* CONFIG_BLK_DEV_IDEPCI */

+#ifdef CONFIG_BLK_DEV_IDE_PC9800
+ {
+ extern void ide_probe_for_pc9800(void);
+ ide_probe_for_pc9800();
+ }
+#endif
#ifdef CONFIG_ETRAX_IDE
{
extern void init_e100_ide(void);
diff -Nru linux/drivers/ide/legacy/Makefile linux98/drivers/ide/legacy/Makefile
--- linux/drivers/ide/legacy/Makefile 2002-12-16 11:07:47.000000000 +0900
+++ linux98/drivers/ide/legacy/Makefile 2002-12-17 09:42:08.000000000 +0900
@@ -2,6 +2,7 @@
obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
+obj-$(CONFIG_BLK_DEV_IDE_PC9800) += pc9800.o
obj-$(CONFIG_BLK_DEV_PDC4030) += pdc4030.o
obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
@@ -15,6 +16,10 @@
obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o

# Last of all
+ifneq ($(CONFIG_X86_PC9800),y)
obj-$(CONFIG_BLK_DEV_HD) += hd.o
+else
+obj-$(CONFIG_BLK_DEV_HD) += hd98.o
+endif

EXTRA_CFLAGS := -Idrivers/ide
diff -Nru linux/drivers/ide/legacy/hd98.c linux98/drivers/ide/legacy/hd98.c
--- linux/drivers/ide/legacy/hd98.c 1970-01-01 09:00:00.000000000 +0900
+++ linux98/drivers/ide/legacy/hd98.c 2002-10-26 15:42:09.000000000 +0900
@@ -0,0 +1,904 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ *
+ * modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *
+ * Thanks to Branko Lankester, [email protected], who found a bug
+ * in the early extended-partition checks and added DM partitions
+ *
+ * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ * and general streamlining by Mark Lord.
+ *
+ * Removed 99% of above. Use Mark's ide driver for those options.
+ * This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ * Modified 1995 Russell King for ARM processor.
+ *
+ * Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ * off in a hurry once you queue things up - Paul G. 02/2001
+ */
+
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+#include <linux/hdreg.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#define DEVICE_NR(device) (minor(device)>>6)
+#include <linux/blk.h>
+
+#include "io_ports.h"
+
+#ifdef __arm__
+#undef HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+/* Hd controller regster ports */
+
+#define HD_DATA 0x640 /* _CTL when writing */
+#define HD_ERROR 0x642 /* see err-bits */
+#define HD_NSECTOR 0x644 /* nr of sectors to read/write */
+#define HD_SECTOR 0x646 /* starting sector */
+#define HD_LCYL 0x648 /* starting cylinder */
+#define HD_HCYL 0x64a /* high byte of starting cyl */
+#define HD_CURRENT 0x64c /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x64e /* see status-bits */
+#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
+#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x74c /* used for resets */
+#define HD_ALTSTATUS 0x74c /* same as HD_STATUS but doesn't clear irq */
+
+/* Bits of HD_STATUS */
+#define ERR_STAT 0x01
+#define INDEX_STAT 0x02
+#define ECC_STAT 0x04 /* Corrected error */
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define SERVICE_STAT SEEK_STAT
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR 0x01 /* Bad address mark */
+#define TRK0_ERR 0x02 /* couldn't find track 0 */
+#define ABRT_ERR 0x04 /* Command aborted */
+#define MCR_ERR 0x08 /* media change request */
+#define ID_ERR 0x10 /* ID field not found */
+#define MC_ERR 0x20 /* media changed */
+#define ECC_ERR 0x40 /* Uncorrectable ECC error */
+#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
+#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
+
+static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
+
+#define TIMEOUT_VALUE (6*HZ)
+#define HD_DELAY 0
+
+#define MAX_ERRORS 16 /* Max read/write errors/sector */
+#define RESET_FREQ 8 /* Reset controller every 8th retry */
+#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
+#define MAX_HD 2
+
+#define STAT_OK (READY_STAT|SEEK_STAT)
+#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+
+static int reset;
+static int hd_error;
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
+
+/*
+ * This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+ unsigned int head,sect,cyl,wpcom,lzone,ctl;
+};
+
+#ifdef HD_TYPE
+struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct gendisk *hd_gendisk[MAX_HD];
+
+static struct timer_list device_timer;
+
+#define TIMEOUT_VALUE (6*HZ)
+
+#define SET_TIMER \
+ do { \
+ mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \
+ } while (0)
+
+static void (*do_hd)(void) = NULL;
+#define SET_HANDLER(x) \
+if ((do_hd = (x)) != NULL) \
+ SET_TIMER; \
+else \
+ del_timer(&device_timer);
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+ extern spinlock_t i8253_lock;
+ unsigned long t, flags;
+ int i;
+
+ spin_lock_irqsave(&i8253_lock, flags);
+ t = jiffies * 11932;
+ outb_p(0, PIT_MODE);
+ i = inb_p(PIT_CH0);
+ i |= inb(PIT_CH0) << 8;
+ spin_unlock_irqrestore(&i8253_lock, flags);
+ return(t - i);
+}
+#endif
+
+void __init hd_setup(char *str, int *ints)
+{
+ int hdind = 0;
+
+ if (ints[0] != 3)
+ return;
+ if (hd_info[0].head != 0)
+ hdind=1;
+ hd_info[hdind].head = ints[2];
+ hd_info[hdind].sect = ints[3];
+ hd_info[hdind].cyl = ints[1];
+ hd_info[hdind].wpcom = 0;
+ hd_info[hdind].lzone = ints[1];
+ hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+ NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+ char devc;
+
+ devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+#ifdef VERBOSE_ERRORS
+ printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
+ if (stat & BUSY_STAT) printk("Busy ");
+ if (stat & READY_STAT) printk("DriveReady ");
+ if (stat & WRERR_STAT) printk("WriteFault ");
+ if (stat & SEEK_STAT) printk("SeekComplete ");
+ if (stat & DRQ_STAT) printk("DataRequest ");
+ if (stat & ECC_STAT) printk("CorrectedError ");
+ if (stat & INDEX_STAT) printk("Index ");
+ if (stat & ERR_STAT) printk("Error ");
+ printk("}\n");
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+ if (hd_error & BBD_ERR) printk("BadSector ");
+ if (hd_error & ECC_ERR) printk("UncorrectableError ");
+ if (hd_error & ID_ERR) printk("SectorIdNotFound ");
+ if (hd_error & ABRT_ERR) printk("DriveStatusError ");
+ if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
+ if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
+ printk("}");
+ if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+ printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
+ inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+ if (!blk_queue_empty(QUEUE))
+ printk(", sector=%ld", CURRENT->sector);
+ }
+ printk("\n");
+ }
+#else
+ printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+ }
+#endif
+}
+
+void check_status(void)
+{
+ int i = inb(HD_STATUS);
+
+ if (!OK_STATUS(i)) {
+ dump_status("check_status", i);
+ bad_rw_intr();
+ }
+}
+
+static int controller_busy(void)
+{
+ int retries = 100000;
+ unsigned char status;
+
+ do {
+ status = inb(HD_STATUS);
+ } while ((status & BUSY_STAT) && --retries);
+ return status;
+}
+
+static int status_ok(void)
+{
+ unsigned char status = inb(HD_STATUS);
+
+ if (status & BUSY_STAT)
+ return 1; /* Ancient, but does it make sense??? */
+ if (status & WRERR_STAT)
+ return 0;
+ if (!(status & READY_STAT))
+ return 0;
+ if (!(status & SEEK_STAT))
+ return 0;
+ return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+ int retry = 100;
+
+ do {
+ if (controller_busy() & BUSY_STAT)
+ return 0;
+ outb(0xA0 | (drive<<4) | head, HD_CURRENT);
+ if (status_ok())
+ return 1;
+ } while (--retry);
+ return 0;
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+ unsigned int head,unsigned int cyl,unsigned int cmd,
+ void (*intr_addr)(void))
+{
+ unsigned short port;
+
+#if (HD_DELAY > 0)
+ while (read_timer() - last_req < HD_DELAY)
+ /* nothing */;
+#endif
+ if (reset)
+ return;
+ if (!controller_ready(drive, head)) {
+ reset = 1;
+ return;
+ }
+ SET_HANDLER(intr_addr);
+ outb(hd_info[drive].ctl,HD_CMD);
+ port=HD_DATA + 2;
+ outb(hd_info[drive].wpcom>>2, port); port += 2;
+ outb(nsect, port); port += 2;
+ outb(sect, port); port += 2;
+ outb(cyl, port); port += 2;
+ outb(cyl>>8, port); port += 2;
+ outb(0xA0|(drive<<4)|head, port); port += 2;
+ outb(cmd, port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+ unsigned int i;
+ unsigned char c;
+
+ for (i = 0; i < 500000 ; i++) {
+ c = inb(HD_STATUS);
+ if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+ return 0;
+ }
+ dump_status("reset timed out", c);
+ return 1;
+}
+
+static void reset_controller(void)
+{
+ int i;
+
+ outb(4,HD_CMD);
+ for(i = 0; i < 1000; i++) barrier();
+ outb(hd_info[0].ctl & 0x0f,HD_CMD);
+ for(i = 0; i < 1000; i++) barrier();
+ if (drive_busy())
+ printk("hd: controller still busy\n");
+ else if ((hd_error = inb(HD_ERROR)) != 1)
+ printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+ static int i;
+
+repeat:
+ if (reset) {
+ reset = 0;
+ i = -1;
+ reset_controller();
+ } else {
+ check_status();
+ if (reset)
+ goto repeat;
+ }
+ if (++i < NR_HD) {
+ special_op[i] = recalibrate[i] = 1;
+ hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
+ hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+ if (reset)
+ goto repeat;
+ } else
+ hd_request();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
+ * drive enters "idle", "standby", or "sleep" mode, so if the status looks
+ * "good", we just ignore the interrupt completely.
+ */
+void unexpected_hd_interrupt(void)
+{
+ unsigned int stat = inb(HD_STATUS);
+
+ if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+ dump_status ("unexpected interrupt", stat);
+ SET_TIMER;
+ }
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg ([email protected])
+ */
+static void bad_rw_intr(void)
+{
+ int dev;
+
+ if (blk_queue_empty(QUEUE))
+ return;
+ dev = DEVICE_NR(CURRENT->rq_dev);
+ if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+ end_request(CURRENT, 0);
+ special_op[dev] = recalibrate[dev] = 1;
+ } else if (CURRENT->errors % RESET_FREQ == 0)
+ reset = 1;
+ else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+ special_op[dev] = recalibrate[dev] = 1;
+ /* Otherwise just retry */
+}
+
+static inline int wait_DRQ(void)
+{
+ int retries = 100000, stat;
+
+ while (--retries > 0)
+ if ((stat = inb(HD_STATUS)) & DRQ_STAT)
+ return 0;
+ dump_status("wait_DRQ", stat);
+ return -1;
+}
+
+static void read_intr(void)
+{
+ int i, retries = 100000;
+
+ do {
+ i = (unsigned) inb(HD_STATUS);
+ if (i & BUSY_STAT)
+ continue;
+ if (!OK_STATUS(i))
+ break;
+ if (i & DRQ_STAT)
+ goto ok_to_read;
+ } while (--retries > 0);
+ dump_status("read_intr", i);
+ bad_rw_intr();
+ hd_request();
+ return;
+ok_to_read:
+ insw(HD_DATA,CURRENT->buffer,256);
+ CURRENT->sector++;
+ CURRENT->buffer += 512;
+ CURRENT->errors = 0;
+ i = --CURRENT->nr_sectors;
+ --CURRENT->current_nr_sectors;
+#ifdef DEBUG
+ printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+ dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+ (unsigned long) CURRENT->buffer+512);
+#endif
+ if (CURRENT->current_nr_sectors <= 0)
+ end_request(CURRENT, 1);
+ if (i > 0) {
+ SET_HANDLER(&read_intr);
+ return;
+ }
+ (void) inb(HD_STATUS);
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ if (!blk_queue_empty(QUEUE))
+ hd_request();
+ return;
+}
+
+static void write_intr(void)
+{
+ int i;
+ int retries = 100000;
+
+ do {
+ i = (unsigned) inb(HD_STATUS);
+ if (i & BUSY_STAT)
+ continue;
+ if (!OK_STATUS(i))
+ break;
+ if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
+ goto ok_to_write;
+ } while (--retries > 0);
+ dump_status("write_intr", i);
+ bad_rw_intr();
+ hd_request();
+ return;
+ok_to_write:
+ CURRENT->sector++;
+ i = --CURRENT->nr_sectors;
+ --CURRENT->current_nr_sectors;
+ CURRENT->buffer += 512;
+ if (!i || (CURRENT->bio && !SUBSECTOR(i)))
+ end_request(CURRENT, 1);
+ if (i > 0) {
+ SET_HANDLER(&write_intr);
+ outsw(HD_DATA,CURRENT->buffer,256);
+ local_irq_enable();
+ } else {
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ hd_request();
+ }
+ return;
+}
+
+static void recal_intr(void)
+{
+ check_status();
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+ unsigned int dev;
+
+ do_hd = NULL;
+
+ if (blk_queue_empty(QUEUE))
+ return;
+
+ disable_irq(HD_IRQ);
+ local_irq_enable();
+ reset = 1;
+ dev = DEVICE_NR(CURRENT->rq_dev);
+ printk("hd%c: timeout\n", dev+'a');
+ if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+ printk("hd%c: too many errors\n", dev+'a');
+#endif
+ end_request(CURRENT, 0);
+ }
+ local_irq_disable();
+ hd_request();
+ enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+ if (recalibrate[dev]) {
+ recalibrate[dev] = 0;
+ hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+ return reset;
+ }
+ if (hd_info[dev].head > 16) {
+ printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+ end_request(CURRENT, 0);
+ }
+ special_op[dev] = 0;
+ return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible. In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+ unsigned int dev, block, nsect, sec, track, head, cyl;
+
+ if (do_hd)
+ return;
+repeat:
+ del_timer(&device_timer);
+ local_irq_enable();
+
+ if (blk_queue_empty(QUEUE)) {
+ do_hd = NULL;
+ return;
+ }
+
+ if (reset) {
+ local_irq_disable();
+ reset_hd();
+ return;
+ }
+ dev = DEVICE_NR(CURRENT->rq_dev);
+ block = CURRENT->sector;
+ nsect = CURRENT->nr_sectors;
+ if (dev >= NR_HD) {
+ printk("hd: bad disk number: %d\n", dev);
+ end_request(CURRENT, 0);
+ goto repeat;
+ }
+ if (block >= get_capacity(hd_gendisk[dev]) ||
+ ((block+nsect) > get_capacity(hd_gendisk[dev]))) {
+ printk("%s: bad access: block=%d, count=%d\n",
+ hd_gendisk[dev]->disk_name, block, nsect);
+ end_request(CURRENT, 0);
+ goto repeat;
+ }
+
+ if (special_op[dev]) {
+ if (do_special_op(dev))
+ goto repeat;
+ return;
+ }
+ sec = block % hd_info[dev].sect + 1;
+ track = block / hd_info[dev].sect;
+ head = track % hd_info[dev].head;
+ cyl = track / hd_info[dev].head;
+#ifdef DEBUG
+ printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+ dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+ cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
+#endif
+ if(CURRENT->flags & REQ_CMD) {
+ switch (rq_data_dir(CURRENT)) {
+ case READ:
+ hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+ if (reset)
+ goto repeat;
+ break;
+ case WRITE:
+ hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ if (reset)
+ goto repeat;
+ if (wait_DRQ()) {
+ bad_rw_intr();
+ goto repeat;
+ }
+ outsw(HD_DATA,CURRENT->buffer,256);
+ break;
+ default:
+ printk("unknown hd-command\n");
+ end_request(CURRENT, 0);
+ break;
+ }
+ }
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+ disable_irq(HD_IRQ);
+ hd_request();
+ enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
+ int dev;
+
+ if ((!inode) || kdev_none(inode->i_rdev))
+ return -EINVAL;
+ dev = DEVICE_NR(inode->i_rdev);
+ if (dev >= NR_HD)
+ return -EINVAL;
+ switch (cmd) {
+ case HDIO_GETGEO:
+ {
+ struct hd_geometry g;
+ if (!loc) return -EINVAL;
+ g.heads = hd_info[dev].head;
+ g.sectors = hd_info[dev].sect;
+ g.cylinders = hd_info[dev].cyl;
+ g.start = get_start_sect(inode->i_bdev);
+ return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+ int target = DEVICE_NR(inode->i_rdev);
+ if (target >= NR_HD)
+ return -ENODEV;
+ return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+
+extern struct block_device_operations hd_fops;
+
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ void (*handler)(void) = do_hd;
+
+ do_hd = NULL;
+ del_timer(&device_timer);
+ if (!handler)
+ handler = unexpected_hd_interrupt;
+ handler();
+ local_irq_enable();
+}
+
+static struct block_device_operations hd_fops = {
+ .open = hd_open,
+ .ioctl = hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines.
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+
+static int __init hd_init(void)
+{
+ int drive;
+ if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+ printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+ return -1;
+ }
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
+ blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
+ init_timer(&device_timer);
+ device_timer.function = hd_times_out;
+ blk_queue_hardsect_size(QUEUE, 512);
+
+#ifdef __i386__
+ if (!NR_HD) {
+ extern struct drive_info drive_info;
+ unsigned char *BIOS = (unsigned char *) &drive_info;
+ unsigned long flags;
+#ifndef CONFIG_X86_PC9800
+ int cmos_disks;
+#endif
+
+ for (drive=0 ; drive<2 ; drive++) {
+ hd_info[drive].cyl = *(unsigned short *) BIOS;
+ hd_info[drive].head = *(3+BIOS);
+ hd_info[drive].sect = *(2+BIOS);
+ hd_info[drive].wpcom = 0;
+ hd_info[drive].ctl = *(3+BIOS) > 8 ? 8 : 0;
+ hd_info[drive].lzone = *(unsigned short *) BIOS;
+ if (hd_info[drive].cyl && NR_HD == drive)
+ NR_HD++;
+ BIOS += 6;
+ }
+
+ }
+#endif /* __i386__ */
+#ifdef __arm__
+ if (!NR_HD) {
+ /* We don't know anything about the drive. This means
+ * that you *MUST* specify the drive parameters to the
+ * kernel yourself.
+ */
+ printk("hd: no drives specified - use hd=cyl,head,sectors"
+ " on kernel command line\n");
+ }
+#endif
+ if (!NR_HD)
+ goto out;
+
+ for (drive=0 ; drive < NR_HD ; drive++) {
+ struct gendisk *disk = alloc_disk();
+ if (!disk)
+ goto Enomem;
+ disk->major = MAJOR_NR;
+ disk->first_minor = drive << 6;
+ disk->minor_shift = 6;
+ disk->fops = &hd_fops;
+ sprintf(disk->disk_name, "hd%c", 'a'+drive);
+ hd_gendisk[drive] = disk;
+ }
+ for (drive=0 ; drive < NR_HD ; drive++) {
+ sector_t size = hd_info[drive].head *
+ hd_info[drive].sect * hd_info[drive].cyl;
+ set_capacity(hd_gendisk[drive], size);
+ printk ("%s: %ldMB, CHS=%d/%d/%d\n",
+ hd_gendisk[drive]->disk_name,
+ size / 2048, hd_info[drive].cyl,
+ hd_info[drive].head, hd_info[drive].sect);
+ }
+
+ if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+ printk("hd: unable to get IRQ%d for the hard disk driver\n",
+ HD_IRQ);
+ goto out1;
+ }
+
+ if (!request_region(HD_DATA, 2, "hd(data)")) {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ NR_HD = 0;
+ free_irq(HD_IRQ, NULL);
+ return;
+ }
+
+ if (!request_region(HD_DATA + 2, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out2;
+ }
+
+ if (!request_region(HD_DATA + 4, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out3;
+ }
+
+ if (!request_region(HD_DATA + 6, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out4;
+ }
+
+ if (!request_region(HD_DATA + 8, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out5;
+ }
+
+ if (!request_region(HD_DATA + 10, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out6;
+ }
+
+ if (!request_region(HD_DATA + 12, 1, "hd"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out7;
+ }
+
+ if (!request_region(HD_CMD, 1, "hd(cmd)"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
+ goto out8;
+ }
+
+ if (!request_region(HD_CMD + 2, 1, "hd(cmd)"))
+ {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
+ goto out9;
+ }
+
+ for(drive=0; drive < NR_HD; drive++) {
+ struct hd_i_struct *p = hd_info + drive;
+ set_capacity(hd_gendisk[drive], p->head * p->sect * p->cyl);
+ add_disk(hd_gendisk[drive]);
+ }
+ return 0;
+
+out9:
+ release_region(HD_CMD, 1);
+out8:
+ release_region(HD_DATA + 12, 1);
+out7:
+ release_region(HD_DATA + 10, 1);
+out6:
+ release_region(HD_DATA + 8, 1);
+out5:
+ release_region(HD_DATA + 6, 1);
+out4:
+ release_region(HD_DATA + 4, 1);
+out3:
+ release_region(HD_DATA + 2, 1);
+out2:
+ release_region(HD_DATA, 2);
+ free_irq(HD_IRQ, NULL);
+out1:
+ for (drive = 0; drive < NR_HD; drive++)
+ put_disk(hd_gendisk[drive]);
+ NR_HD = 0;
+out:
+ del_timer(&device_timer);
+ unregister_blkdev(MAJOR_NR,"hd");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ return -1;
+Enomem:
+ while (drive--)
+ put_disk(hd_gendisk[drive]);
+ goto out;
+}
+
+static int parse_hd_setup (char *line) {
+ int ints[6];
+
+ (void) get_options(line, ARRAY_SIZE(ints), ints);
+ hd_setup(NULL, ints);
+
+ return 1;
+}
+__setup("hd=", parse_hd_setup);
+
+module_init(hd_init);
diff -Nru linux/drivers/ide/legacy/pc9800.c linux98/drivers/ide/legacy/pc9800.c
--- linux/drivers/ide/legacy/pc9800.c 1970-01-01 09:00:00.000000000 +0900
+++ linux98/drivers/ide/legacy/pc9800.c 2003-03-04 10:44:14.000000000 +0900
@@ -0,0 +1,80 @@
+/*
+ * ide_pc9800.c
+ *
+ * Copyright (C) 1997-2000 Linux/98 project,
+ * Kyoto University Microcomputer Club.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pc9800.h>
+
+#define PC9800_IDE_BANKSELECT 0x432
+
+#undef PC9800_IDE_DEBUG
+
+static void pc9800_select(ide_drive_t *drive)
+{
+#ifdef PC9800_IDE_DEBUG
+ byte old;
+
+ /* Too noisy: */
+ /* printk(KERN_DEBUG "pc9800_select(%s)\n", drive->name); */
+
+ outb(0x80, PC9800_IDE_BANKSELECT);
+ old = inb(PC9800_IDE_BANKSELECT);
+ if (old != HWIF(drive)->index)
+ printk(KERN_DEBUG "ide-pc9800: switching bank #%d -> #%d\n",
+ old, HWIF(drive)->index);
+#endif
+ outb(HWIF(drive)->index, PC9800_IDE_BANKSELECT);
+}
+
+void __init ide_probe_for_pc9800(void)
+{
+ u8 saved_bank;
+
+ if (!PC9800_9821_P() /* || !PC9821_IDEIF_DOUBLE_P() */)
+ return;
+
+ if (!request_region(PC9800_IDE_BANKSELECT, 1, "ide0/1 bank")) {
+ printk(KERN_ERR
+ "ide: bank select port (%#x) is already occupied!\n",
+ PC9800_IDE_BANKSELECT);
+ return;
+ }
+
+ /* Do actual probing. */
+ if ((saved_bank = inb(PC9800_IDE_BANKSELECT)) == (u8) ~0
+ || (outb(saved_bank ^ 1, PC9800_IDE_BANKSELECT),
+ /* Next outb is dummy for reading status. */
+ outb(0x80, PC9800_IDE_BANKSELECT),
+ inb(PC9800_IDE_BANKSELECT) != (saved_bank ^ 1))) {
+ printk(KERN_INFO
+ "ide: pc9800 type bank selecting port not found\n");
+ release_region(PC9800_IDE_BANKSELECT, 1);
+ return;
+ }
+
+ /* Restore original value, just in case. */
+ outb(saved_bank, PC9800_IDE_BANKSELECT);
+
+ /* These ports are probably used by IDE I/F. */
+ request_region(0x430, 1, "ide");
+ request_region(0x435, 1, "ide");
+
+ if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET] == HD_DATA &&
+ ide_hwifs[1].io_ports[IDE_DATA_OFFSET] == HD_DATA) {
+ ide_hwifs[0].chipset = ide_pc9800;
+ ide_hwifs[0].mate = &ide_hwifs[1];
+ ide_hwifs[0].selectproc = pc9800_select;
+ ide_hwifs[1].chipset = ide_pc9800;
+ ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].selectproc = pc9800_select;
+ }
+}
diff -Nru linux/include/asm-i386/ide.h linux98/include/asm-i386/ide.h
--- linux/include/asm-i386/ide.h 2003-02-21 10:01:16.000000000 +0900
+++ linux98/include/asm-i386/ide.h 2003-02-21 11:51:22.000000000 +0900
@@ -26,6 +26,9 @@
static __inline__ int ide_default_irq(unsigned long base)
{
switch (base) {
+#ifdef CONFIG_X86_PC9800
+ case 0x640: return 9;
+#endif
case 0x1f0: return 14;
case 0x170: return 15;
case 0x1e8: return 11;
@@ -40,12 +43,17 @@
static __inline__ unsigned long ide_default_io_base(int index)
{
switch (index) {
+#ifdef CONFIG_X86_PC9800
+ case 0:
+ case 1: return 0x640;
+#else
case 0: return 0x1f0;
case 1: return 0x170;
case 2: return 0x1e8;
case 3: return 0x168;
case 4: return 0x1e0;
case 5: return 0x160;
+#endif
default:
return 0;
}
@@ -56,13 +64,24 @@
{
unsigned long reg = data_port;
int i;
+#ifdef CONFIG_X86_PC9800
+ unsigned long increment = data_port == 0x640 ? 2 : 1;
+#endif

for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
hw->io_ports[i] = reg;
+#ifdef CONFIG_X86_PC9800
+ reg += increment;
+#else
reg += 1;
+#endif
}
if (ctrl_port) {
hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+#ifdef CONFIG_X86_PC9800
+ } else if (data_port == 0x640) {
+ hw->io_ports[IDE_CONTROL_OFFSET] = 0x74c;
+#endif
} else {
hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
}
diff -Nru linux/include/linux/hdreg.h linux98/include/linux/hdreg.h
--- linux/include/linux/hdreg.h 2003-02-15 08:51:42.000000000 +0900
+++ linux98/include/linux/hdreg.h 2003-02-20 10:18:37.000000000 +0900
@@ -5,11 +5,29 @@
* This file contains some defines for the AT-hd-controller.
* Various sources.
*/
+#include <linux/config.h>

/* ide.c has its own port definitions in "ide.h" */

#define HD_IRQ 14

+#ifdef CONFIG_X86_PC9800
+/* Hd controller regs. for NEC PC-9800 */
+#define HD_DATA 0x640 /* _CTL when writing */
+#define HD_ERROR 0x642 /* see err-bits */
+#define HD_NSECTOR 0x644 /* nr of sectors to read/write */
+#define HD_SECTOR 0x646 /* starting sector */
+#define HD_LCYL 0x648 /* starting cylinder */
+#define HD_HCYL 0x64a /* high byte of starting cyl */
+#define HD_CURRENT 0x64c /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x64e /* see status-bits */
+#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
+#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x74c /* used for resets */
+#define HD_ALTSTATUS 0x74c /* same as HD_STATUS but doesn't clear irq */
+#else /* !CONFIG_X86_PC9800 */
/* Hd controller regs. Ref: IBM AT Bios-listing */
#define HD_DATA 0x1f0 /* _CTL when writing */
#define HD_ERROR 0x1f1 /* see err-bits */
@@ -25,6 +43,7 @@

#define HD_CMD 0x3f6 /* used for resets */
#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
+#endif /* CONFIG_X86_PC9800 */

/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */

diff -Nru linux/include/linux/ide.h linux98/include/linux/ide.h
--- linux/include/linux/ide.h 2003-02-21 10:01:17.000000000 +0900
+++ linux98/include/linux/ide.h 2003-02-21 10:46:24.000000000 +0900
@@ -302,7 +302,7 @@
ide_qd65xx, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
- ide_pmac, ide_etrax100, ide_acorn
+ ide_pmac, ide_etrax100, ide_acorn, ide_pc9800
} hwif_chipset_t;

/*

2003-03-09 04:16:51

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (12/20) parport

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (12/20)

Parallel port support.
- Change IO port and IRQ assign.
- Add probing for PC98 parport.

Regards,
Osamu Tomita


diff -Nru linux-2.5.64-ac2/drivers/parport/parport_pc.c linux98-2.5.64-ac2/drivers/parport/parport_pc.c
--- linux-2.5.64-ac2/drivers/parport/parport_pc.c 2003-03-08 08:25:20.000000000 +0900
+++ linux98-2.5.64-ac2/drivers/parport/parport_pc.c 2003-03-08 10:44:43.000000000 +0900
@@ -1892,6 +1892,9 @@
config & 0x80 ? "Level" : "Pulses");

configb = inb (CONFIGB (pb));
+ if (pc98 && (CONFIGB(pb) == 0x14d) && ((configb & 0x38) == 0x30))
+ configb = (configb & ~0x38) | 0x28; /* IRQ 14 */
+
printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
pb->base, config, configb);
printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
@@ -2032,6 +2035,9 @@
ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */

intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
+ if (pc98 && (CONFIGB(pb) == 0x14d) && (intrLine == 6))
+ intrLine = 5; /* IRQ 14 */
+
irq = lookup[intrLine];

ECR_WRITE (pb, oecr);
@@ -2248,7 +2254,7 @@
parport_ECR_present(p);
}

- if (base != 0x3bc) {
+ if (!pc98 && base != 0x3bc) {
EPP_res = request_region(base+0x3, 5, fake_name);
if (EPP_res)
if (!parport_EPP_supported(p))
@@ -3022,6 +3028,26 @@
{
int count = 0;

+ if (pc98) {
+ /* Set default settings for IEEE1284 parport */
+ int base = 0x140;
+ int base_hi = 0x14c;
+ int irq = 14;
+ int dma = PARPORT_DMA_NONE;
+
+ /* Check PC9800 old style parport */
+ outb(inb(0x149) & ~0x10, 0x149); /* disable IEEE1284 */
+ if (!(inb(0x149) & 0x10)) { /* IEEE1284 disabled ? */
+ outb(inb(0x149) | 0x10, 0x149); /* enable IEEE1284 */
+ if (inb(0x149) & 0x10) { /* IEEE1284 enabled ? */
+ if (parport_pc_probe_port(base, base_hi,
+ irq, dma, NULL))
+ count++;
+ }
+ }
+
+ }
+
if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL))
count++;
if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL))

2003-03-09 04:25:01

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (16/20) SCSI

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (16/20)

SCSI host adapter support.
- BIOS parameter change for PC98.
- Add pc980155 driver for old PC98.
- wd33c93.h register address size to int, because PC-9801-55 mapped 0xcc0.

Regards,
Osamu Tomita


diff -Nru linux-2.5.64/drivers/scsi/Kconfig linux98-2.5.64/drivers/scsi/Kconfig
--- linux-2.5.64/drivers/scsi/Kconfig 2003-03-05 13:18:53.000000000 +0900
+++ linux98-2.5.64/drivers/scsi/Kconfig 2003-03-05 15:34:46.000000000 +0900
@@ -1715,6 +1715,11 @@
If you have the NEC PC-9801-55 SCSI interface card or compatibles
for NEC PC-9801/PC-9821, say Y.

+config WD33C93_PIO
+ bool
+ depends on SCSI_PC980155
+ default y
+
# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
endmenu
diff -Nru linux-2.5.64/drivers/scsi/Makefile linux98-2.5.64/drivers/scsi/Makefile
--- linux-2.5.64/drivers/scsi/Makefile 2003-03-05 13:18:54.000000000 +0900
+++ linux98-2.5.64/drivers/scsi/Makefile 2003-03-05 13:40:14.000000000 +0900
@@ -29,6 +29,7 @@
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
+obj-$(CONFIG_SCSI_PC980155) += pc980155.o wd33c93.o
obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o
diff -Nru linux-2.5.64/drivers/scsi/pc980155.c linux98-2.5.64/drivers/scsi/pc980155.c
--- linux-2.5.64/drivers/scsi/pc980155.c 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.64/drivers/scsi/pc980155.c 2003-03-08 00:12:49.000000000 +0900
@@ -0,0 +1,311 @@
+/*
+ *
+ * drivers/scsi/pc980155.c
+ *
+ * PC-9801-55 SCSI host adapter driver
+ *
+ * Copyright (C) 1997-2003 Kyoto University Microcomputer Club
+ * (Linux/98 project)
+ * Tomoharu Ugawa <[email protected]>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+#include "pc980155.h"
+
+extern int pc98_bios_param(struct scsi_device *, struct block_device *,
+ sector_t, int *);
+static int scsi_pc980155_detect(Scsi_Host_Template *);
+static int scsi_pc980155_release(struct Scsi_Host *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#undef PC_9801_55_DEBUG
+#undef PC_9801_55_DEBUG_VERBOSE
+
+#define NR_BASE_IOS 4
+static int nr_base_ios = NR_BASE_IOS;
+static unsigned int base_ios[NR_BASE_IOS] = {0xcc0, 0xcd0, 0xce0, 0xcf0};
+static unsigned int SASR;
+static unsigned int SCMD;
+static wd33c93_regs regs = {&SASR, &SCMD};
+static int io;
+
+static struct Scsi_Host *pc980155_host = NULL;
+
+static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp);
+
+static inline void pc980155_dma_enable(unsigned int base_io)
+{
+ outb(0x01, REG_CWRITE);
+}
+
+static inline void pc980155_dma_disable(unsigned int base_io)
+{
+ outb(0x02, REG_CWRITE);
+}
+
+
+static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp)
+{
+ wd33c93_intr(pc980155_host);
+}
+
+static int dma_setup(Scsi_Cmnd *sc, int dir_in)
+{
+ /*
+ * sc->SCp.this_residual : transfer count
+ * sc->SCp.ptr : distination address (virtual address)
+ * dir_in : data direction (DATA_OUT_DIR:0 or DATA_IN_DIR:1)
+ *
+ * if success return 0
+ */
+
+ /*
+ * DMA WRITE MODE
+ * bit 7,6 01b single mode (this mode only)
+ * bit 5 inc/dec (default:0 = inc)
+ * bit 4 auto initialize (normaly:0 = off)
+ * bit 3,2 01b memory -> io
+ * 10b io -> memory
+ * 00b verify
+ * bit 1,0 channel
+ */
+ disable_dma(sc->device->host->dma_channel);
+ set_dma_mode(sc->device->host->dma_channel,
+ 0x40 | (dir_in ? 0x04 : 0x08));
+ clear_dma_ff(sc->device->host->dma_channel);
+ set_dma_addr(sc->device->host->dma_channel, virt_to_phys(sc->SCp.ptr));
+ set_dma_count(sc->device->host->dma_channel, sc->SCp.this_residual);
+#ifdef PC_9801_55_DEBUG
+ printk("D%d(%x)D", sc->device->host->dma_channel,
+ sc->SCp.this_residual);
+#endif
+ enable_dma(sc->device->host->dma_channel);
+ pc980155_dma_enable(sc->device->host->io_port);
+ return 0;
+}
+
+static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *sc, int status)
+{
+ /*
+ * instance: Hostadapter's instance
+ * sc: scsi command
+ * status: True if success
+ */
+ pc980155_dma_disable(sc->device->host->io_port);
+ disable_dma(sc->device->host->dma_channel);
+}
+
+/* return non-zero on detection */
+static inline int pc980155_test_port(wd33c93_regs regs)
+{
+ /* Quick and dirty test for presence of the card. */
+ if (inb(*regs.SASR) == 0xff)
+ return 0;
+
+ return 1;
+}
+
+static inline int pc980155_getconfig(unsigned int base_io, wd33c93_regs regs,
+ unsigned char* irq, unsigned char* dma,
+ unsigned char* scsi_id)
+{
+ static unsigned char irqs[] = {3, 5, 6, 9, 12, 13};
+ unsigned char result;
+
+ printk(KERN_DEBUG "PC-9801-55: base_io=%x SASR=%x SCMD=%x\n",
+ base_io, *regs.SASR, *regs.SCMD);
+ result = read_pc980155_resetint(regs);
+ printk(KERN_DEBUG "PC-9801-55: getting config (%x)\n", result);
+ *scsi_id = result & 0x07;
+ *irq = (result >> 3) & 0x07;
+ if (*irq > 5) {
+ printk(KERN_ERR "PC-9801-55 (base %#x): impossible IRQ (%d)"
+ " - other device here?\n", base_io, *irq);
+ return 0;
+ }
+
+ *irq = irqs[*irq];
+ result = inb(REG_STATRD);
+ *dma = result & 0x03;
+ if (*dma == 1) {
+ printk(KERN_ERR
+ "PC-9801-55 (base %#x): impossible DMA channl (%d)"
+ " - other device here?\n", base_io, *dma);
+ return 0;
+ }
+#ifdef PC_9801_55_DEBUG
+ printk("PC-9801-55: end of getconfig\n");
+#endif
+ return 1;
+}
+
+/* return non-zero on detection */
+static int scsi_pc980155_detect(Scsi_Host_Template* tpnt)
+{
+ unsigned int base_io;
+ unsigned char irq, dma, scsi_id;
+ int i;
+#ifdef PC_9801_55_DEBUG
+ unsigned char debug;
+#endif
+
+ if (io) {
+ base_ios[0] = io;
+ nr_base_ios = 1;
+ }
+
+ for (i = 0; i < nr_base_ios; i++) {
+ base_io = base_ios[i];
+ SASR = REG_ADDRST;
+ SCMD = REG_CONTRL;
+#ifdef PC_9801_55_DEBUG_VERBOSE
+ printk("PC-9801-55: SASR(%x = %x)\n", SASR, REG_ADDRST);
+#endif
+ if (!request_region(base_io, 6, "PC-9801-55"))
+ continue;
+
+ if (pc980155_test_port(regs) &&
+ pc980155_getconfig(base_io, regs, &irq, &dma, &scsi_id))
+ goto found;
+
+ release_region(base_io, 6);
+ }
+
+ printk("PC-9801-55: not found\n");
+ return 0;
+
+ found:
+#ifdef PC_9801_55_DEBUG
+ printk("PC-9801-55: config: base io = %x, irq = %d, dma channel = %d, scsi id = %d\n", base_io, irq, dma, scsi_id);
+#endif
+ if (request_irq(irq, pc980155_intr_handle, 0, "PC-9801-55", NULL)) {
+ printk(KERN_ERR "PC-9801-55: unable to allocate IRQ %d\n", irq);
+ goto err1;
+ }
+
+ if (request_dma(dma, "PC-9801-55")) {
+ printk(KERN_ERR "PC-9801-55: unable to allocate DMA channel %d\n", dma);
+ goto err2;
+ }
+
+ pc980155_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+ if (pc980155_host) {
+ pc980155_host->this_id = scsi_id;
+ pc980155_host->io_port = base_io;
+ pc980155_host->n_io_port = 6;
+ pc980155_host->irq = irq;
+ pc980155_host->dma_channel = dma;
+ printk("PC-9801-55: scsi host found at %x irq = %d, use dma channel %d.\n", base_io, irq, dma);
+ pc980155_int_enable(regs);
+ wd33c93_init(pc980155_host, regs, dma_setup, dma_stop,
+ WD33C93_FS_12_15);
+ return 1;
+ }
+
+ printk(KERN_ERR "PC-9801-55: failed to register device\n");
+
+err2:
+ free_irq(irq, NULL);
+err1:
+ release_region(base_io, 6);
+ return 0;
+}
+
+static int scsi_pc980155_release(struct Scsi_Host *shost)
+{
+ pc980155_int_disable(regs);
+ release_region(shost->io_port, shost->n_io_port);
+ free_irq(shost->irq, NULL);
+ free_dma(shost->dma_channel);
+ wd33c93_release();
+ return 1;
+}
+
+static int pc980155_abort(Scsi_Cmnd *cmd)
+{
+ if (wd33c93_abort(cmd) == SCSI_ABORT_SUCCESS)
+ return SUCCESS;
+
+ return FAILED;
+}
+
+static int pc980155_bus_reset(Scsi_Cmnd *cmd)
+{
+ struct WD33C93_hostdata *hostdata
+ = (struct WD33C93_hostdata *)cmd->device->host->hostdata;
+
+ pc980155_int_disable(hostdata->regs);
+ pc980155_assert_bus_reset(hostdata->regs);
+ udelay(50);
+ pc980155_negate_bus_reset(hostdata->regs);
+ (void) inb(*hostdata->regs.SASR);
+ (void) read_pc980155(hostdata->regs, WD_SCSI_STATUS);
+ pc980155_int_enable(hostdata->regs);
+ wd33c93_reset(cmd, 0);
+ return SUCCESS;
+}
+
+static int pc980155_host_reset(Scsi_Cmnd *cmd)
+{
+ wd33c93_reset(cmd, 0);
+ return SUCCESS;
+}
+
+
+#ifndef MODULE
+static int __init pc980155_setup(char *str)
+{
+ int ints[4];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ if (ints[0] > 0)
+ io = ints[1];
+ return 1;
+}
+__setup("pc980155_io=", pc980155_setup);
+#endif
+
+MODULE_PARM(io, "i");
+MODULE_AUTHOR("Tomoharu Ugawa <[email protected]>");
+MODULE_DESCRIPTION("PC-9801-55 SCSI host adapter driver");
+MODULE_LICENSE("GPL");
+
+static Scsi_Host_Template driver_template = {
+ .proc_info = wd33c93_proc_info,
+ .name = "SCSI PC-9801-55",
+ .detect = scsi_pc980155_detect,
+ .release = scsi_pc980155_release,
+ .queuecommand = wd33c93_queuecommand,
+ .eh_abort_handler = pc980155_abort,
+ .eh_bus_reset_handler = pc980155_bus_reset,
+ .eh_host_reset_handler = pc980155_host_reset,
+ .bios_param = pc98_bios_param,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN, /* dont use link command */
+ .unchecked_isa_dma = 1, /* use dma **XXXX***/
+ .use_clustering = ENABLE_CLUSTERING,
+ .proc_name = "PC_9801_55",
+};
+
+#include "scsi_module.c"
diff -Nru linux-2.5.64/drivers/scsi/pc980155.h linux98-2.5.64/drivers/scsi/pc980155.h
--- linux-2.5.64/drivers/scsi/pc980155.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.64/drivers/scsi/pc980155.h 2003-03-06 16:07:56.000000000 +0900
@@ -0,0 +1,52 @@
+/*
+ *
+ * drivers/scsi/pc980155.h
+ *
+ * PC-9801-55 SCSI host adapter driver
+ *
+ * Copyright (C) 1997-2003 Kyoto University Microcomputer Club
+ * (Linux/98 project)
+ * Tomoharu Ugawa <[email protected]>
+ *
+ */
+
+#ifndef __PC980155_H
+#define __PC980155_H
+
+#include "wd33c93.h"
+
+#define REG_ADDRST (base_io)
+#define REG_CONTRL (base_io + 2)
+#define REG_CWRITE (base_io + 4)
+#define REG_STATRD (base_io + 4)
+
+#define WD_MEMORYBANK 0x30
+#define WD_RESETINT 0x33
+
+static inline uchar read_pc980155(const wd33c93_regs regs, uchar reg_num)
+{
+ outb(reg_num, *regs.SASR);
+ return (uchar)inb(*regs.SCMD);
+}
+
+static inline void write_memorybank(const wd33c93_regs regs, uchar value)
+{
+ outb(WD_MEMORYBANK, *regs.SASR);
+ outb(value, *regs.SCMD);
+}
+
+#define read_pc980155_resetint(regs) \
+ read_pc980155((regs), WD_RESETINT)
+#define pc980155_int_enable(regs) \
+ write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) | 0x04)
+
+#define pc980155_int_disable(regs) \
+ write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) & ~0x04)
+
+#define pc980155_assert_bus_reset(regs) \
+ write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) | 0x02)
+
+#define pc980155_negate_bus_reset(regs) \
+ write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) & ~0x02)
+
+#endif /* __PC980155_H */
diff -Nru linux/drivers/scsi/scsi_pc98.c linux98/drivers/scsi/scsi_pc98.c
--- linux/drivers/scsi/scsi_pc98.c 2003-03-05 13:18:57.000000000 +0900
+++ linux98/drivers/scsi/scsi_pc98.c 2003-03-05 13:49:21.000000000 +0900
@@ -48,7 +48,7 @@
int pc98_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *ip)
{
- static struct Scsi_Host *first_real = first_real_host();
+ struct Scsi_Host *first_real = first_real_host();

if (sdev->host == first_real && sdev->id < 7 &&
__PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id))
diff -Nru linux/drivers/scsi/sd.c linux98/drivers/scsi/sd.c
--- linux/drivers/scsi/sd.c 2003-03-05 12:29:32.000000000 +0900
+++ linux98/drivers/scsi/sd.c 2003-03-08 11:13:28.000000000 +0900
@@ -485,6 +485,15 @@
else
scsicam_bios_param(bdev, sdkp->capacity, diskinfo);

+#ifdef CONFIG_X86_PC9800
+ {
+ extern int pc98_bios_param(struct scsi_device *,
+ struct block_device *,
+ sector_t, int *);
+ pc98_bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+ }
+#endif
+
if (put_user(diskinfo[0], &loc->heads))
return -EFAULT;
if (put_user(diskinfo[1], &loc->sectors))
diff -Nru linux/drivers/scsi/wd33c93.c linux98/drivers/scsi/wd33c93.c
--- linux/drivers/scsi/wd33c93.c 2003-03-05 13:19:00.000000000 +0900
+++ linux98/drivers/scsi/wd33c93.c 2003-03-06 13:33:27.000000000 +0900
@@ -1755,7 +1755,7 @@

return 1;
}
-__setup("wd33c9=", wd33c93_setup);
+__setup("wd33c93=", wd33c93_setup);

/* check_setup_args() returns index if key found, 0 if not
*/
@@ -2086,3 +2086,4 @@
EXPORT_SYMBOL(wd33c93_abort);
EXPORT_SYMBOL(wd33c93_queuecommand);
EXPORT_SYMBOL(wd33c93_intr);
+EXPORT_SYMBOL(wd33c93_proc_info);
diff -Nru linux/drivers/scsi/wd33c93.h linux98/drivers/scsi/wd33c93.h
--- linux/drivers/scsi/wd33c93.h 2002-10-12 13:21:35.000000000 +0900
+++ linux98/drivers/scsi/wd33c93.h 2002-10-12 14:18:53.000000000 +0900
@@ -186,8 +186,13 @@

/* This is what the 3393 chip looks like to us */
typedef struct {
+#if defined(CONFIG_SCSI_PC980155) || defined(CONFIG_SCSI_PC980155_MODULE)
+ volatile unsigned int *SASR;
+ volatile unsigned int *SCMD;
+#else
volatile unsigned char *SASR;
volatile unsigned char *SCMD;
+#endif
} wd33c93_regs;


2003-03-09 04:27:30

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (17/20) serial

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (17/20)

Serial port support for PC98.
- Patch for onboard modem.
- New driver for 1st COM port.
PC98 has 2 COM ports. 1st port uses 8251 upper compatible chip
and 2nd port uses 16550A compatible chip.

Regards,
Osamu tomita


diff -Nru linux/drivers/serial/8250_pnp.c linux98/drivers/serial/8250_pnp.c
--- linux/drivers/serial/8250_pnp.c 2002-12-11 13:10:07.000000000 +0900
+++ linux98/drivers/serial/8250_pnp.c 2002-12-11 13:16:51.000000000 +0900
@@ -188,6 +188,8 @@
{ "MVX00A1", 0 },
/* PC Rider K56 Phone System PnP */
{ "MVX00F2", 0 },
+ /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
+ { "nEC8241", 0 },
/* Pace 56 Voice Internal Plug & Play Modem */
{ "PMC2430", 0 },
/* Generic */
@@ -373,6 +375,9 @@
((port->min == 0x2f8) ||
(port->min == 0x3f8) ||
(port->min == 0x2e8) ||
+#ifdef CONFIG_X86_PC9800
+ (port->min == 0x8b0) ||
+#endif
(port->min == 0x3e8)))
return 0;
}
diff -Nru linux/drivers/serial/Kconfig linux98/drivers/serial/Kconfig
--- linux/drivers/serial/Kconfig 2003-01-14 14:59:16.000000000 +0900
+++ linux98/drivers/serial/Kconfig 2003-01-17 13:07:46.000000000 +0900
@@ -372,14 +372,25 @@
bool "Use NEC V850E on-chip UART for console"
depends on V850E_NB85E_UART

+config SERIAL98
+ tristate "PC-9800 8251-based primary serial port support"
+ depends on X86_PC9800
+ help
+ If you want to use standard primary serial ports on PC-9800,
+ say Y. Otherwise, say N.
+
+config SERIAL98_CONSOLE
+ bool "Support for console on PC-9800 standard serial port"
+ depends on SERIAL98=y
+
config SERIAL_CORE
tristate
- default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m)
- default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART
+ default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m)
+ default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART || SERIAL98=y

config SERIAL_CORE_CONSOLE
bool
- depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNCORE || V850E_NB85E_UART_CONSOLE
+ depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNCORE || V850E_NB85E_UART_CONSOLE || SERIAL98_CONSOLE
default y

config SERIAL_68328
diff -Nru linux-2.5.60/drivers/serial/Makefile linux98-2.5.60/drivers/serial/Makefile
--- linux-2.5.60/drivers/serial/Makefile 2003-02-11 03:38:32.000000000 +0900
+++ linux98-2.5.60/drivers/serial/Makefile 2003-02-11 13:32:49.000000000 +0900
@@ -27,3 +27,4 @@
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o
+obj-$(CONFIG_SERIAL98) += serial98.o
diff -Nru linux-2.5.64/drivers/serial/serial98.c linux98-2.5.64/drivers/serial/serial98.c
--- linux-2.5.64/drivers/serial/serial98.c 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.64/drivers/serial/serial98.c 2003-03-05 17:20:41.000000000 +0900
@@ -0,0 +1,1124 @@
+/*
+ * linux/drivers/serial/serial98.c
+ *
+ * Driver for NEC PC-9801/PC-9821 standard serial ports
+ *
+ * Based on drivers/serial/8250.c, by Russell King.
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2002 Osamu Tomita <[email protected]>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pc9800.h>
+#include <asm/pc9800_sca.h>
+
+#if defined(CONFIG_SERIAL98_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SERIAL98_NR 1
+#define SERIAL98_ISR_PASS_LIMIT 256
+#define SERIAL98_EXT 0x434
+
+//#define RX_8251F 0x130 /* In: Receive buffer */
+//#define TX_8251F 0x130 /* Out: Transmit buffer */
+//#define LSR_8251F 0x132 /* In: Line Status Register */
+//#define MSR_8251F 0x134 /* In: Modem Status Register */
+#define IIR_8251F 0x136 /* In: Interrupt ID Register */
+#define FCR_8251F 0x138 /* I/O: FIFO Control Register */
+#define VFAST_8251F 0x13a /* I/O: VFAST mode Register */
+
+#define CMD_8251F 0x32 /* Out: 8251 Command Resister */
+#define IER2_8251F 0x34 /* I/O: Interrupt Enable Register */
+#define IER1_8251F 0x35 /* I/O: Interrupt Enable Register */
+#define IER1_CTL 0x37 /* Out: Interrupt Enable Register */
+#define DIS_RXR_INT 0x00 /* disable RxRDY Interrupt */
+#define ENA_RXR_INT 0x01 /* enable RxRDY Interrupt */
+#define DIS_TXE_INT 0x02 /* disable TxEMPTY Interrupt */
+#define ENA_TXE_INT 0x03 /* enable TxEMPTY Interrupt */
+#define DIS_TXR_INT 0x04 /* disable TxRDY Interrupt */
+#define ENA_TXR_INT 0x05 /* enable TxRDY Interrupt */
+
+#define CMD_RESET 0x40 /* Reset Command */
+#define CMD_RTS 0x20 /* Set RTS line */
+#define CMD_CLR_ERR 0x10 /* Clear error flag */
+#define CMD_BREAK 0x08 /* Send Break */
+#define CMD_RXE 0x04 /* Enable receive */
+#define CMD_DTR 0x02 /* Set DTR line */
+#define CMD_TXE 0x01 /* Enable send */
+#define CMD_DUMMY 0x00 /* Dummy Command */
+
+#define VFAST_ENABLE 0x80 /* V.Fast mode Enable */
+
+/* Interrupt masks */
+#define INTR_8251_TXRE 0x04
+#define INTR_8251_TXEE 0x02
+#define INTR_8251_RXRE 0x01
+/* I/O Port */
+//#define PORT_8251_DATA 0
+//#define PORT_8251_CMD 2
+//#define PORT_8251_MOD 2
+//#define PORT_8251_STS 2
+/* status read */
+#define STAT_8251_TXRDY 0x01
+#define STAT_8251_RXRDY 0x02
+#define STAT_8251_TXEMP 0x04
+#define STAT_8251_PER 0x08
+#define STAT_8251_OER 0x10
+#define STAT_8251_FER 0x20
+#define STAT_8251_BRK 0x40
+#define STAT_8251_DSR 0x80
+#if 1
+#define STAT_8251F_TXEMP 0x01
+#define STAT_8251F_TXRDY 0x02
+#define STAT_8251F_RXRDY 0x04
+#define STAT_8251F_DSR 0x08
+#define STAT_8251F_OER 0x10
+#define STAT_8251F_PER 0x20
+#define STAT_8251F_FER 0x40
+#define STAT_8251F_BRK 0x80
+#else
+#define STAT_8251F_TXEMP 0x01
+#define STAT_8251F_TEMT 0x01
+#define STAT_8251F_TXRDY 0x02
+#define STAT_8251F_THRE 0x02
+#define STAT_8251F_RXRDY 0x04
+#define STAT_8251F_DSR 0x04
+#define STAT_8251F_PER 0x08
+#define STAT_8251F_OER 0x10
+#define STAT_8251F_FER 0x20
+#define STAT_8251F_BRK 0x40
+#endif
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct serial98_port {
+ struct uart_port port;
+ unsigned int type;
+ unsigned int ext;
+ unsigned int lsr_break_flag;
+ unsigned char cmd;
+ unsigned char mode;
+ unsigned char msr;
+ unsigned char ier;
+ unsigned char rxchk;
+ unsigned char txemp;
+ unsigned char txrdy;
+ unsigned char rxrdy;
+ unsigned char brk;
+ unsigned char fe;
+ unsigned char oe;
+ unsigned char pe;
+ unsigned char dr;
+};
+
+#ifdef CONFIG_SERIAL98_CONSOLE
+static void
+serial98_console_write(struct console *co, const char *s, unsigned int count);
+static kdev_t serial98_console_device(struct console *co);
+static int __init serial98_console_setup(struct console *co, char *options);
+
+static struct console serial98_console = {
+ .name = "ttyS",
+ .write = serial98_console_write,
+ .device = serial98_console_device,
+ .setup = serial98_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+#define SERIAL98_CONSOLE &serial98_console
+#else
+#define SERIAL98_CONSOLE NULL
+#endif
+
+static struct uart_driver serial98_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial98",
+ .dev_name = "ttyS%d",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = SERIAL98_NR,
+ .cons = SERIAL98_CONSOLE,
+};
+
+static int serial98_clk;
+static char type_str[48];
+
+#define PORT98 ((struct serial98_port *)port)
+#define PORT (PORT98->port)
+
+static void serial98_fifo_enable(struct uart_port *port, int enable)
+{
+ unsigned char fcr;
+
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ fcr = inb(FCR_8251F);
+ if (enable)
+ fcr |= UART_FCR_ENABLE_FIFO;
+ else
+ fcr &= ~UART_FCR_ENABLE_FIFO;
+ outb(fcr, FCR_8251F);
+ }
+
+ if (!enable)
+ return;
+
+ outb(0, 0x5f); /* wait */
+ outb(0, 0x5f);
+ outb(0, 0x5f);
+ outb(0, 0x5f);
+}
+
+static void serial98_cmd_out(struct uart_port *port, unsigned char cmd)
+{
+ serial98_fifo_enable(port, 0);
+ outb(cmd, CMD_8251F);
+ serial98_fifo_enable(port, 1);
+}
+
+static void serial98_mode_set(struct uart_port *port)
+{
+ serial98_cmd_out(port, CMD_DUMMY);
+ serial98_cmd_out(port, CMD_DUMMY);
+ serial98_cmd_out(port, CMD_DUMMY);
+ serial98_cmd_out(port, CMD_RESET);
+ serial98_cmd_out(port, PORT98->mode);
+}
+
+static unsigned char serial98_msr_in(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int ms, st;
+ unsigned int tmp;
+
+ spin_lock_irqsave(&PORT.lock, flags);
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ PORT98->msr = inb(PORT.iobase + 4);
+ } else {
+ ms = inb(0x33);
+ st = inb(0x32);
+ tmp = 0;
+ if(!(ms & 0x20))
+ tmp |= UART_MSR_DCD;
+ if(!(ms & 0x80)) {
+ tmp |= UART_MSR_RI;
+ PORT98->msr |= UART_MSR_RI;
+ }
+ if(!(ms & 0x40))
+ tmp |= UART_MSR_CTS;
+ if(st & 0x80)
+ tmp |= UART_MSR_DSR;
+ PORT98->msr = ((PORT98->msr ^ tmp) >> 4) | tmp;
+ }
+
+ spin_unlock_irqrestore(&PORT.lock, flags);
+ return PORT98->msr;
+}
+
+static void serial98_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ unsigned int ier = inb(IER1_8251F);
+
+ ier &= ~(INTR_8251_TXRE | INTR_8251_TXEE);
+ outb(ier, IER1_8251F);
+}
+
+static void serial98_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ unsigned int ier = inb(IER1_8251F);
+
+ ier |= INTR_8251_TXRE | INTR_8251_TXEE;
+ outb(ier, IER1_8251F);
+}
+
+static void serial98_stop_rx(struct uart_port *port)
+{
+ PORT.read_status_mask &= ~PORT98->dr;
+ outb(DIS_RXR_INT, IER1_CTL);
+}
+
+static void serial98_enable_ms(struct uart_port *port)
+{
+ outb(PORT98->ier | 0x80, IER2_8251F);
+}
+
+static void serial98_rx_chars(struct uart_port *port, int *status,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty = PORT.info->tty;
+ unsigned char ch;
+ int max_count = 256;
+
+ do {
+ if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+ tty->flip.work.func((void *)tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ return; // if TTY_DONT_FLIP is set
+ }
+ ch = inb(PORT.iobase);
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ PORT.icount.rx++;
+
+ if (unlikely(*status & (PORT98->brk | PORT98->pe |
+ PORT98->fe | PORT98->oe))) {
+ /*
+ * For statistics only
+ */
+ if (*status & PORT98->brk) {
+ *status &= ~(PORT98->fe | PORT98->pe);
+ PORT.icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(&PORT))
+ goto ignore_char;
+ } else if (*status & PORT98->pe)
+ PORT.icount.parity++;
+ else if (*status & PORT98->fe)
+ PORT.icount.frame++;
+ if (*status & PORT98->oe)
+ PORT.icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ingored.
+ */
+ *status &= PORT.read_status_mask;
+
+#ifdef CONFIG_SERIAL98_CONSOLE
+ if (PORT.line == PORT.cons->index) {
+ /* Recover the break flag from console xmit */
+ *status |= PORT98->lsr_break_flag;
+ PORT98->lsr_break_flag = 0;
+ }
+#endif
+ if (*status & PORT98->brk) {
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ } else if (*status & PORT98->pe)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (*status & PORT98->fe)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ }
+ if (uart_handle_sysrq_char(&PORT, ch, regs))
+ goto ignore_char;
+ if ((*status & PORT.ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & PORT98->oe) &&
+ tty->flip.count < TTY_FLIPBUF_SIZE) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character.
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ ignore_char:
+ *status = inb(PORT.iobase + 2);
+ } while ((*status & PORT98->rxchk) && (max_count-- > 0));
+ tty_flip_buffer_push(tty);
+}
+
+static void serial98_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &PORT.info->xmit;
+ int count;
+
+ if (PORT.x_char) {
+ outb(PORT.x_char, PORT.iobase);
+ PORT.icount.tx++;
+ PORT.x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&PORT)) {
+ serial98_stop_tx(port, 0);
+ return;
+ }
+
+ count = PORT.fifosize;
+ do {
+ outb(xmit->buf[xmit->tail], PORT.iobase);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ PORT.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&PORT);
+
+ if (uart_circ_empty(xmit))
+ serial98_stop_tx(&PORT, 0);
+}
+
+static void serial98_modem_status(struct uart_port *port)
+{
+ int status;
+
+ status = serial98_msr_in(port);
+
+ if ((status & UART_MSR_ANY_DELTA) == 0)
+ return;
+
+ if (status & UART_MSR_TERI)
+ PORT.icount.rng++;
+ if (status & UART_MSR_DDSR)
+ PORT.icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ uart_handle_dcd_change(&PORT, status & UART_MSR_DCD);
+ if (status & UART_MSR_DCTS)
+ uart_handle_cts_change(&PORT, status & UART_MSR_CTS);
+
+ wake_up_interruptible(&PORT.info->delta_msr_wait);
+}
+
+static void serial98_int(int irq, void *port, struct pt_regs *regs)
+{
+ unsigned int status;
+
+ spin_lock(&PORT.lock);
+ status = inb(PORT.iobase + 2);
+ if (status & PORT98->rxrdy) {
+ serial98_rx_chars(port, &status, regs);
+ }
+ serial98_modem_status(port);
+ if (status & PORT98->txrdy) {
+ serial98_tx_chars(port);
+ }
+ spin_unlock(&PORT.lock);
+}
+
+static unsigned int serial98_tx_empty(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int ret = 0;
+
+ spin_lock_irqsave(&PORT.lock, flags);
+ if (inb(PORT.iobase + 2) & PORT98->txemp)
+ ret = TIOCSER_TEMT;
+
+ spin_unlock_irqrestore(&PORT.lock, flags);
+ return ret;
+}
+
+static unsigned int serial98_get_mctrl(struct uart_port *port)
+{
+ unsigned char status;
+ unsigned int ret = 0;
+
+ status = serial98_msr_in(port);
+ if (status & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+ if (status & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+ if (status & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+ if (status & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void serial98_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ PORT98->cmd &= 0xdd;
+ if (mctrl & TIOCM_RTS)
+ PORT98->cmd |= CMD_RTS;
+
+ if (mctrl & TIOCM_DTR)
+ PORT98->cmd |= CMD_DTR;
+
+ serial98_cmd_out(port, PORT98->cmd);
+}
+
+static void serial98_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&PORT.lock, flags);
+ if (break_state == -1)
+ PORT98->cmd |= CMD_BREAK;
+ else
+ PORT98->cmd &= ~CMD_BREAK;
+
+ serial98_cmd_out(port, PORT98->cmd);
+ spin_unlock_irqrestore(&PORT.lock, flags);
+}
+
+static int serial98_startup(struct uart_port *port)
+{
+ int retval;
+
+ if (PORT.type == PORT_8251_PC98) {
+ /* Wake up UART */
+ PORT98->mode = 0xfc;
+ serial98_mode_set(port);
+ outb(DIS_RXR_INT, IER1_CTL);
+ outb(DIS_TXE_INT, IER1_CTL);
+ outb(DIS_TXR_INT, IER1_CTL);
+ PORT98->mode = 0;
+ serial98_mode_set(port);
+ }
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reeanbled in set_termios())
+ */
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ outb(UART_FCR_ENABLE_FIFO, FCR_8251F);
+ outb((UART_FCR_ENABLE_FIFO
+ | UART_FCR_CLEAR_RCVR
+ | UART_FCR_CLEAR_XMIT), FCR_8251F);
+ outb(0, FCR_8251F);
+ }
+
+ /* Clear the interrupt registers. */
+ inb(0x30);
+ inb(0x32);
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ inb(PORT.iobase);
+ inb(PORT.iobase + 2);
+ inb(PORT.iobase + 4);
+ inb(PORT.iobase + 6);
+ }
+
+ /* Allocate the IRQ */
+ retval = request_irq(PORT.irq, serial98_int, 0,
+ serial98_reg.driver_name, port);
+ if (retval)
+ return retval;
+
+ /*
+ * Now, initialize the UART
+ */
+ PORT98->mode = 0x4e;
+ serial98_mode_set(port);
+ PORT98->cmd = 0x15;
+ serial98_cmd_out(port, PORT98->cmd);
+ PORT98->cmd = 0x05;
+
+ /*
+ * Finally, enable interrupts
+ */
+ outb(0x00, IER2_8251F);
+ outb(ENA_RXR_INT, IER1_CTL);
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ inb(0x30);
+ inb(0x32);
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ inb(PORT.iobase);
+ inb(PORT.iobase + 2);
+ inb(PORT.iobase + 4);
+ inb(PORT.iobase + 6);
+ }
+
+ return 0;
+}
+
+static void serial98_shutdown(struct uart_port *port)
+{
+ unsigned long flags;
+
+ /*
+ * disable all interrupts
+ */
+ spin_lock_irqsave(&PORT.lock, flags);
+ if (PORT.type == PORT_VFAST_PC98)
+ outb(0, VFAST_8251F); /* V.FAST mode off */
+
+ /* disnable all modem status interrupt */
+ outb(0x80, IER2_8251F);
+
+ /* disnable TX/RX interrupt */
+ outb(0x00, IER2_8251F);
+ outb(DIS_RXR_INT, IER1_CTL);
+ outb(DIS_TXE_INT, IER1_CTL);
+ outb(DIS_TXR_INT, IER1_CTL);
+ PORT98->ier = 0;
+
+ spin_unlock_irqrestore(&PORT.lock, flags);
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(PORT.irq, port);
+
+ /* disable break condition and disable the port */
+ serial98_mode_set(port);
+
+ /* disable FIFO's */
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ outb((UART_FCR_ENABLE_FIFO
+ | UART_FCR_CLEAR_RCVR
+ | UART_FCR_CLEAR_XMIT), FCR_8251F);
+ outb(0, FCR_8251F);
+ }
+
+ inb(PORT.iobase);
+}
+
+static void
+serial98_set_termios(struct uart_port *port, struct termios *termios,
+ struct termios *old)
+{
+ unsigned char stopbit, cval, fcr = 0, ier = 0;
+ unsigned long flags;
+ unsigned int baud, quot;
+
+ stopbit = 0x80;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ cval = 0x42;
+ stopbit = 0xc0;
+ break;
+ case CS6:
+ cval = 0x46;
+ break;
+ case CS7:
+ cval = 0x4a;
+ break;
+ default:
+ case CS8:
+ cval = 0x4e;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ cval ^= stopbit;
+ if (termios->c_cflag & PARENB)
+ cval |= 0x10;
+ if (!(termios->c_cflag & PARODD))
+ cval |= 0x20;
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+
+ if (PORT.type == PORT_FIFO_PC98 || PORT.type == PORT_VFAST_PC98) {
+ if ((PORT.uartclk / quot) < (2400 * 16))
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+ else
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+ }
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ */
+ spin_lock_irqsave(&PORT.lock, flags);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ PORT.read_status_mask = PORT98->oe | PORT98->txemp | PORT98->dr;
+ if (termios->c_iflag & INPCK)
+ PORT.read_status_mask |= PORT98->fe | PORT98->pe;
+
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ PORT.read_status_mask |= PORT98->brk;
+ /*
+ * Characteres to ignore
+ */
+ PORT.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ PORT.ignore_status_mask |= PORT98->fe | PORT98->pe;
+
+ if (termios->c_iflag & IGNBRK) {
+ PORT.ignore_status_mask |= PORT98->brk;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ PORT.ignore_status_mask |= PORT98->oe;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ PORT.ignore_status_mask |= PORT98->dr;
+
+ /*
+ * CTS flow control flag and modem status interrupts
+ */
+ if (PORT.flags & UPF_HARDPPS_CD)
+ ier |= 0x80; /* enable modem status interrupt */
+ if (termios->c_cflag & CRTSCTS) {
+ ier |= 0x08; /* enable CTS interrupt */
+ ier |= 0x80; /* enable modem status interrupt */
+ }
+ if (!(termios->c_cflag & CLOCAL)) {
+ ier |= 0x20; /* enable CD interrupt */
+ ier |= 0x80; /* enable modem status interrupt */
+ }
+ PORT98->ier = ier;
+
+ PORT98->mode = cval;
+ serial98_mode_set(port);
+ if (PORT.type == PORT_VFAST_PC98 && quot <= 48) {
+ quot /= 4;
+ if (quot < 1)
+ quot = 1;
+ outb(quot | VFAST_ENABLE, VFAST_8251F);
+ } else {
+ quot /= 3;
+ if (quot < 1)
+ quot = 1;
+ if (PORT.type == PORT_VFAST_PC98)
+ outb(0, VFAST_8251F); /* V.FAST mode off */
+ outb(0xb6, 0x77);
+ outb(quot & 0xff, 0x75); /* LS of divisor */
+ outb(quot >> 8, 0x75); /* MS of divisor */
+ }
+
+ if (fcr & UART_FCR_ENABLE_FIFO) {
+ outb(UART_FCR_ENABLE_FIFO, FCR_8251F);
+ outb(fcr, FCR_8251F);
+ }
+
+ /* enable RX/TX */
+ PORT98->cmd = 0x15;
+ serial98_cmd_out(port, PORT98->cmd);
+ PORT98->cmd = 0x05;
+ /* enable interrupts */
+ outb(0x00, IER2_8251F);
+ outb(ENA_RXR_INT, IER1_CTL);
+ spin_unlock_irqrestore(&PORT.lock, flags);
+}
+
+static const char *serial98_type(struct uart_port *port)
+{
+ char *p;
+
+ switch (PORT.type) {
+ case PORT_8251_PC98:
+ p = "PC98 onboard legacy 8251";
+ break;
+ case PORT_19K_PC98:
+ p = "PC98 onboard max 19200bps";
+ break;
+ case PORT_FIFO_PC98:
+ p = "PC98 onboard with FIFO";
+ break;
+ case PORT_VFAST_PC98:
+ p = "PC98 onboard V.FAST";
+ break;
+ case PORT_PC9861:
+ p = "PC-9861K RS-232C ext. board";
+ break;
+ case PORT_PC9801_101:
+ p = "PC-9801-101 RS-232C ext. board";
+ break;
+ default:
+ return NULL;
+ }
+
+ sprintf(type_str, "%s Clock %dMHz", p, serial98_clk);
+ return type_str;
+}
+
+/* Release the region(s) being used by 'port' */
+static void serial98_release_port(struct uart_port *port)
+{
+ switch (PORT.type) {
+ case PORT_VFAST_PC98:
+ release_region(PORT.iobase + 0xa, 1);
+ case PORT_FIFO_PC98:
+ release_region(PORT.iobase + 8, 1);
+ release_region(PORT.iobase + 6, 1);
+ release_region(PORT.iobase + 4, 1);
+ release_region(PORT.iobase + 2, 1);
+ release_region(PORT.iobase, 1);
+ case PORT_19K_PC98:
+ release_region(SERIAL98_EXT, 1);
+ release_region(0x34, 1);
+ case PORT_8251_PC98:
+ release_region(0x32, 1);
+ release_region(0x30, 1);
+ }
+}
+
+/* Request the region(s) being used by 'port' */
+#define REQ_REGION98(base) (request_region((base), 1, serial98_reg.driver_name))
+static int serial98_request_region(unsigned int type)
+{
+ if (!REQ_REGION98(0x30))
+ return -EBUSY;
+ if (REQ_REGION98(0x32)) {
+ if (type == PORT_8251_PC98)
+ return 0;
+ if (REQ_REGION98(0x34)) {
+ if (REQ_REGION98(SERIAL98_EXT)) {
+ unsigned long base;
+
+ if (type == PORT_19K_PC98)
+ return 0;
+ for (base = 0x130; base <= 0x138; base += 2) {
+ if (!REQ_REGION98(base)) {
+ base -= 2;
+ goto err;
+ }
+ }
+ if (type == PORT_FIFO_PC98)
+ return 0;
+ if (type == PORT_VFAST_PC98) {
+ if (REQ_REGION98(0x13a))
+ return 0;
+ }
+ err:
+ while (base >= 0x130) {
+ release_region(base, 1);
+ base -= 2;
+ }
+ release_region(SERIAL98_EXT, 1);
+ }
+ release_region(0x34, 1);
+ }
+ release_region(0x32, 1);
+ }
+ release_region(0x30, 1);
+ return -EBUSY;
+}
+
+static int serial98_request_port(struct uart_port *port)
+{
+ return serial98_request_region(PORT.type);
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void serial98_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ PORT.type = PORT98->type;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int serial98_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ switch (ser->type) {
+ case PORT_VFAST_PC98:
+ case PORT_FIFO_PC98:
+ case PORT_19K_PC98:
+ case PORT_8251_PC98:
+ /* not implemented yet
+ case PORT_PC9861:
+ case PORT_PC9801_101:
+ */
+ case PORT_UNKNOWN:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ return -EINVAL;
+ if (ser->baud_base < 9600)
+ return -EINVAL;
+ return 0;
+}
+
+static struct uart_ops serial98_ops = {
+ .tx_empty = serial98_tx_empty,
+ .set_mctrl = serial98_set_mctrl,
+ .get_mctrl = serial98_get_mctrl,
+ .stop_tx = serial98_stop_tx,
+ .start_tx = serial98_start_tx,
+ .stop_rx = serial98_stop_rx,
+ .enable_ms = serial98_enable_ms,
+ .break_ctl = serial98_break_ctl,
+ .startup = serial98_startup,
+ .shutdown = serial98_shutdown,
+ .set_termios = serial98_set_termios,
+ .type = serial98_type,
+ .release_port = serial98_release_port,
+ .request_port = serial98_request_port,
+ .config_port = serial98_config_port,
+ .verify_port = serial98_verify_port,
+};
+
+static struct serial98_port serial98_ports[SERIAL98_NR] = {
+ {
+ .port = {
+ .iobase = 0x30,
+ .iotype = SERIAL_IO_PORT,
+ .irq = 4,
+ .fifosize = 1,
+ .ops = &serial98_ops,
+ .flags = ASYNC_BOOT_AUTOCONF,
+ .line = 0,
+ },
+ .rxchk = STAT_8251_RXRDY,
+ .txemp = STAT_8251_TXEMP,
+ .txrdy = STAT_8251_TXRDY,
+ .rxrdy = STAT_8251_RXRDY,
+ .brk = STAT_8251_BRK,
+ .fe = STAT_8251_FER,
+ .oe = STAT_8251_OER,
+ .pe = STAT_8251_PER,
+ .dr = STAT_8251_DSR,
+ },
+};
+
+#ifdef CONFIG_SERIAL98_CONSOLE
+
+#define BOTH_EMPTY (PORT98->txemp | PORT98->txrdy)
+
+/*
+ * Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = inb(PORT.iobase + 2);
+
+ if (status & PORT98->brk)
+ PORT98->lsr_break_flag = PORT98->brk;
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+ /* Wait up to 1s for flow control if necessary */
+ if (PORT.flags & UPF_CONS_FLOW) {
+ tmout = 1000000;
+ while (--tmout &&
+ ((serial98_msr_in(port) & UART_MSR_CTS) == 0))
+ udelay(1);
+ }
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ * The console_lock must be held when we get here.
+ */
+static void
+serial98_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = (struct uart_port *)&serial98_ports[co->index];
+ unsigned int ier1, ier2;
+ int i;
+
+ /*
+ * First save the UER then disable the interrupts
+ */
+ ier1 = inb(IER1_8251F);
+ ier2 = inb(IER2_8251F);
+ /* disnable all modem status interrupt */
+ outb(0x80, IER2_8251F);
+
+ /* disnable TX/RX interrupt */
+ outb(0x00, IER2_8251F);
+ outb(DIS_RXR_INT, IER1_CTL);
+ outb(DIS_TXE_INT, IER1_CTL);
+ outb(DIS_TXR_INT, IER1_CTL);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++, s++) {
+ wait_for_xmitr(port);
+
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ outb(*s, PORT.iobase);
+ if (*s == 10) {
+ wait_for_xmitr(port);
+ outb(13, PORT.iobase);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IER
+ */
+ wait_for_xmitr(port);
+
+ /* restore TX/RX interrupt */
+ outb(0x00, IER2_8251F);
+ if (ier1 & 0x01)
+ outb(ENA_RXR_INT, IER1_CTL);
+ if (ier1 & 0x02)
+ outb(ENA_TXE_INT, IER1_CTL);
+ if (ier1 & 0x04)
+ outb(ENA_TXR_INT, IER1_CTL);
+
+ /* restore modem status interrupt */
+ outb(ier2, IER2_8251F);
+}
+
+static kdev_t serial98_console_device(struct console *co)
+{
+ return mk_kdev(TTY_MAJOR, 64 + co->index);
+}
+
+static int __init serial98_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= SERIAL98_NR)
+ co->index = 0;
+ port = &serial98_ports[co->index].port;
+
+ /*
+ * Temporary fix.
+ */
+ spin_lock_init(&port->lock);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+void __init serial98_console_init(void)
+{
+ register_console(&serial98_console);
+}
+
+#endif /* CONFIG_SERIAL98_CONSOLE */
+
+
+static int __init serial98_init(void)
+{
+ int ret;
+ unsigned char iir1, iir2;
+
+ if (PC9800_8MHz_P()) {
+ serial98_clk = 8;
+ serial98_ports[0].port.uartclk = 374400 * 16;
+ } else {
+ serial98_clk = 5;
+ serial98_ports[0].port.uartclk = 460800 * 16;
+ }
+
+ printk(KERN_INFO "serial98: PC-9801 standard serial port driver Version 0.1alpha\n");
+ serial98_ports[0].type = PORT_8251_PC98;
+ /* Check FIFO exist */
+ iir1 = inb(IIR_8251F);
+ iir2 = inb(IIR_8251F);
+ if ((iir1 & 0x40) != (iir2 & 0x40) && (iir1 & 0x20) == (iir2 & 0x20)) {
+ serial98_ports[0].port.iobase = 0x130;
+ serial98_ports[0].port.fifosize = 16;
+ serial98_ports[0].rxchk = STAT_8251F_DSR;
+ serial98_ports[0].txemp = STAT_8251F_TXEMP;
+ serial98_ports[0].txrdy = STAT_8251F_TXRDY;
+ serial98_ports[0].rxrdy = STAT_8251F_RXRDY;
+ serial98_ports[0].brk = STAT_8251F_BRK;
+ serial98_ports[0].fe = STAT_8251F_FER;
+ serial98_ports[0].oe = STAT_8251F_OER;
+ serial98_ports[0].pe = STAT_8251F_PER;
+ serial98_ports[0].dr = STAT_8251F_DSR;
+
+ if (*(unsigned char*)__va(PC9821SCA_RSFLAGS) & 0x10)
+ serial98_ports[0].type = PORT_VFAST_PC98;
+ else {
+ outb(serial98_ports[0].ext | 0x40, SERIAL98_EXT);
+ serial98_ports[0].port.uartclk *= 4;
+ serial98_ports[0].type = PORT_FIFO_PC98;
+ }
+ } else if ((serial98_ports[0].ext = inb(SERIAL98_EXT)) != 0xff) {
+ outb(serial98_ports[0].ext | 0x40, SERIAL98_EXT);
+ if (inb(SERIAL98_EXT) == (serial98_ports[0].ext | 0x40)) {
+ serial98_ports[0].port.uartclk *= 4;
+ serial98_ports[0].type = PORT_19K_PC98;
+ } else {
+ serial98_ops.enable_ms = NULL;
+ outb(serial98_ports[0].ext, SERIAL98_EXT);
+ }
+ }
+
+ if (serial98_request_region(serial98_ports[0].type))
+ return -EBUSY;
+
+ ret = uart_register_driver(&serial98_reg);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < SERIAL98_NR; i++) {
+ uart_add_one_port(&serial98_reg,
+ (struct uart_port *)&serial98_ports[i]);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit serial98_exit(void)
+{
+ int i;
+
+ if (serial98_ports[0].type == PORT_19K_PC98
+ || serial98_ports[0].type == PORT_FIFO_PC98)
+ outb(serial98_ports[0].ext, SERIAL98_EXT);
+
+ for (i = 0; i < SERIAL98_NR; i++) {
+ uart_remove_one_port(&serial98_reg,
+ (struct uart_port *)&serial98_ports[i]);
+ }
+
+ uart_unregister_driver(&serial98_reg);
+}
+
+module_init(serial98_init);
+module_exit(serial98_exit);
+
+MODULE_AUTHOR("Osamu Tomita <[email protected]>");
+MODULE_DESCRIPTION("PC-9801 standard serial port driver Version 0.1alpha");
+MODULE_LICENSE("GPL");
diff -Nru linux-2.5.64/include/linux/serial_core.h linux98-2.5.64/include/linux/serial_core.h
--- linux-2.5.64/include/linux/serial_core.h 2003-03-05 11:23:13.000000000 +0900
+++ linux98-2.5.64/include/linux/serial_core.h 2003-03-05 11:55:15.000000000 +0900
@@ -59,6 +59,14 @@
/* NEC v850. */
#define PORT_NB85E_UART 40

+/* NEC PC-9800 */
+#define PORT_8251_PC98 41
+#define PORT_19K_PC98 42
+#define PORT_FIFO_PC98 43
+#define PORT_VFAST_PC98 44
+#define PORT_PC9861 45
+#define PORT_PC9801_101 46
+

#ifdef __KERNEL__

2003-03-09 04:28:05

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (18/20) setup resources

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (18/20)

Support difference of IO port/memory address, using mach-* scheme.

Regards,
Osamu tomita


diff -Nru linux-2.5.64/arch/i386/kernel/setup.c linux98-2.5.64/arch/i386/kernel/setup.c
--- linux-2.5.64/arch/i386/kernel/setup.c 2003-03-05 11:30:00.000000000 +0900
+++ linux98-2.5.64/arch/i386/kernel/setup.c 2003-03-05 11:58:20.000000000 +0900
@@ -43,6 +43,7 @@
#include <asm/setup.h>
#include <asm/arch_hooks.h>
#include "setup_arch_pre.h"
+#include "mach_resources.h"

int disable_pse __initdata = 0;

@@ -104,97 +105,20 @@
static char command_line[COMMAND_LINE_SIZE];
char saved_command_line[COMMAND_LINE_SIZE];

-struct resource standard_io_resources[] = {
- { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
- { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
- { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
- { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
- { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
- { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
- { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
- { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
-};
-#ifdef CONFIG_MELAN
-standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
-standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
-#endif
-
-#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
-
static struct resource code_resource = { "Kernel code", 0x100000, 0 };
static struct resource data_resource = { "Kernel data", 0, 0 };
-static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
-
-/* System ROM resources */
-#define MAXROMS 6
-static struct resource rom_resources[MAXROMS] = {
- { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
- { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
-};
-
-#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)

static void __init probe_roms(void)
{
int roms = 1;
- unsigned long base;
- unsigned char *romstart;

request_resource(&iomem_resource, rom_resources+0);

/* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
- for (base = 0xC0000; base < 0xE0000; base += 2048) {
- romstart = isa_bus_to_virt(base);
- if (!romsignature(romstart))
- continue;
- request_resource(&iomem_resource, rom_resources + roms);
- roms++;
- break;
- }
+ probe_video_rom(roms);

- /* Extension roms at C800:0000 - DFFF:0000 */
- for (base = 0xC8000; base < 0xE0000; base += 2048) {
- unsigned long length;
-
- romstart = isa_bus_to_virt(base);
- if (!romsignature(romstart))
- continue;
- length = romstart[2] * 512;
- if (length) {
- unsigned int i;
- unsigned char chksum;
-
- chksum = 0;
- for (i = 0; i < length; i++)
- chksum += romstart[i];
-
- /* Good checksum? */
- if (!chksum) {
- rom_resources[roms].start = base;
- rom_resources[roms].end = base + length - 1;
- rom_resources[roms].name = "Extension ROM";
- rom_resources[roms].flags = IORESOURCE_BUSY;
-
- request_resource(&iomem_resource, rom_resources + roms);
- roms++;
- if (roms >= MAXROMS)
- return;
- }
- }
- }
-
- /* Final check for motherboard extension rom at E000:0000 */
- base = 0xE0000;
- romstart = isa_bus_to_virt(base);
-
- if (romsignature(romstart)) {
- rom_resources[roms].start = base;
- rom_resources[roms].end = base + 65535;
- rom_resources[roms].name = "Extension ROM";
- rom_resources[roms].flags = IORESOURCE_BUSY;
-
- request_resource(&iomem_resource, rom_resources + roms);
- }
+ /* Extension roms */
+ probe_extension_roms(roms);
}

static void __init limit_regions (unsigned long long size)
@@ -838,7 +762,8 @@
request_resource(res, &data_resource);
}
}
- request_resource(&iomem_resource, &vram_resource);
+
+ request_graphics_resource();

/* request I/O space for devices used on all i[345]86 PCs */
for (i = 0; i < STANDARD_IO_RESOURCES; i++)
@@ -923,6 +848,8 @@
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
+#elif defined(CONFIG_GDC_CONSOLE)
+ conswitchp = &gdc_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
diff -Nru linux/include/asm-i386/mach-default/mach_resources.h linux98/include/asm-i386/mach-default/mach_resources.h
--- linux/include/asm-i386/mach-default/mach_resources.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-default/mach_resources.h 2003-03-01 11:10:47.000000000 +0900
@@ -0,0 +1,110 @@
+/*
+ * include/asm-i386/mach-default/mach_resources.h
+ *
+ * Machine specific resource allocation for generic.
+ * Split out from setup.c by Osamu Tomita <[email protected]>
+ */
+#ifndef _MACH_RESOURCES_H
+#define _MACH_RESOURCES_H
+
+struct resource standard_io_resources[] = {
+ { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+ { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+ { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+ { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+ { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+ { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+ { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
+};
+#ifdef CONFIG_MELAN
+standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
+standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
+#endif
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
+
+/* System ROM resources */
+#define MAXROMS 6
+static struct resource rom_resources[MAXROMS] = {
+ { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
+ { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
+};
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static inline void probe_video_rom(int roms)
+{
+ unsigned long base;
+ unsigned char *romstart;
+
+
+ /* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
+ for (base = 0xC0000; base < 0xE0000; base += 2048) {
+ romstart = isa_bus_to_virt(base);
+ if (!romsignature(romstart))
+ continue;
+ request_resource(&iomem_resource, rom_resources + roms);
+ roms++;
+ break;
+ }
+}
+
+static inline void probe_extension_roms(int roms)
+{
+ unsigned long base;
+ unsigned char *romstart;
+
+ /* Extension roms at C800:0000 - DFFF:0000 */
+ for (base = 0xC8000; base < 0xE0000; base += 2048) {
+ unsigned long length;
+
+ romstart = isa_bus_to_virt(base);
+ if (!romsignature(romstart))
+ continue;
+ length = romstart[2] * 512;
+ if (length) {
+ unsigned int i;
+ unsigned char chksum;
+
+ chksum = 0;
+ for (i = 0; i < length; i++)
+ chksum += romstart[i];
+
+ /* Good checksum? */
+ if (!chksum) {
+ rom_resources[roms].start = base;
+ rom_resources[roms].end = base + length - 1;
+ rom_resources[roms].name = "Extension ROM";
+ rom_resources[roms].flags = IORESOURCE_BUSY;
+
+ request_resource(&iomem_resource, rom_resources + roms);
+ roms++;
+ if (roms >= MAXROMS)
+ return;
+ }
+ }
+ }
+
+ /* Final check for motherboard extension rom at E000:0000 */
+ base = 0xE0000;
+ romstart = isa_bus_to_virt(base);
+
+ if (romsignature(romstart)) {
+ rom_resources[roms].start = base;
+ rom_resources[roms].end = base + 65535;
+ rom_resources[roms].name = "Extension ROM";
+ rom_resources[roms].flags = IORESOURCE_BUSY;
+
+ request_resource(&iomem_resource, rom_resources + roms);
+ }
+}
+
+static inline void request_graphics_resource(void)
+{
+ request_resource(&iomem_resource, &vram_resource);
+}
+
+#endif /* !_MACH_RESOURCES_H */
diff -Nru linux/include/asm-i386/mach-pc9800/mach_resources.h linux98/include/asm-i386/mach-pc9800/mach_resources.h
--- linux/include/asm-i386/mach-pc9800/mach_resources.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/mach_resources.h 2003-03-01 11:12:46.000000000 +0900
@@ -0,0 +1,191 @@
+/*
+ * include/asm-i386/mach-pc9800/mach_resources.h
+ *
+ * Machine specific resource allocation for PC-9800.
+ * Written by Osamu Tomita <[email protected]>
+ */
+#ifndef _MACH_RESOURCES_H
+#define _MACH_RESOURCES_H
+
+static char str_pic1[] = "pic1";
+static char str_dma[] = "dma";
+static char str_pic2[] = "pic2";
+static char str_calender_clock[] = "calender clock";
+static char str_system[] = "system";
+static char str_nmi_control[] = "nmi control";
+static char str_kanji_rom[] = "kanji rom";
+static char str_keyboard[] = "keyboard";
+static char str_text_gdc[] = "text gdc";
+static char str_crtc[] = "crtc";
+static char str_timer[] = "timer";
+static char str_graphic_gdc[] = "graphic gdc";
+static char str_dma_ex_bank[] = "dma ex. bank";
+static char str_beep_freq[] = "beep freq.";
+static char str_mouse_pio[] = "mouse pio";
+struct resource standard_io_resources[] = {
+ { str_pic1, 0x00, 0x00, IORESOURCE_BUSY },
+ { str_dma, 0x01, 0x01, IORESOURCE_BUSY },
+ { str_pic1, 0x02, 0x02, IORESOURCE_BUSY },
+ { str_dma, 0x03, 0x03, IORESOURCE_BUSY },
+ { str_dma, 0x05, 0x05, IORESOURCE_BUSY },
+ { str_dma, 0x07, 0x07, IORESOURCE_BUSY },
+ { str_pic2, 0x08, 0x08, IORESOURCE_BUSY },
+ { str_dma, 0x09, 0x09, IORESOURCE_BUSY },
+ { str_pic2, 0x0a, 0x0a, IORESOURCE_BUSY },
+ { str_dma, 0x0b, 0x0b, IORESOURCE_BUSY },
+ { str_dma, 0x0d, 0x0d, IORESOURCE_BUSY },
+ { str_dma, 0x0f, 0x0f, IORESOURCE_BUSY },
+ { str_dma, 0x11, 0x11, IORESOURCE_BUSY },
+ { str_dma, 0x13, 0x13, IORESOURCE_BUSY },
+ { str_dma, 0x15, 0x15, IORESOURCE_BUSY },
+ { str_dma, 0x17, 0x17, IORESOURCE_BUSY },
+ { str_dma, 0x19, 0x19, IORESOURCE_BUSY },
+ { str_dma, 0x1b, 0x1b, IORESOURCE_BUSY },
+ { str_dma, 0x1d, 0x1d, IORESOURCE_BUSY },
+ { str_dma, 0x1f, 0x1f, IORESOURCE_BUSY },
+ { str_calender_clock, 0x20, 0x20, 0 },
+ { str_dma, 0x21, 0x21, IORESOURCE_BUSY },
+ { str_calender_clock, 0x22, 0x22, 0 },
+ { str_dma, 0x23, 0x23, IORESOURCE_BUSY },
+ { str_dma, 0x25, 0x25, IORESOURCE_BUSY },
+ { str_dma, 0x27, 0x27, IORESOURCE_BUSY },
+ { str_dma, 0x29, 0x29, IORESOURCE_BUSY },
+ { str_dma, 0x2b, 0x2b, IORESOURCE_BUSY },
+ { str_dma, 0x2d, 0x2d, IORESOURCE_BUSY },
+ { str_system, 0x31, 0x31, IORESOURCE_BUSY },
+ { str_system, 0x33, 0x33, IORESOURCE_BUSY },
+ { str_system, 0x35, 0x35, IORESOURCE_BUSY },
+ { str_system, 0x37, 0x37, IORESOURCE_BUSY },
+ { str_nmi_control, 0x50, 0x50, IORESOURCE_BUSY },
+ { str_nmi_control, 0x52, 0x52, IORESOURCE_BUSY },
+ { "time stamp", 0x5c, 0x5f, IORESOURCE_BUSY },
+ { str_kanji_rom, 0xa1, 0xa1, IORESOURCE_BUSY },
+ { str_kanji_rom, 0xa3, 0xa3, IORESOURCE_BUSY },
+ { str_kanji_rom, 0xa5, 0xa5, IORESOURCE_BUSY },
+ { str_kanji_rom, 0xa7, 0xa7, IORESOURCE_BUSY },
+ { str_kanji_rom, 0xa9, 0xa9, IORESOURCE_BUSY },
+ { str_keyboard, 0x41, 0x41, IORESOURCE_BUSY },
+ { str_keyboard, 0x43, 0x43, IORESOURCE_BUSY },
+ { str_text_gdc, 0x60, 0x60, IORESOURCE_BUSY },
+ { str_text_gdc, 0x62, 0x62, IORESOURCE_BUSY },
+ { str_text_gdc, 0x64, 0x64, IORESOURCE_BUSY },
+ { str_text_gdc, 0x66, 0x66, IORESOURCE_BUSY },
+ { str_text_gdc, 0x68, 0x68, IORESOURCE_BUSY },
+ { str_text_gdc, 0x6a, 0x6a, IORESOURCE_BUSY },
+ { str_text_gdc, 0x6c, 0x6c, IORESOURCE_BUSY },
+ { str_text_gdc, 0x6e, 0x6e, IORESOURCE_BUSY },
+ { str_crtc, 0x70, 0x70, IORESOURCE_BUSY },
+ { str_crtc, 0x72, 0x72, IORESOURCE_BUSY },
+ { str_crtc, 0x74, 0x74, IORESOURCE_BUSY },
+ { str_crtc, 0x74, 0x74, IORESOURCE_BUSY },
+ { str_crtc, 0x76, 0x76, IORESOURCE_BUSY },
+ { str_crtc, 0x78, 0x78, IORESOURCE_BUSY },
+ { str_crtc, 0x7a, 0x7a, IORESOURCE_BUSY },
+ { str_timer, 0x71, 0x71, IORESOURCE_BUSY },
+ { str_timer, 0x73, 0x73, IORESOURCE_BUSY },
+ { str_timer, 0x75, 0x75, IORESOURCE_BUSY },
+ { str_timer, 0x77, 0x77, IORESOURCE_BUSY },
+ { str_graphic_gdc, 0xa0, 0xa0, IORESOURCE_BUSY },
+ { str_graphic_gdc, 0xa2, 0xa2, IORESOURCE_BUSY },
+ { str_graphic_gdc, 0xa4, 0xa4, IORESOURCE_BUSY },
+ { str_graphic_gdc, 0xa6, 0xa6, IORESOURCE_BUSY },
+ { "cpu", 0xf0, 0xf7, IORESOURCE_BUSY },
+ { "fpu", 0xf8, 0xff, IORESOURCE_BUSY },
+ { str_dma_ex_bank, 0x0e05, 0x0e05, 0 },
+ { str_dma_ex_bank, 0x0e07, 0x0e07, 0 },
+ { str_dma_ex_bank, 0x0e09, 0x0e09, 0 },
+ { str_dma_ex_bank, 0x0e0b, 0x0e0b, 0 },
+ { str_beep_freq, 0x3fd9, 0x3fd9, IORESOURCE_BUSY },
+ { str_beep_freq, 0x3fdb, 0x3fdb, IORESOURCE_BUSY },
+ { str_beep_freq, 0x3fdd, 0x3fdd, IORESOURCE_BUSY },
+ { str_beep_freq, 0x3fdf, 0x3fdf, IORESOURCE_BUSY },
+ /* All PC-9800 have (exactly) one mouse interface. */
+ { str_mouse_pio, 0x7fd9, 0x7fd9, 0 },
+ { str_mouse_pio, 0x7fdb, 0x7fdb, 0 },
+ { str_mouse_pio, 0x7fdd, 0x7fdd, 0 },
+ { str_mouse_pio, 0x7fdf, 0x7fdf, 0 },
+ { "mouse timer", 0xbfdb, 0xbfdb, 0 },
+ { "mouse irq", 0x98d7, 0x98d7, 0 },
+};
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+static struct resource tvram_resource = { "Text VRAM/CG window", 0xa0000, 0xa4fff, IORESOURCE_BUSY };
+static struct resource gvram_brg_resource = { "Graphic VRAM (B/R/G)", 0xa8000, 0xbffff, IORESOURCE_BUSY };
+static struct resource gvram_e_resource = { "Graphic VRAM (E)", 0xe0000, 0xe7fff, IORESOURCE_BUSY };
+
+/* System ROM resources */
+#define MAXROMS 6
+static struct resource rom_resources[MAXROMS] = {
+ { "System ROM", 0xe8000, 0xfffff, IORESOURCE_BUSY }
+};
+
+static inline void probe_video_rom(int roms)
+{
+ /* PC-9800 has no video ROM */
+}
+
+static inline void probe_extension_roms(int roms)
+{
+ int i;
+ __u8 *xrom_id;
+
+ xrom_id = (__u8 *) isa_bus_to_virt(PC9800SCA_XROM_ID + 0x10);
+
+ for (i = 0; i < 16; i++) {
+ if (xrom_id[i] & 0x80) {
+ int j;
+
+ for (j = i + 1; j < 16 && (xrom_id[j] & 0x80); j++)
+ ;
+ rom_resources[roms].start = 0x0d0000 + i * 0x001000;
+ rom_resources[roms].end = 0x0d0000 + j * 0x001000 - 1;
+ rom_resources[roms].name = "Extension ROM";
+ rom_resources[roms].flags = IORESOURCE_BUSY;
+
+ request_resource(&iomem_resource,
+ rom_resources + roms);
+ if (++roms >= MAXROMS)
+ return;
+ }
+ }
+}
+
+static inline void request_graphics_resource(void)
+{
+ int i;
+
+ if (PC9800_HIGHRESO_P()) {
+ tvram_resource.start = 0xe0000;
+ tvram_resource.end = 0xe4fff;
+ gvram_brg_resource.name = "Graphic VRAM";
+ gvram_brg_resource.start = 0xc0000;
+ gvram_brg_resource.end = 0xdffff;
+ }
+
+ request_resource(&iomem_resource, &tvram_resource);
+ request_resource(&iomem_resource, &gvram_brg_resource);
+ if (!PC9800_HIGHRESO_P())
+ request_resource(&iomem_resource, &gvram_e_resource);
+
+ if (PC9800_HIGHRESO_P() || PC9800_9821_P()) {
+ static char graphics[] = "graphics";
+ static struct resource graphics_resources[] = {
+ { graphics, 0x9a0, 0x9a0, 0 },
+ { graphics, 0x9a2, 0x9a2, 0 },
+ { graphics, 0x9a4, 0x9a4, 0 },
+ { graphics, 0x9a6, 0x9a6, 0 },
+ { graphics, 0x9a8, 0x9a8, 0 },
+ { graphics, 0x9aa, 0x9aa, 0 },
+ { graphics, 0x9ac, 0x9ac, 0 },
+ { graphics, 0x9ae, 0x9ae, 0 },
+ };
+
+#define GRAPHICS_RESOURCES (sizeof(graphics_resources)/sizeof(struct resource))
+
+ for (i = 0; i < GRAPHICS_RESOURCES; i++)
+ request_resource(&ioport_resource, graphics_resources + i);
+ }
+}
+
+#endif /* !_MACH_RESOURCES_H */

2003-03-09 04:32:18

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (19/20) SMP

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (19/20)

SMP support for PC98.
- Support mpc table location.
- Handling EBDA.
- Hnadling warm reset vector.

Regards,
Osamu tomita


diff -Nru linux-2.5.61-ac1/arch/i386/kernel/mpparse.c linux98-2.5.61-ac1/arch/i386/kernel/mpparse.c
--- linux-2.5.61-ac1/arch/i386/kernel/mpparse.c 2003-02-18 08:58:20.000000000 +0900
+++ linux98-2.5.61-ac1/arch/i386/kernel/mpparse.c 2003-02-18 15:52:44.000000000 +0900
@@ -33,6 +33,7 @@

#include <mach_apic.h>
#include <mach_mpparse.h>
+#include <bios_ebda.h>

/* Have we found an MP table */
int smp_found_config;
@@ -654,7 +655,8 @@
* Read the physical hardware table. Anything here will
* override the defaults.
*/
- if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+ if (!smp_read_mpc(pc98 ? phys_to_virt(mpf->mpf_physptr)
+ : (void *)mpf->mpf_physptr)) {
smp_found_config = 0;
printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
@@ -708,8 +710,23 @@
printk(KERN_INFO "found SMP MP-table at %08lx\n",
virt_to_phys(mpf));
reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
- if (mpf->mpf_physptr)
- reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE);
+ if (mpf->mpf_physptr) {
+ /*
+ * We cannot access to MPC table to compute
+ * table size yet, as only few megabytes from
+ * the bottom is mapped now.
+ * PC-9800's MPC table places on the very last
+ * of physical memory; so that simply reserving
+ * PAGE_SIZE from mpg->mpf_physptr yields BUG()
+ * in reserve_bootmem.
+ */
+ unsigned long size = PAGE_SIZE;
+ unsigned long end = max_low_pfn * PAGE_SIZE;
+ if (mpf->mpf_physptr + size > end)
+ size = end - mpf->mpf_physptr;
+ reserve_bootmem(mpf->mpf_physptr, size);
+ }
+
mpf_found = mpf;
return 1;
}
@@ -752,9 +769,9 @@
* MP1.4 SPEC states to only scan first 1K of 4K EBDA.
*/

- address = *(unsigned short *)phys_to_virt(0x40E);
- address <<= 4;
- smp_scan_config(address, 0x400);
+ address = get_bios_ebda();
+ if (address)
+ smp_scan_config(address, 0x400);
}


diff -Nru linux-2.5.63/arch/i386/kernel/smpboot.c linux98-2.5.63/arch/i386/kernel/smpboot.c
--- linux-2.5.63/arch/i386/kernel/smpboot.c 2003-02-25 04:05:31.000000000 +0900
+++ linux98-2.5.63/arch/i386/kernel/smpboot.c 2003-02-28 13:52:18.000000000 +0900
@@ -49,10 +49,10 @@
#include <asm/tlbflush.h>
#include <asm/desc.h>
#include <asm/arch_hooks.h>
-#include "smpboot_hooks.h"

#include <mach_apic.h>
#include <mach_wakecpu.h>
+#include "smpboot_hooks.h"

/* Set if we find a B stepping CPU */
static int __initdata smp_b_stepping;
@@ -823,13 +823,7 @@

store_NMI_vector(&nmi_high, &nmi_low);

- CMOS_WRITE(0xa, 0xf);
- local_flush_tlb();
- Dprintk("1.\n");
- *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
- Dprintk("2.\n");
- *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
- Dprintk("3.\n");
+ smpboot_setup_warm_reset_vector(start_eip);

/*
* Starting actual IPI sequence...
@@ -1044,7 +1038,7 @@
/*
* Cleanup possible dangling ends...
*/
- smpboot_setup_warm_reset_vector();
+ smpboot_restore_warm_reset_vector();

/*
* Allow the user to impress friends.
diff -Nru linux/include/asm-i386/mach-default/bios_ebda.h linux98/include/asm-i386/mach-default/bios_ebda.h
--- linux/include/asm-i386/mach-default/bios_ebda.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-default/bios_ebda.h 2002-12-18 22:40:38.000000000 +0900
@@ -0,0 +1,15 @@
+#ifndef _MACH_BIOS_EBDA_H
+#define _MACH_BIOS_EBDA_H
+
+/*
+ * there is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E.
+ */
+static inline unsigned int get_bios_ebda(void)
+{
+ unsigned int address = *(unsigned short *)phys_to_virt(0x40E);
+ address <<= 4;
+ return address; /* 0 means none */
+}
+
+#endif /* _MACH_BIOS_EBDA_H */
diff -Nru linux/include/asm-i386/mach-default/smpboot_hooks.h linux98/include/asm-i386/mach-default/smpboot_hooks.h
--- linux/include/asm-i386/mach-default/smpboot_hooks.h 2003-02-25 04:05:15.000000000 +0900
+++ linux98/include/asm-i386/mach-default/smpboot_hooks.h 2003-02-28 13:56:55.000000000 +0900
@@ -6,7 +6,18 @@
io_apic_irqs = 0;
}

-static inline void smpboot_setup_warm_reset_vector(void)
+static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
+{
+ CMOS_WRITE(0xa, 0xf);
+ local_flush_tlb();
+ Dprintk("1.\n");
+ *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
+ Dprintk("2.\n");
+ *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
+ Dprintk("3.\n");
+}
+
+static inline void smpboot_restore_warm_reset_vector(void)
{
/*
* Install writable page 0 entry to set BIOS data area.
diff -Nru linux/include/asm-i386/mach-pc9800/bios_ebda.h linux98/include/asm-i386/mach-pc9800/bios_ebda.h
--- linux/include/asm-i386/mach-pc9800/bios_ebda.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/bios_ebda.h 2002-12-18 22:49:59.000000000 +0900
@@ -0,0 +1,14 @@
+#ifndef _MACH_BIOS_EBDA_H
+#define _MACH_BIOS_EBDA_H
+
+/*
+ * PC-9800 has no EBDA.
+ * Its BIOS uses 0x40E for other purpose,
+ * Not pointer to 4K EBDA area.
+ */
+static inline unsigned int get_bios_ebda(void)
+{
+ return 0; /* 0 means none */
+}
+
+#endif /* _MACH_BIOS_EBDA_H */
diff -Nru linux/include/asm-i386/mach-pc9800/mach_wakecpu.h linux98/include/asm-i386/mach-pc9800/mach_wakecpu.h
--- linux/include/asm-i386/mach-pc9800/mach_wakecpu.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/mach_wakecpu.h 2003-01-10 11:40:16.000000000 +0900
@@ -0,0 +1,45 @@
+#ifndef __ASM_MACH_WAKECPU_H
+#define __ASM_MACH_WAKECPU_H
+
+/*
+ * This file copes with machines that wakeup secondary CPUs by the
+ * INIT, INIT, STARTUP sequence.
+ */
+
+#define WAKE_SECONDARY_VIA_INIT
+
+/*
+ * On PC-9800, continuation on warm reset is done by loading
+ * %ss:%sp from 0x0000:0404 and executing 'lret', so:
+ */
+#define TRAMPOLINE_LOW phys_to_virt(0x4fa)
+#define TRAMPOLINE_HIGH phys_to_virt(0x4fc)
+
+#define boot_cpu_apicid boot_cpu_physical_apicid
+
+static inline void wait_for_init_deassert(atomic_t *deassert)
+{
+ while (!atomic_read(deassert));
+ return;
+}
+
+/* Nothing to do for most platforms, since cleared by the INIT cycle */
+static inline void smp_callin_clear_local_apic(void)
+{
+}
+
+static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
+{
+}
+
+static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
+{
+}
+
+#if APIC_DEBUG
+ #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid)
+#else
+ #define inquire_remote_apic(apicid) {}
+#endif
+
+#endif /* __ASM_MACH_WAKECPU_H */
diff -Nru linux/include/asm-i386/mach-pc9800/smpboot_hooks.h linux98/include/asm-i386/mach-pc9800/smpboot_hooks.h
--- linux/include/asm-i386/mach-pc9800/smpboot_hooks.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/smpboot_hooks.h 2003-02-28 13:53:53.000000000 +0900
@@ -0,0 +1,52 @@
+/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
+ * which needs to alter them. */
+
+static inline void smpboot_clear_io_apic_irqs(void)
+{
+ io_apic_irqs = 0;
+}
+
+static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
+{
+ /* reset code is stored in 8255 on PC-9800. */
+ outb(0x0e, 0x37); /* SHUT0 = 0 */
+ local_flush_tlb();
+ Dprintk("1.\n");
+ *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
+ Dprintk("2.\n");
+ *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
+ Dprintk("3.\n");
+ /*
+ * On PC-9800, continuation on warm reset is done by loading
+ * %ss:%sp from 0x0000:0404 and executing 'lret', so:
+ */
+ /* 0x3f0 is on unused interrupt vector and should be safe... */
+ *((volatile unsigned long *) phys_to_virt(0x404)) = 0x000003f0;
+ Dprintk("4.\n");
+}
+
+static inline void smpboot_restore_warm_reset_vector(void)
+{
+ /*
+ * Install writable page 0 entry to set BIOS data area.
+ */
+ local_flush_tlb();
+
+ /*
+ * Paranoid: Set warm reset code and vector here back
+ * to default values.
+ */
+ outb(0x0f, 0x37); /* SHUT0 = 1 */
+
+ *((volatile long *) phys_to_virt(0x404)) = 0;
+}
+
+static inline void smpboot_setup_io_apic(void)
+{
+ /*
+ * Here we can be sure that there is an IO-APIC in the system. Let's
+ * go and set it up:
+ */
+ if (!skip_ioapic_setup && nr_ioapics)
+ setup_IO_APIC();
+}
diff -Nru linux/include/asm-i386/mach-visws/smpboot_hooks.h linux98/include/asm-i386/mach-visws/smpboot_hooks.h
--- linux/include/asm-i386/mach-visws/smpboot_hooks.h 2003-02-25 04:05:10.000000000 +0900
+++ linux98/include/asm-i386/mach-visws/smpboot_hooks.h 2003-02-28 13:57:13.000000000 +0900
@@ -1,10 +1,21 @@
+static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
+{
+ CMOS_WRITE(0xa, 0xf);
+ local_flush_tlb();
+ Dprintk("1.\n");
+ *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
+ Dprintk("2.\n");
+ *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
+ Dprintk("3.\n");
+}
+
/* for visws do nothing for any of these */

static inline void smpboot_clear_io_apic_irqs(void)
{
}

-static inline void smpboot_setup_warm_reset_vector(void)
+static inline void smpboot_restore_warm_reset_vector(void)
{
}

2003-03-09 04:33:18

by Osamu Tomita

[permalink] [raw]
Subject: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (20/20) timer

This is the patch to support NEC PC-9800 subarchitecture
against 2.5.64-ac3. (20/20)

Support difference of timer, using mach-* scheme.
- Change CLOCK_TICK_RATE from constant to variable.
Some PC98 can select base clock at boottime.
- Replace calibrate_tsc function using anoter time counter on PC98.
Because PIT channel2 on notebook PC98 is stopped.

Regards,
Osamu Tomita


diff -Nru linux-2.5.63/arch/i386/kernel/timers/timer_pit.c linux98-2.5.63/arch/i386/kernel/timers/timer_pit.c
--- linux-2.5.63/arch/i386/kernel/timers/timer_pit.c 2003-02-25 04:05:41.000000000 +0900
+++ linux98-2.5.63/arch/i386/kernel/timers/timer_pit.c 2003-03-04 14:58:59.000000000 +0900
@@ -16,9 +16,13 @@
extern spinlock_t i8259A_lock;
extern spinlock_t i8253_lock;
#include "do_timer.h"
+#include "io_ports.h"
+
+static int count_p; /* counter in get_offset_pit() */

static int init_pit(void)
{
+ count_p = LATCH;
return 0;
}

@@ -77,7 +81,6 @@
{
int count;
unsigned long flags;
- static int count_p = LATCH; /* for the first call after boot */
static unsigned long jiffies_p = 0;

/*
@@ -87,9 +90,9 @@

spin_lock_irqsave(&i8253_lock, flags);
/* timer count may underflow right here */
- outb_p(0x00, 0x43); /* latch the count ASAP */
+ outb_p(0x00, PIT_MODE); /* latch the count ASAP */

- count = inb_p(0x40); /* read the latched count */
+ count = inb_p(PIT_CH0); /* read the latched count */

/*
* We do this guaranteed double memory access instead of a _p
@@ -97,13 +100,13 @@
*/
jiffies_t = jiffies;

- count |= inb_p(0x40) << 8;
+ count |= inb_p(PIT_CH0) << 8;

/* VIA686a test code... reset the latch if count > max + 1 */
if (count > LATCH) {
- outb_p(0x34, 0x43);
- outb_p(LATCH & 0xff, 0x40);
- outb(LATCH >> 8, 0x40);
+ outb_p(0x34, PIT_MODE);
+ outb_p(LATCH & 0xff, PIT_CH0);
+ outb(LATCH >> 8, PIT_CH0);
count = LATCH - 1;
}

diff -Nru linux-2.5.63/arch/i386/kernel/timers/timer_tsc.c linux98-2.5.63/arch/i386/kernel/timers/timer_tsc.c
--- linux-2.5.63/arch/i386/kernel/timers/timer_tsc.c 2003-02-25 04:05:37.000000000 +0900
+++ linux98-2.5.63/arch/i386/kernel/timers/timer_tsc.c 2003-03-04 14:39:42.000000000 +0900
@@ -14,6 +14,9 @@
/* processor.h for distable_tsc flag */
#include <asm/processor.h>

+#include "io_ports.h"
+#include "mach_timer.h"
+
int tsc_disable __initdata = 0;

extern spinlock_t i8253_lock;
@@ -24,6 +27,8 @@

static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */

+static int count2; /* counter for mark_offset_tsc() */
+
/* Cached *multiplier* to convert TSC counts to microseconds.
* (see the equation below).
* Equal to 2^32 * (1 / (clocks per usec) ).
@@ -64,7 +69,7 @@
{
int count;
int countmp;
- static int count1=0, count2=LATCH;
+ static int count1 = 0;
/*
* It is important that these two operations happen almost at
* the same time. We do the RDTSC stuff first, since it's
@@ -82,10 +87,10 @@
rdtscl(last_tsc_low);

spin_lock(&i8253_lock);
- outb_p(0x00, 0x43); /* latch the count ASAP */
+ outb_p(0x00, PIT_MODE); /* latch the count ASAP */

- count = inb_p(0x40); /* read the latched count */
- count |= inb(0x40) << 8;
+ count = inb_p(PIT_CH0); /* read the latched count */
+ count |= inb(PIT_CH0) << 8;
spin_unlock(&i8253_lock);

if (pit_latch_buggy) {
@@ -127,26 +132,11 @@
* device.
*/

-#define CALIBRATE_LATCH (5 * LATCH)
#define CALIBRATE_TIME (5 * 1000020/HZ)

unsigned long __init calibrate_tsc(void)
{
- /* Set the Gate high, disable speaker */
- outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
- /*
- * Now let's take care of CTC channel 2
- *
- * Set the Gate high, program CTC channel 2 for mode 0,
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB) to begin countdown.
- *
- * Some devices need a delay here.
- */
- outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
- outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
- outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+ mach_prepare_counter();

{
unsigned long startlow, starthigh;
@@ -154,10 +144,7 @@
unsigned long count;

rdtsc(startlow,starthigh);
- count = 0;
- do {
- count++;
- } while ((inb(0x61) & 0x20) == 0);
+ mach_countup(&count);
rdtsc(endlow,endhigh);

last_tsc_low = endlow;
@@ -273,6 +260,8 @@
cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
#endif

+ count2 = LATCH; /* initialize counter for mark_offset_tsc() */
+
if (cpu_has_tsc) {
unsigned long tsc_quotient = calibrate_tsc();
if (tsc_quotient) {
diff -Nru linux/include/asm-i386/mach-default/mach_timer.h linux98/include/asm-i386/mach-default/mach_timer.h
--- linux/include/asm-i386/mach-default/mach_timer.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-default/mach_timer.h 2003-03-04 15:39:44.000000000 +0900
@@ -0,0 +1,46 @@
+/*
+ * include/asm-i386/mach-default/mach_timer.h
+ *
+ * Machine specific calibrate_tsc() for generic.
+ * Split out from timer_tsc.c by Osamu Tomita <[email protected]>
+ */
+/* ------ Calibrate the TSC -------
+ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+#ifndef _MACH_TIMER_H
+#define _MACH_TIMER_H
+
+#define CALIBRATE_LATCH (5 * LATCH)
+
+static inline void mach_prepare_counter(void)
+{
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+ * Now let's take care of CTC channel 2
+ *
+ * Set the Gate high, program CTC channel 2 for mode 0,
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+ *
+ * Some devices need a delay here.
+ */
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
+ outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+}
+
+static inline void mach_countup(unsigned long *count)
+{
+ do {
+ *count++;
+ } while ((inb(0x61) & 0x20) == 0);
+}
+
+#endif /* !_MACH_TIMER_H */
diff -Nru linux-2.5.64/include/asm-i386/mach-pc9800/do_timer.h linux98-2.5.64/include/asm-i386/mach-pc9800/do_timer.h
--- linux-2.5.64/include/asm-i386/mach-pc9800/do_timer.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98-2.5.64/include/asm-i386/mach-pc9800/do_timer.h 2003-03-05 13:37:30.000000000 +0900
@@ -0,0 +1,82 @@
+/* defines for inline arch setup functions */
+
+#include <asm/apic.h>
+
+/**
+ * do_timer_interrupt_hook - hook into timer tick
+ * @regs: standard registers from interrupt
+ *
+ * Description:
+ * This hook is called immediately after the timer interrupt is ack'd.
+ * It's primary purpose is to allow architectures that don't possess
+ * individual per CPU clocks (like the CPU APICs supply) to broadcast the
+ * timer interrupt as a means of triggering reschedules etc.
+ **/
+
+static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+{
+ do_timer(regs);
+/*
+ * In the SMP case we use the local APIC timer interrupt to do the
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
+ */
+#ifndef CONFIG_X86_LOCAL_APIC
+ x86_do_profile(regs);
+#else
+ if (!using_apic_timer)
+ smp_local_timer_interrupt(regs);
+#endif
+}
+
+
+/* you can safely undefine this if you don't have the Neptune chipset */
+
+#define BUGGY_NEPTUN_TIMER
+
+/**
+ * do_timer_overflow - process a detected timer overflow condition
+ * @count: hardware timer interrupt count on overflow
+ *
+ * Description:
+ * This call is invoked when the jiffies count has not incremented but
+ * the hardware timer interrupt has. It means that a timer tick interrupt
+ * came along while the previous one was pending, thus a tick was missed
+ **/
+static inline int do_timer_overflow(int count)
+{
+ int i;
+
+ spin_lock(&i8259A_lock);
+ /*
+ * This is tricky when I/O APICs are used;
+ * see do_timer_interrupt().
+ */
+ i = inb(0x00);
+ spin_unlock(&i8259A_lock);
+
+ /* assumption about timer being IRQ0 */
+ if (i & 0x01) {
+ /*
+ * We cannot detect lost timer interrupts ...
+ * well, that's why we call them lost, don't we? :)
+ * [hmm, on the Pentium and Alpha we can ... sort of]
+ */
+ count -= LATCH;
+ } else {
+#ifdef BUGGY_NEPTUN_TIMER
+ /*
+ * for the Neptun bug we know that the 'latch'
+ * command doesn't latch the high and low value
+ * of the counter atomically. Thus we have to
+ * substract 256 from the counter
+ * ... funny, isnt it? :)
+ */
+
+ count -= 256;
+#else
+ printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+#endif
+ }
+ return count;
+}
diff -Nru linux/include/asm-i386/mach-pc9800/mach_timer.h linux98/include/asm-i386/mach-pc9800/mach_timer.h
--- linux/include/asm-i386/mach-pc9800/mach_timer.h 1970-01-01 09:00:00.000000000 +0900
+++ linux98/include/asm-i386/mach-pc9800/mach_timer.h 2003-03-04 15:43:29.000000000 +0900
@@ -0,0 +1,31 @@
+/*
+ * include/asm-i386/mach-pc9800/mach_timer.h
+ *
+ * Machine specific calibrate_tsc() for PC-9800.
+ * Written by Osamu Tomita <[email protected]>
+ */
+/* ------ Calibrate the TSC -------
+ * PC-9800:
+ * CTC cannot be used because some models (especially
+ * note-machines) may disable clock to speaker channel (#1)
+ * unless speaker is enabled. We use ARTIC instead.
+ */
+#ifndef _MACH_TIMER_H
+#define _MACH_TIMER_H
+
+#define CALIBRATE_LATCH (5 * 307200/HZ) /* 0.050sec * 307200Hz = 15360 */
+
+static inline void mach_prepare_counter(void)
+{
+ /* ARTIC can't be stopped nor reset. So we wait roundup. */
+ while (inw(0x5c));
+}
+
+static inline void mach_countup(unsigned long *count)
+{
+ do {
+ *count = inw(0x5c);
+ } while (*count < CALIBRATE_LATCH);
+}
+
+#endif /* !_MACH_TIMER_H */
diff -Nru linux/include/asm-i386/timex.h linux98/include/asm-i386/timex.h
--- linux/include/asm-i386/timex.h 2002-02-14 18:09:15.000000000 +0900
+++ linux98/include/asm-i386/timex.h 2002-02-14 23:58:57.000000000 +0900
@@ -9,11 +9,15 @@
#include <linux/config.h>
#include <asm/msr.h>

+#ifdef CONFIG_X86_PC9800
+ extern int CLOCK_TICK_RATE;
+#else
#ifdef CONFIG_MELAN
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
#else
# define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
#endif
+#endif

#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
diff -Nru linux-2.5.63/kernel/timer.c linux98-2.5.63/kernel/timer.c
--- linux-2.5.63/kernel/timer.c 2003-02-25 04:05:41.000000000 +0900
+++ linux98-2.5.63/kernel/timer.c 2003-03-04 15:13:37.000000000 +0900
@@ -437,8 +437,13 @@
/*
* Timekeeping variables
*/
+#ifdef CONFIG_X86_PC9800
+unsigned long tick_usec; /* ACTHZ period (usec) */
+unsigned long tick_nsec; /* USER_HZ period (nsec) */
+#else
unsigned long tick_usec = TICK_USEC; /* ACTHZ period (usec) */
unsigned long tick_nsec = TICK_NSEC(TICK_USEC); /* USER_HZ period (nsec) */
+#endif

/* The current time */
struct timespec xtime __attribute__ ((aligned (16)));

2003-03-09 07:54:38

by Paul Gortmaker

[permalink] [raw]
Subject: Re: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (11/20) NIC

Osamu Tomita wrote:
>
> This is the patch to support NEC PC-9800 subarchitecture
> against 2.5.64-ac3. (11/20)
>
> C-bus(PC98's legacy bus like ISA) network cards support.
> Change IO port and IRQ assign.
> Add auto detect function for some cards.
> PCI netwwork card works fine without patch.

I had a quick look at the ne.c part of this patch, and I can't
say I'm really thrilled to see some 30 or more ifdefs added to
just one driver. Okay, I know it is an old crusty ISA driver, but
when somebody has to go in there to repair the inevitable bitrot,
the readability factor is significantly reduced.

If the hardware differences can't be abstracted out any cleaner
than this, then it probably makes sense to just make a ne2k-pc98.c
and you can scrap all the bits you don't want. Code sharing is
fine, but no point bending over backwards in trying to do so.
(e.g. we already have MCA and PCMCIA versions of ne.c now...)

Thanks,
Paul.

2003-03-09 08:57:50

by Osamu Tomita

[permalink] [raw]
Subject: Re: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (11/20) NIC

Thanks for the comment.

Paul Gortmaker wrote:
>
> Osamu Tomita wrote:
> >
> > This is the patch to support NEC PC-9800 subarchitecture
> > against 2.5.64-ac3. (11/20)
> >
> > C-bus(PC98's legacy bus like ISA) network cards support.
> > Change IO port and IRQ assign.
> > Add auto detect function for some cards.
> > PCI netwwork card works fine without patch.
>
> I had a quick look at the ne.c part of this patch, and I can't
> say I'm really thrilled to see some 30 or more ifdefs added to
> just one driver. Okay, I know it is an old crusty ISA driver, but
> when somebody has to go in there to repair the inevitable bitrot,
> the readability factor is significantly reduced.
I see.
> If the hardware differences can't be abstracted out any cleaner
> than this, then it probably makes sense to just make a ne2k-pc98.c
> and you can scrap all the bits you don't want. Code sharing is
> fine, but no point bending over backwards in trying to do so.
> (e.g. we already have MCA and PCMCIA versions of ne.c now...)
I'll try to write separated driver for PC98. And post later.

Regards,
Osamu Tomita

2003-03-12 11:38:44

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (16/20) SCSI

On Sun, 9 Mar 2003, Osamu Tomita wrote:
> This is the patch to support NEC PC-9800 subarchitecture
> against 2.5.64-ac3. (16/20)
>
> SCSI host adapter support.
> - BIOS parameter change for PC98.
> - Add pc980155 driver for old PC98.
> - wd33c93.h register address size to int, because PC-9801-55 mapped 0xcc0.
>
> Regards,
> Osamu Tomita
>
> diff -Nru linux/drivers/scsi/wd33c93.h linux98/drivers/scsi/wd33c93.h
> --- linux/drivers/scsi/wd33c93.h 2002-10-12 13:21:35.000000000 +0900
> +++ linux98/drivers/scsi/wd33c93.h 2002-10-12 14:18:53.000000000 +0900
> @@ -186,8 +186,13 @@
>
> /* This is what the 3393 chip looks like to us */
> typedef struct {
> +#if defined(CONFIG_SCSI_PC980155) || defined(CONFIG_SCSI_PC980155_MODULE)
> + volatile unsigned int *SASR;
> + volatile unsigned int *SCMD;

Since you want to do ordinary ISA/PCI I/O on SASR and SCMD, I think you want to
get rid of the pointers and put the plain I/O port numbers there:

unsigned long SASR;
unsigned long SCMD;

> +#else
> volatile unsigned char *SASR;
> volatile unsigned char *SCMD;
> +#endif

M68k and MIPS use pointers because they do MMIO.

Then the following can go away:

> +static unsigned int SASR;
> +static unsigned int SCMD;
> +static wd33c93_regs regs = {&SASR, &SCMD};

And you store the I/O ports here:

static wd33c93_regs regs;

> + for (i = 0; i < nr_base_ios; i++) {
> + base_io = base_ios[i];
> + SASR = REG_ADDRST;
> + SCMD = REG_CONTRL;

regs.SASR = REG_ADDRST;
regs.SCMD = REG_CONTRL;

> +static int pc980155_abort(Scsi_Cmnd *cmd)
> +{
> + if (wd33c93_abort(cmd) == SCSI_ABORT_SUCCESS)
> + return SUCCESS;
> +
> + return FAILED;
> +}

The abort handler is generic. Hence it can be moved to wd33c93.c, so the other
wd33c93 drivers (my main interest :-) can use it.

> +static int pc980155_bus_reset(Scsi_Cmnd *cmd)
> +{
> + struct WD33C93_hostdata *hostdata
> + = (struct WD33C93_hostdata *)cmd->device->host->hostdata;
> +
> + pc980155_int_disable(hostdata->regs);
> + pc980155_assert_bus_reset(hostdata->regs);
> + udelay(50);
> + pc980155_negate_bus_reset(hostdata->regs);
> + (void) inb(*hostdata->regs.SASR);
> + (void) read_pc980155(hostdata->regs, WD_SCSI_STATUS);
> + pc980155_int_enable(hostdata->regs);
> + wd33c93_reset(cmd, 0);
> + return SUCCESS;
> +}

Is there a generic (wd33c93) way to do this?

> +static int pc980155_host_reset(Scsi_Cmnd *cmd)
> +{
> + wd33c93_reset(cmd, 0);
> + return SUCCESS;
> +}

The host reset handler is generic, too.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2003-03-21 07:34:02

by Osamu Tomita

[permalink] [raw]
Subject: Re: [PATCH] PC-9800 subarch. support for 2.5.64-ac3 (16/20) SCSI

Aplogize for slow respnse.

Geert Uytterhoeven wrote:
>
> On Sun, 9 Mar 2003, Osamu Tomita wrote:
> > This is the patch to support NEC PC-9800 subarchitecture
> > against 2.5.64-ac3. (16/20)
> >
> > SCSI host adapter support.
> > - BIOS parameter change for PC98.
> > - Add pc980155 driver for old PC98.
> > - wd33c93.h register address size to int, because PC-9801-55 mapped 0xcc0.
[snip]
> > +static int pc980155_abort(Scsi_Cmnd *cmd)
> > +{
> > + if (wd33c93_abort(cmd) == SCSI_ABORT_SUCCESS)
> > + return SUCCESS;
> > +
> > + return FAILED;
> > +}
>
> The abort handler is generic. Hence it can be moved to wd33c93.c, so the other
> wd33c93 drivers (my main interest :-) can use it.
I posted patch to merge into wd33c93.c aginst 2.5.65-ac1.

> > +static int pc980155_bus_reset(Scsi_Cmnd *cmd)
> > +{
> > + struct WD33C93_hostdata *hostdata
> > + = (struct WD33C93_hostdata *)cmd->device->host->hostdata;
> > +
> > + pc980155_int_disable(hostdata->regs);
> > + pc980155_assert_bus_reset(hostdata->regs);
> > + udelay(50);
> > + pc980155_negate_bus_reset(hostdata->regs);
> > + (void) inb(*hostdata->regs.SASR);
> > + (void) read_pc980155(hostdata->regs, WD_SCSI_STATUS);
> > + pc980155_int_enable(hostdata->regs);
> > + wd33c93_reset(cmd, 0);
> > + return SUCCESS;
> > +}
>
> Is there a generic (wd33c93) way to do this?
I'd been looking for better way. But It seems, standard WD33C93 has
no feature for control bus reset line. I think bus reset is board
specific.

> > +static int pc980155_host_reset(Scsi_Cmnd *cmd)
> > +{
> > + wd33c93_reset(cmd, 0);
> > + return SUCCESS;
> > +}
>
> The host reset handler is generic, too.
Patch for PC-98 aginst 2.5.65-ac1 includes this too.

Thanks,
Osamu Tomita