diff -u --recursive --new-file v2.1.124/linux/CREDITS linux/CREDITS --- v2.1.124/linux/CREDITS Mon Oct 5 13:13:34 1998 +++ linux/CREDITS Mon Oct 5 10:04:35 1998 @@ -93,7 +93,7 @@ S: Canada N: Ralf Baechle -E: ralf@gnu.ai.mit.edu +E: ralf@gnu.org P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3 D: Linux/MIPS port D: Linux/68k hacker diff -u --recursive --new-file v2.1.124/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.124/linux/Documentation/Configure.help Mon Oct 5 13:13:35 1998 +++ linux/Documentation/Configure.help Mon Oct 5 13:38:23 1998 @@ -1479,13 +1479,6 @@ display that complies with the generic VGA standard. Virtually everyone wants that. Say Y. -Use 64KB of VGA video RAM (aka: Maximum VGA Scrollback) -CONFIG_VGA_GET_64KB - Use 64K rather than 32K of video RAM. This doesn't actually work - on all "VGA" controllers. If your vga card can do it, then you - can say Y here to get more scrollback buffer (shift-pgup) on VGA - consoles. - Video mode selection support CONFIG_VIDEO_SELECT This enables support for text mode selection on kernel startup. If @@ -1507,20 +1500,26 @@ hardware. It represents the frame buffer of some video hardware and allows application software to access the graphics hardware through a well-defined interface, so the software doesn't need to know - anything about the low-level (hardware register) stuff. This works - across the different architectures supported by Linux and makes the - implementation of application programs easier and more portable; at - this point, an X server exists which uses the frame buffer device - exclusively. + anything about the low-level (hardware register) stuff. + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + The device is accessed through special device nodes, usually located in the /dev directory, i.e. /dev/fb*. - Please read the file Documentation/fb/framebuffer.txt for more - information. - - If you want to play with it, say Y here and to the driver for your - graphics board, below. If unsure, say N. + You need an utility program called fbset to make full use of frame + buffer devices. Please read the file + Documentation/fb/framebuffer.txt for more information. + + If you want to play with it, say Y here and also to the driver for + your graphics board, below. If unsure, say N, unless you are + compiling a kernel for a non-X86 architecture, in which case you + should say Y. Acorn VIDC support CONFIG_FB_ACORN @@ -1559,33 +1558,34 @@ Amiga CyberVision support CONFIG_FB_CYBER - This enables support for the Cybervision 64 graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64 or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the Cybervision 64 3D - card, as they use incompatible video chips. + This enables support for the Cybervision 64 graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64 or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the + Cybervision 64 3D card, as they use incompatible video chips. Amiga CyberVision3D support (EXPERIMENTAL) CONFIG_FB_VIRGE - This enables support for the Cybervision 64/3D graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64/3D or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the older Cybervision 64 - card, as they use incompatible video chips. + This enables support for the Cybervision 64/3D graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64/3D or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the older + Cybervision 64 card, as they use incompatible video chips. Amiga RetinaZ3 support (EXPERIMENTAL) CONFIG_FB_RETINAZ3 - This enables support for the Retina Z3 graphics card. Say N unless you - have a Retina Z3 or plan to get one before you next recompile the kernel. + This enables support for the Retina Z3 graphics card. Say N unless + you have a Retina Z3 or plan to get one before you next recompile + the kernel. Amiga CLgen driver (EXPERIMENTAL) CONFIG_FB_CLGEN - This enables support for Cirrus Logic GD542x/543x based boards on Amiga: - SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. Say N - unless you have such a graphics board or plan to get one before you next - recompile the kernel. + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. Atari native chipset support CONFIG_FB_ATARI @@ -1686,13 +1686,14 @@ Virtual Frame Buffer support (ONLY FOR TESTING!) CONFIG_FB_VIRTUAL - This is a `virtual' frame buffer device. It operates on a chunk of - unswapable kernel memory instead of on the memory of a graphics board. - This means you cannot see any output sent to this frame buffer device, - while it does consume precious memory. The main use of this frame - buffer device is testing and debugging the frame buffer subsystem. Do - NOT enable it for normal systems! To protect the innocent, it has to - be enabled explicitly on boot time using the kernel option `video=vfb:'. + This is a `virtual' frame buffer device. It operates on a chunk of + unswapable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -1709,12 +1710,12 @@ drivers. Note that they are used for text console output only; they are NOT needed for graphical applications. - If you do not enable this option, the needed low level drivers are - automatically enabled, depending on what frame buffer devices you - selected. This is recommended for most users. + If you say N here, the needed low level drivers are automatically + enabled, depending on what frame buffer devices you selected above. + This is recommended for most users. - If you enable this option, you have more fine-grained control over which - low level drivers are enabled. You can e.g. leave out low level drivers + If you say Y here, you have more fine-grained control over which low + level drivers are enabled. You can e.g. leave out low level drivers for color depths you do not intend to use for text consoles. Low level frame buffer console drivers can be modules ( = code which @@ -1788,13 +1789,13 @@ Mac variable bpp packed pixels support CONFIG_FBCON_MAC This is the low level frame buffer console driver for 1/2/4/8/16/32 - bits per pixel packed pixels on Mac. It supports variable fontwidths + bits per pixel packed pixels on Mac. It supports variable font widths for low resolution screens. VGA characters/attributes support CONFIG_FBCON_VGA - This is the low level frame buffer console driver for VGA text mode, as - used by vgafb. + This is the low level frame buffer console driver for VGA text mode; + it is used if you said Y to "VGA chipset support (text only)" above. Parallel-port support CONFIG_PARPORT @@ -8988,15 +8989,6 @@ and CD32. If you intend to run Linux on any of these systems, say Y; otherwise say N. -Amiga Cybervision support -CONFIG_FB_CYBER - This enables support for the Cybervision 64 graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64 or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the Cybervision 64 3D - card at present, as they use incompatible video chips. - Amiga GSP (TMS340x0) support CONFIG_AMIGA_GSP Include support for Amiga graphics cards that use the Texas @@ -9124,6 +9116,11 @@ 1260 accelerator, and the optional SCSI module, say Y. Otherwise, say N. +Blizzard PowerUP 603e+ SCSI support +CONFIG_BLZ603EPLUS_SCSI + If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ + accelerator, say Y. Otherwise, say N. + Fastlane SCSI support CONFIG_FASTLANE_SCSI If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use @@ -9165,6 +9162,16 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called ariadne.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Ariadne II support +CONFIG_ARIADNE2 + If you have a VillageTronics Ariadne II Ethernet adapter, say Y. + Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called ariadne2.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. A2065 support diff -u --recursive --new-file v2.1.124/linux/Documentation/fb/internals.txt linux/Documentation/fb/internals.txt --- v2.1.124/linux/Documentation/fb/internals.txt Wed Jun 24 22:54:01 1998 +++ linux/Documentation/fb/internals.txt Mon Oct 5 13:39:20 1998 @@ -2,7 +2,7 @@ This is a first start for some documentation about frame buffer device internals. -Geert Uytterhoeven , 10 June 1998 +Geert Uytterhoeven , 21 July 1998 -------------------------------------------------------------------------------- @@ -68,14 +68,13 @@ True color (FB_VISUAL_TRUECOLOR) -------------------------------- -The pixel value is broken up into red, green, and blue fields, each of which -are looked up in separate red, green, and blue lookup tables. +The pixel value is broken up into red, green, and blue fields. Direct color (FB_VISUAL_DIRECTCOLOR) ------------------------------------ -The pixel value is broken up into red, green, and blue fields. This is what -most people mean when then say `true color'. +The pixel value is broken up into red, green, and blue fields, each of which +are looked up in separate red, green, and blue lookup tables. Grayscale displays diff -u --recursive --new-file v2.1.124/linux/Documentation/fb/vesafb.txt linux/Documentation/fb/vesafb.txt --- v2.1.124/linux/Documentation/fb/vesafb.txt Mon Oct 5 13:13:35 1998 +++ linux/Documentation/fb/vesafb.txt Mon Oct 5 13:39:20 1998 @@ -79,20 +79,17 @@ by comma. Accepted options: invers - no comment... - -redraw - scroll by redrawing the affected part of the screen. - This is the default. +redraw - scroll by redrawing the affected part of the screen ypan - enable display panning using the VESA protected mode interface. This enables the Shift-PgUp scrollback thing and greatly speeds up fullscreen scrolling. It is slower than "redraw" when scrolling only a halve - screen. Seems not to work with some BIOSes. + screen. This is the default. ywrap - If your gfx board supports wrap-around, use this one instead of ypan. - -vgapal - Use the standard vga registers for palette changes. - This is the default. -pmipal - Use the protected mode interface for palette changes. +nopal - Don't use the protected mode interface for palette + changes. vesafb will try the standard vga registers + instead. Have fun! diff -u --recursive --new-file v2.1.124/linux/Documentation/i386/zero-page.txt linux/Documentation/i386/zero-page.txt --- v2.1.124/linux/Documentation/i386/zero-page.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/i386/zero-page.txt Mon Oct 5 12:59:25 1998 @@ -0,0 +1,73 @@ +Summary of empty_zero_page layout (kernel point of view) + ( collected by Hans Lermen and Martin Mares ) + +The contents of empty_zero_page are used to pass parameters from the +16-bit realmode code of the kernel to the 32-bit part. References/settings +to it mainly are in: + + arch/i386/boot/setup.S + arch/i386/boot/video.S + arch/i386/kernel/head.S + arch/i386/kernel/setup.c + + +Offset Type Description +------ ---- ----------- + 0 32 bytes struct screen_info, SCREEN_INFO + ATTENTION, overlaps the following !!! + 2 unsigned short EXT_MEM_K, extended memory size in Kb (from int 0x15) + 0x20 unsigned short CL_MAGIC, commandline magic number (=0xA33F) + 0x22 unsigned short CL_OFFSET, commandline offset + Address of commandline is calculated: + 0x90000 + contents of CL_OFFSET + (only taken, when CL_MAGIC = 0xA33F) + 0x40 20 bytes struct apm_bios_info, APM_BIOS_INFO + 0x80 16 bytes hd0-disk-parameter from intvector 0x41 + 0x90 16 bytes hd1-disk-parameter from intvector 0x46 + + 0xa0 16 bytes System description table truncated to 16 bytes. + ( struct sys_desc_table_struct ) + 0xb0 - 0x1df Free. Add more parameters here if you really need them. + +0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb +0x1f1 char size of setup.S, number of sectors +0x1f2 unsigned short MOUNT_ROOT_RDONLY (if !=0) +0x1f4 unsigned short size of compressed kernel-part in the + (b)zImage-file (in 16 byte units, rounded up) +0x1f6 unsigned short swap_dev (unused AFAIK) +0x1f8 unsigned short RAMDISK_FLAGS +0x1fa unsigned short VGA-Mode (old one) +0x1fc unsigned short ORIG_ROOT_DEV (high=Major, low=minor) +0x1ff char AUX_DEVICE_INFO + +0x200 short jump to start of setup code aka "reserved" field. +0x202 4 bytes Signature for SETUP-header, ="HdrS" +0x206 unsigned short Version number of header format + Current version is 0x0201... +0x208 8 bytes (used by setup.S for communication with boot loaders, + look there) +0x210 char LOADER_TYPE, = 0, old one + else it is set by the loader: + 0xTV: T=0 for LILO + 1 for Loadlin + 2 for bootsect-loader + 3 for SYSLINUX + 4 for ETHERBOOT + V = version +0x211 char loadflags: + bit0 = 1: kernel is loaded high (bzImage) + bit7 = 1: Heap and pointer (see below) set by boot + loader. +0x212 unsigned short (setup.S) +0x214 unsigned long KERNEL_START, where the loader started the kernel +0x218 unsigned long INITRD_START, address of loaded ramdisk image +0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image +0x220 4 bytes (setup.S) +0x224 unsigned short setup.S heap end pointer +0x226 - 0x7ff setup.S code. + +0x800 string, 2K max COMMAND_LINE, the kernel commandline as + copied using CL_OFFSET. + Note: this will be copied once more by setup.c + into a local buffer which is only 256 bytes long. + ( #define COMMAND_LINE_SIZE 256 ) diff -u --recursive --new-file v2.1.124/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.124/linux/MAINTAINERS Mon Sep 28 10:51:32 1998 +++ linux/MAINTAINERS Mon Oct 5 13:38:23 1998 @@ -384,6 +384,12 @@ L: linux-mac68k@wave.lm.com S: As time permits [Michael confess, you are the mac68k maintainer 8)] +M68K ON HP9000/300 +P: Philip Blundell +M: philb@gnu.org +W: http://www.tazenda.demon.co.uk/phil/linux-hp +S: Maintained + MENUCONFIG: P: Michael Elizabeth Chastain M: mec@shout.net diff -u --recursive --new-file v2.1.124/linux/Makefile linux/Makefile --- v2.1.124/linux/Makefile Mon Oct 5 13:13:35 1998 +++ linux/Makefile Mon Oct 5 13:13:20 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 124 +SUBLEVEL = 125 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -35,6 +35,7 @@ AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip +OBJDUMP =$(CROSS_COMPILE)objdump MAKE =make GENKSYMS=/sbin/genksyms @@ -155,6 +156,10 @@ DRIVERS := $(DRIVERS) drivers/zorro/zorro.a endif +ifeq ($(CONFIG_FC4),y) +DRIVERS := $(DRIVERS) drivers/fc4/fc4.a +endif + ifdef CONFIG_PPC DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a endif @@ -316,11 +321,10 @@ if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ \ - rm -f /tmp/.misc.$$$$ /tmp/.allmods.$$$$; \ - ls *.o > /tmp/.allmods.$$$$; \ - echo $$MODULES | tr ' ' '\n' | sort | comm -23 /tmp/.allmods.$$$$ - > /tmp/.misc.$$$$; \ - if [ -s /tmp/.misc.$$$$ ]; then inst_mod /tmp/.misc.$$$$ misc; fi; \ - rm -f /tmp/.misc.$$$$ /tmp/.allmods.$$$$; \ + ls *.o > .allmods; \ + echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \ + if [ -s .misc ]; then inst_mod .misc misc; fi; \ + rm -f .misc .allmods; \ ) # modules disabled.... diff -u --recursive --new-file v2.1.124/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.1.124/linux/arch/i386/boot/setup.S Sat Sep 5 16:46:40 1998 +++ linux/arch/i386/boot/setup.S Mon Oct 5 12:59:25 1998 @@ -145,7 +145,7 @@ jne bad_sig jmp good_sig1 -! Routine to print ASCII string at DS:SI +! Routine to print ASCIIz string at DS:SI prtstr: lodsb and al,al @@ -345,7 +345,7 @@ mov ds,ax mov ds,ax xor ax,ax - mov [0x220], ax ! set table length to 0 + mov [0xa0], ax ! set table length to 0 mov ah, #0xc0 stc int 0x15 ! puts feature table at es:bx @@ -357,9 +357,13 @@ sub ax, #DELTA_INITSEG ! aka #INITSEG mov es,ax mov si,bx - mov di,#0x220 + mov di,#0xa0 mov cx,(si) add cx,#2 ! table length is a short + cmp cx,#0x10 + jc sysdesc_ok + mov cx,#0x10 ! we keep only first 16 bytes +sysdesc_ok: rep movsb pop ds diff -u --recursive --new-file v2.1.124/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.1.124/linux/arch/i386/kernel/io_apic.c Mon Oct 5 13:13:35 1998 +++ linux/arch/i386/kernel/io_apic.c Mon Oct 5 17:12:23 1998 @@ -103,8 +103,10 @@ /* * This is performance-critical, we want to do it O(1) + * + * the indexing order of this array favors 1:1 mappings + * between pins and IRQs. */ -static int irq_2_pin[NR_IRQS]; static inline unsigned int io_apic_read(unsigned int reg) { @@ -119,6 +121,15 @@ } /* + * Re-write a value: to be used for read-modify-write + * cycles where the read already set up the index register. + */ +static inline void io_apic_modify(unsigned int value) +{ + *(IO_APIC_BASE+4) = value; +} + +/* * Synchronize the IO-APIC and the CPU by doing * a dummy read from the IO-APIC */ @@ -128,58 +139,68 @@ } /* - * We disable IO-APIC IRQs by setting their 'destination CPU mask' to - * zero. Trick by Ramesh Nalluri. + * Rough estimation of how many shared IRQs there are, can + * be changed anytime. */ -static inline void disable_IO_APIC_irq(unsigned int irq) -{ - int pin = irq_2_pin[irq]; - struct IO_APIC_route_entry entry; +#define MAX_PLUS_SHARED_IRQS NR_IRQS +#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) - if (pin != -1) { - *(((int *)&entry) + 1) = io_apic_read(0x11 + pin * 2); - entry.dest.logical.logical_dest = 0x0; - io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); - io_apic_sync(); - } -} +static struct irq_pin_list { + int pin, next; +} irq_2_pin[PIN_MAP_SIZE]; -static inline void enable_IO_APIC_irq(unsigned int irq) +/* + * The common case is 1:1 IRQ<->pin mappings. Sometimes there are + * shared ISA-space IRQs, so we have to support them. We are super + * fast in the common case, and fast for shared ISA-space IRQs. + */ +static void add_pin_to_irq(unsigned int irq, int pin) { - int pin = irq_2_pin[irq]; - struct IO_APIC_route_entry entry; + static int first_free_entry = NR_IRQS; + struct irq_pin_list *entry = irq_2_pin + irq; - if (pin != -1) { - *(((int *)&entry) + 1) = io_apic_read(0x11 + pin * 2); - entry.dest.logical.logical_dest = 0xff; - io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); - } -} - -static inline void mask_IO_APIC_irq(unsigned int irq) -{ - int pin = irq_2_pin[irq]; - struct IO_APIC_route_entry entry; + while (entry->next) + entry = irq_2_pin + entry->next; - if (pin != -1) { - *(((int *)&entry) + 0) = io_apic_read(0x10 + pin * 2); - entry.mask = 1; - io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0)); - io_apic_sync(); - } + if (entry->pin != -1) { + entry->next = first_free_entry; + entry = irq_2_pin + entry->next; + if (++first_free_entry >= PIN_MAP_SIZE) + panic("io_apic.c: whoops"); + } + entry->pin = pin; +} + +#define DO_ACTION(name,R,ACTION, FINAL) \ + \ +static void name##_IO_APIC_irq(unsigned int irq) \ +{ \ + int pin; \ + struct irq_pin_list *entry = irq_2_pin + irq; \ + \ + for (;;) { \ + unsigned int reg; \ + pin = entry->pin; \ + if (pin == -1) \ + break; \ + reg = io_apic_read(0x10 + R + pin*2); \ + reg ACTION; \ + io_apic_modify(reg); \ + if (!entry->next) \ + break; \ + entry = irq_2_pin + entry->next; \ + } \ + FINAL; \ } -static inline void unmask_IO_APIC_irq(unsigned int irq) -{ - int pin = irq_2_pin[irq]; - struct IO_APIC_route_entry entry; - - if (pin != -1) { - *(((int *)&entry) + 0) = io_apic_read(0x10 + pin * 2); - entry.mask = 0; - io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0)); - } -} +/* + * We disable IO-APIC IRQs by setting their 'destination CPU mask' to + * zero. Trick by Ramesh Nalluri. + */ +DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync()) /* destination = 0x00 */ +DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */ +DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */ +DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ static void __init clear_IO_APIC_pin(unsigned int pin) { @@ -577,7 +598,7 @@ } irq = pin_2_irq(idx,pin); - irq_2_pin[irq] = pin; + add_pin_to_irq(irq, pin); if (!IO_APIC_IRQ(irq)) continue; @@ -703,8 +724,8 @@ } printk("IRQ to pin mappings:\n"); - for (i = 0; i < NR_IRQS; i++) - printk("%d->%d ", i, irq_2_pin[i]); + for (i = 0; i < PIN_MAP_SIZE; i++) + printk("%d->%d(%d) ", i, irq_2_pin[i].pin, irq_2_pin[i].next); printk("\n"); printk(".................................... done.\n"); @@ -716,8 +737,10 @@ { int i, pin; - for (i = 0; i < NR_IRQS; i++) - irq_2_pin[i] = -1; + for (i = 0; i < PIN_MAP_SIZE; i++) { + irq_2_pin[i].pin = -1; + irq_2_pin[i].next = 0; + } if (!pirqs_enabled) for (i = 0; i < MAX_PIRQS; i++) pirq_entries[i] =- 1; diff -u --recursive --new-file v2.1.124/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.124/linux/arch/i386/kernel/setup.c Thu Sep 17 17:53:34 1998 +++ linux/arch/i386/kernel/setup.c Mon Oct 5 12:59:26 1998 @@ -86,13 +86,12 @@ * This is set up by the setup-routine at boot-time */ #define PARAM ((unsigned char *)empty_zero_page) +#define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) #define EXT_MEM_K (*(unsigned short *) (PARAM+2)) #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0)) -#ifdef CONFIG_APM -#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64)) -#endif +#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40)) #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) -#define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) +#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0)) #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2)) #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8)) #define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC)) @@ -101,7 +100,6 @@ #define KERNEL_START (*(unsigned long *) (PARAM+0x214)) #define INITRD_START (*(unsigned long *) (PARAM+0x218)) #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) -#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0x220)) #define COMMAND_LINE ((char *) (PARAM+2048)) #define COMMAND_LINE_SIZE 256 diff -u --recursive --new-file v2.1.124/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.124/linux/arch/i386/kernel/smp.c Mon Oct 5 13:13:35 1998 +++ linux/arch/i386/kernel/smp.c Mon Oct 5 13:19:44 1998 @@ -736,7 +736,6 @@ /* Must be done before calibration delay is computed */ mtrr_init_secondary_cpu (); #endif - stts(); smp_callin(); while (!smp_commenced) barrier(); @@ -753,6 +752,13 @@ struct thread_struct * p = ¤t->tss; /* + * Load up the LDT and the task register. + */ + asm volatile("lldt %%ax": :"a" (p->ldt)); + asm volatile("ltr %%ax": :"a" (p->tr)); + stts(); + + /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. * @@ -760,8 +766,7 @@ * to release it as part of the "reschedule" return. */ spin_lock(&scheduler_lock); - asm volatile("lldt %%ax": :"a" (p->ldt)); - asm volatile("ltr %%ax": :"a" (p->tr)); + asm volatile( "movl %0,%%esp\n\t" "jmp *%1" diff -u --recursive --new-file v2.1.124/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.1.124/linux/arch/m68k/amiga/amiints.c Mon Aug 3 12:45:44 1998 +++ linux/arch/m68k/amiga/amiints.c Mon Oct 5 13:54:39 1998 @@ -288,12 +288,14 @@ } if (irq >= IRQ_AMIGA_CIAB) { + cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); cia_able_irq(&ciab_base, CIA_ICR_SETCLR | (1 << (irq - IRQ_AMIGA_CIAB))); return; } if (irq >= IRQ_AMIGA_CIAA) { + cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | (1 << (irq - IRQ_AMIGA_CIAA))); return; diff -u --recursive --new-file v2.1.124/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.1.124/linux/arch/m68k/amiga/config.c Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/amiga/config.c Mon Oct 5 13:54:39 1998 @@ -398,6 +398,28 @@ /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + /* don't use Z2 RAM as system memory on Z3 capable machines */ + if (AMIGAHW_PRESENT(ZORRO3)) { + int i, j; + u32 disabled_z2mem = 0; + for (i = 0; i < m68k_num_memory; i++) + if (m68k_memory[i].addr < 16*1024*1024) { + if (i == 0) { + /* don't cut off the branch we're sitting on */ + printk("Warning: kernel runs in Zorro II memory\n"); + continue; + } + disabled_z2mem += m68k_memory[i].size; + m68k_num_memory--; + for (j = i; j < m68k_num_memory; j++) + m68k_memory[j] = m68k_memory[j+1]; + i--; + } + if (disabled_z2mem) + printk("%dK of Zorro II memory will not be used as system memory\n", + disabled_z2mem>>10); + } + /* initialize chipram allocator */ amiga_chip_init (); diff -u --recursive --new-file v2.1.124/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v2.1.124/linux/arch/m68k/atari/ataints.c Tue Jun 23 10:01:20 1998 +++ linux/arch/m68k/atari/ataints.c Mon Oct 5 13:54:39 1998 @@ -419,6 +419,7 @@ unsigned long flags, const char *devname, void *dev_id) { int vector; + unsigned long oflags = flags; /* * The following is a hack to make some PCI card drivers work, @@ -427,9 +428,14 @@ flags &= ~SA_SHIRQ; + if (flags == SA_INTERRUPT) { + printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n", + __FUNCTION__, devname); + flags = IRQ_TYPE_SLOW; + } if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { - printk ("%s: Bad irq type %ld requested from %s\n", - __FUNCTION__, flags, devname); + printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n", + __FUNCTION__, flags, oflags, devname); return -EINVAL; } if (!IS_VALID_INTNO(irq)) { diff -u --recursive --new-file v2.1.124/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v2.1.124/linux/arch/m68k/atari/stram.c Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/atari/stram.c Mon Oct 5 13:54:39 1998 @@ -273,7 +273,7 @@ /* determine whether kernel code resides in ST-RAM (then ST-RAM is the * first memory block at virtual 0x0) */ - stram_start = phys_to_virt( 0 ); + stram_start = (unsigned long)phys_to_virt(0); kernel_in_stram = (stram_start == 0); for( i = 0; i < m68k_num_memory; ++i ) { @@ -1465,9 +1465,10 @@ for( p = alloc_list; p; p = p->next ) { if (len + 50 >= PAGE_SIZE) break; - PRINT_PROC( "0x%08lx-0x%08lx: %s (", - virt_to_phys(p->start), - virt_to_phys(p->start+p->size-1), p->owner ); + PRINT_PROC("0x%08lx-0x%08lx: %s (", + virt_to_phys((void *)p->start), + virt_to_phys((void *)p->start+p->size-1), + p->owner); if (p->flags & BLOCK_STATIC) PRINT_PROC( "static)\n" ); else if (p->flags & BLOCK_GFP) diff -u --recursive --new-file v2.1.124/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.1.124/linux/arch/m68k/config.in Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/config.in Mon Oct 5 13:54:39 1998 @@ -32,6 +32,7 @@ bool 'Macintosh support' CONFIG_MAC if [ "$CONFIG_MAC" = "y" ]; then define_bool CONFIG_NUBUS y + define_bool CONFIG_M68K_L2_CACHE y fi bool 'Apollo support' CONFIG_APOLLO bool 'VME (Motorola and BVM) support' CONFIG_VME @@ -155,6 +156,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'A4091 SCSI support' CONFIG_A4091_SCSI bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI + bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI # bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI fi @@ -171,6 +173,7 @@ fi if [ "$CONFIG_MAC" = "y" ]; then bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI + bool 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI @@ -211,6 +214,7 @@ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_ZORRO" = "y" ]; then tristate 'Ariadne support' CONFIG_ARIADNE + tristate 'Ariadne II support' CONFIG_ARIADNE2 tristate 'A2065 support' CONFIG_A2065 tristate 'Hydra support' CONFIG_HYDRA fi @@ -222,6 +226,8 @@ fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT + bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE + bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET diff -u --recursive --new-file v2.1.124/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.1.124/linux/arch/m68k/kernel/entry.S Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/kernel/entry.S Mon Oct 5 13:54:39 1998 @@ -396,7 +396,7 @@ .data ALIGN SYMBOL_NAME_LABEL(sys_call_table) - .long SYMBOL_NAME(sys_setup) /* 0 */ + .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork) .long SYMBOL_NAME(sys_read) diff -u --recursive --new-file v2.1.124/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.124/linux/arch/m68k/kernel/m68k_ksyms.c Tue Aug 18 22:02:03 1998 +++ linux/arch/m68k/kernel/m68k_ksyms.c Mon Oct 5 13:54:39 1998 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -30,9 +31,13 @@ EXPORT_SYMBOL(m68k_is040or060); EXPORT_SYMBOL(cache_push); EXPORT_SYMBOL(cache_clear); +#ifndef CONFIG_SINGLE_MEMORY_CHUNK EXPORT_SYMBOL(mm_vtop); EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); +#endif +EXPORT_SYMBOL(mm_vtop_fallback); +EXPORT_SYMBOL(m68k_memory); EXPORT_SYMBOL(kernel_map); EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); @@ -44,6 +49,7 @@ EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(checksignals); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); diff -u --recursive --new-file v2.1.124/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.1.124/linux/arch/m68k/kernel/signal.c Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/kernel/signal.c Mon Oct 5 13:54:39 1998 @@ -65,6 +65,17 @@ -1, /* sizeof(((struct frame *)0)->un.fmtf), */ }; +void checksignals(void) +{ + sigset_t *blocked = ¤t->blocked; + unsigned long mask = blocked->sig[0] | sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT); + mask &= blocked->sig[1]; + if (~mask) { + printk("Bad signal mask\n"); + *(int *) 0 = 0; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -u --recursive --new-file v2.1.124/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v2.1.124/linux/arch/m68k/kernel/traps.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/kernel/traps.c Mon Oct 5 13:54:39 1998 @@ -452,7 +452,7 @@ #endif errorcode = (mmusr & MMU_I) ? 0 : 1; - if (!(ssw & RW) || ssw & RM) + if (!(ssw & RW) || (ssw & RM)) errorcode |= 2; if (mmusr & (MMU_I | MMU_WP)) { diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.1.124/linux/arch/m68k/mac/adb-bus.c Wed Aug 26 11:37:33 1998 +++ linux/arch/m68k/mac/adb-bus.c Mon Oct 5 13:54:39 1998 @@ -245,13 +245,16 @@ via_write(via1, vIFR, SR_INT); /* get those pesky clock ticks we missed while booting */ - for ( i = 0; i < 30; i++) { + for ( i = 0; i < 60; i++) { udelay(ADB_DELAY); adb_hw_setup_IIsi(); udelay(ADB_DELAY); if (via_read(via1, vBufB) & TREQ) break; } + if (i == 60) + printk("adb_IIsi: maybe bus jammed ??\n"); + /* * Ok we probably ;) have a ready to use adb bus. Its also */ diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.1.124/linux/arch/m68k/mac/config.c Tue Aug 18 22:02:03 1998 +++ linux/arch/m68k/mac/config.c Mon Oct 5 13:54:39 1998 @@ -83,9 +83,9 @@ /* Mac specific timer functions */ extern unsigned long mac_gettimeoffset (void); -extern void mac_gettod (int *, int *, int *, int *, int *, int *); -extern int mac_hwclk (int, struct hwclk_time *); -extern int mac_set_clock_mmss (unsigned long); +static void mac_gettod (int *, int *, int *, int *, int *, int *); +static int mac_hwclk (int, struct hwclk_time *); +static int mac_set_clock_mmss (unsigned long); extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); extern void (*kd_mksound)(unsigned int, unsigned int); @@ -123,7 +123,7 @@ mac_reset(); } -void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) +static void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) { via_init_clock(vector); } @@ -135,7 +135,7 @@ * the system time. */ -void mac_gettod (int *yearp, int *monp, int *dayp, +static void mac_gettod (int *yearp, int *monp, int *dayp, int *hourp, int *minp, int *secp) { unsigned long time; @@ -192,7 +192,7 @@ * TBI: read and write hwclock */ -int mac_hwclk( int op, struct hwclk_time *t ) +static int mac_hwclk( int op, struct hwclk_time *t ) { return 0; } @@ -201,7 +201,7 @@ * TBI: set minutes/seconds in hwclock */ -int mac_set_clock_mmss (unsigned long nowtime) +static int mac_set_clock_mmss (unsigned long nowtime) { short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; @@ -280,10 +280,26 @@ return(unknown); } +/* + * Flip into 24bit mode for an instant - flushes the L2 cache card. We + * have to disable interrupts for this. Our IRQ handlers will crap + * themselves if they take an IRQ in 24bit mode! + */ + +static void mac_cache_card_flush(int writeback) +{ + unsigned long flags; + save_flags(flags); + cli(); + via_write(via2, vBufB, via_read(via2,vBufB)&~VIA2B_vMode32); + via_write(via2, vBufB, via_read(via2,vBufB)|VIA2B_vMode32); + restore_flags(flags); +} + __initfunc(void config_mac(void)) { - if (MACH_IS_ATARI || MACH_IS_AMIGA) { + if (!MACH_IS_MAC) { printk("ERROR: no Mac, but config_mac() called!! \n"); } @@ -338,7 +354,17 @@ mac_identify(); mac_report_hardware(); - + + if( + /* Cache cards */ + macintosh_config->ident == MAC_MODEL_IICI|| + macintosh_config->ident == MAC_MODEL_IISI|| + macintosh_config->ident == MAC_MODEL_IICX|| + /* On board L2 cache */ + macintosh_config->ident == MAC_MODEL_IIFX) + { + mach_l2_flush = mac_cache_card_flush; + } /* goes on forever if timers broken */ #ifdef MAC_DEBUG_SOUND mac_mksound(1000,10); @@ -349,7 +375,6 @@ */ nubus_sweep_video(); - } @@ -411,23 +436,23 @@ { MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, /* - * Quadra (only 68030 ones will actually work!). Not much odd. Video is at - * 0xF9000000, via is like a MacII. We label it differently as some of the - * stuff connected to VIA2 seems different. Better SCSI chip and ???? onboard ethernet - * in all cases using a NatSemi SONIC. The 700, 900 and 950 have some I/O chips in the wrong - * place to confuse us. The 840AV seems to have a scsi location of its own + * Quadra. Video is at 0xF9000000, via is like a MacII. We label it differently + * as some of the stuff connected to VIA2 seems different. Better SCSI chip and + * onboard ethernet using a NatSemi SONIC except the 660AV and 840AV which use an + * AMD 79C940 (MACE). + * The 700, 900 and 950 have some I/O chips in the wrong place to + * confuse us. The 840AV has a SCSI location of its own (same as + * the 660AV). */ - - { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + + { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* The Q700 does have a NS Sonic */ - { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - /* Does the 840AV have ethernet ??? documents seem to indicate its not quite a - Quadra in this respect ? */ - { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS}, /* These might have IOP problems */ { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, @@ -440,7 +465,7 @@ { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, @@ -452,8 +477,8 @@ * Centris - just guessing again; maybe like Quadra */ - { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* @@ -467,10 +492,10 @@ { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* @@ -535,8 +560,8 @@ printk (" Penguin bootinfo data:\n"); printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", mac_bi_data.videoaddr, mac_bi_data.videorow, - mac_bi_data.videodepth, (int) (mac_bi_data.dimensions & 0xFFFF), - (int) (mac_bi_data.dimensions >> 16)); + mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, + mac_bi_data.dimensions >> 16); printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", mac_bi_data.videological, mac_orig_videoaddr, mac_bi_data.sccbase); @@ -576,8 +601,7 @@ break; } - - + via_configure_base(); } void mac_report_hardware(void) @@ -589,6 +613,8 @@ { strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); + if(mach_l2_flush && !(via_read(via2, vBufB)&VIA2B_vCDis)) + strcat(str, "(+L2 cache)"); } /* diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c --- v2.1.124/linux/arch/m68k/mac/debug.c Tue Jun 23 10:01:21 1998 +++ linux/arch/m68k/mac/debug.c Mon Oct 5 13:54:39 1998 @@ -249,7 +249,6 @@ * TODO: serial debug code */ -#define SCC_BAS (0x50F04000) struct SCC { u_char cha_b_ctrl; @@ -260,7 +259,8 @@ u_char char_dummy3; u_char cha_a_data; }; -# define scc ((*(volatile struct SCC*)SCC_BAS)) + +# define scc (*((volatile struct SCC*)mac_bi_data.sccbase)) /* Flag that serial port is already initialized and used */ int mac_SCC_init_done = 0; @@ -268,6 +268,8 @@ * not be repeated; used by kgdb */ int mac_SCC_reset_done = 0; +static int scc_port = -1; + static struct console mac_console_driver = { "debug", NULL, /* write */ @@ -282,20 +284,18 @@ NULL }; -static int scc_port; - /* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/ -#define US 1 +#define uSEC 1 static inline void mac_sccb_out (char c) { int i; do { - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); scc.cha_b_data = c; } @@ -304,10 +304,10 @@ { int i; do { - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); scc.cha_a_data = c; } @@ -337,10 +337,10 @@ { int i; do { - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); return( scc.cha_b_data ); } @@ -349,10 +349,10 @@ { int i; do { - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */ - for( i = US; i > 0; --i ) + for( i = uSEC; i > 0; --i ) barrier(); return( scc.cha_a_data ); } @@ -365,10 +365,10 @@ do { \ int i; \ scc.cha_b_ctrl = (reg); \ - for( i = US; i > 0; --i ) \ + for( i = uSEC; i > 0; --i ) \ barrier(); \ scc.cha_b_ctrl = (val); \ - for( i = US; i > 0; --i ) \ + for( i = uSEC; i > 0; --i ) \ barrier(); \ } while(0) @@ -376,10 +376,10 @@ do { \ int i; \ scc.cha_a_ctrl = (reg); \ - for( i = US; i > 0; --i ) \ + for( i = uSEC; i > 0; --i ) \ barrier(); \ scc.cha_a_ctrl = (val); \ - for( i = US; i > 0; --i ) \ + for( i = uSEC; i > 0; --i ) \ barrier(); \ } while(0) @@ -389,7 +389,7 @@ #define LONG_DELAY() \ do { \ int i; \ - for( i = 60*US; i > 0; --i ) \ + for( i = 60*uSEC; i > 0; --i ) \ barrier(); \ } while(0) @@ -399,19 +399,21 @@ void mac_init_scc_port( int cflag, int port ) #endif { - extern int mac_SCC_reset_done; - static int clksrc_table[9] = - /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ - { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; - static int brgsrc_table[9] = - /* reg 14: 0 = RTxC, 2 = PCLK */ - { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; - static int clkmode_table[9] = - /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ - { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; - static int div_table[9] = - /* reg12 (BRG low) */ - { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + extern int mac_SCC_reset_done; + + /* + * baud rates: 1200, 1800, 2400, 4800, 9600, 19.2k, 38.4k, 57.6k, 115.2k + */ + + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 94, 62, 46, 22, 10, 4, 1, 0, 0 }; int baud = cflag & CBAUD; int clksrc, clkmode, div, reg3, reg5; @@ -426,12 +428,10 @@ clkmode = clkmode_table[baud]; div = div_table[baud]; - reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; - reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); + reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; -#if 0 - if (port) { -#endif + if (port == 1) { (void)scc.cha_b_ctrl; /* reset reg pointer */ SCCB_WRITE( 9, 0xc0 ); /* reset */ LONG_DELAY(); /* extra delay after WR9 access */ @@ -442,17 +442,14 @@ SCCB_WRITE( 5, reg5 ); SCCB_WRITE( 9, 0 ); /* no interrupts */ LONG_DELAY(); /* extra delay after WR9 access */ - SCCB_WRITE( 10, 0 ); /* NRZ mode */ + SCCB_WRITE( 10, 0 ); /* NRZ mode */ SCCB_WRITE( 11, clksrc ); /* main clock source */ SCCB_WRITE( 12, div ); /* BRG value */ SCCB_WRITE( 13, 0 ); /* BRG high byte */ - SCCB_WRITE( 14, brgsrc_table[baud] ); - SCCB_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCCB_WRITE( 14, 1 ); SCCB_WRITE( 3, reg3 | 1 ); SCCB_WRITE( 5, reg5 | 8 ); -#if 0 - } else { -#endif + } else if (port == 0) { (void)scc.cha_a_ctrl; /* reset reg pointer */ SCCA_WRITE( 9, 0xc0 ); /* reset */ LONG_DELAY(); /* extra delay after WR9 access */ @@ -463,17 +460,15 @@ SCCA_WRITE( 5, reg5 ); SCCA_WRITE( 9, 0 ); /* no interrupts */ LONG_DELAY(); /* extra delay after WR9 access */ - SCCA_WRITE( 10, 0 ); /* NRZ mode */ + SCCA_WRITE( 10, 0 ); /* NRZ mode */ SCCA_WRITE( 11, clksrc ); /* main clock source */ SCCA_WRITE( 12, div ); /* BRG value */ SCCA_WRITE( 13, 0 ); /* BRG high byte */ - SCCA_WRITE( 14, brgsrc_table[baud] ); - SCCA_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCCA_WRITE( 14, 1 ); SCCA_WRITE( 3, reg3 | 1 ); SCCA_WRITE( 5, reg5 | 8 ); -#if 0 } -#endif + mac_SCC_reset_done = 1; mac_SCC_init_done = 1; } @@ -486,18 +481,20 @@ return; #endif #ifdef DEBUG_SERIAL - if (!strcmp( m68k_debug_device, "ser" )) { - strcpy( m68k_debug_device, "ser1" ); - } - if (!strcmp( m68k_debug_device, "ser1" )) { - /* ST-MFP Modem1 serial port */ + if ( !strcmp( m68k_debug_device, "ser" ) + || !strcmp( m68k_debug_device, "ser1" )) { + /* Mac modem port */ mac_init_scc_port( B9600|CS8, 0 ); mac_console_driver.write = mac_scca_console_write; + mac_console_driver.wait_key = mac_scca_console_wait_key; + scc_port = 0; } else if (!strcmp( m68k_debug_device, "ser2" )) { - /* SCC Modem2 serial port */ + /* Mac printer port */ mac_init_scc_port( B9600|CS8, 1 ); mac_console_driver.write = mac_sccb_console_write; + mac_console_driver.wait_key = mac_sccb_console_wait_key; + scc_port = 1; } if (mac_console_driver.write) register_console(&mac_console_driver); diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c --- v2.1.124/linux/arch/m68k/mac/macboing.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/mac/macboing.c Mon Oct 5 13:54:39 1998 @@ -27,12 +27,52 @@ unsigned long flags; int samples=512; + if (macintosh_config->ident == MAC_MODEL_C660 + || macintosh_config->ident == MAC_MODEL_Q840) + { + /* + * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. + * It appears to be similar to the "AWACS" custom ASIC in the Power Mac + * [678]100. Because Singer and AWACS may have a similar hardware + * interface, this would imply that the code in drivers/sound/dmasound.c + * for AWACS could be used as a basis for Singer support. All we have to + * do is figure out how to do DMA on the 660AV/840AV through the PSC and + * figure out where the Singer hardware sits in memory. (I'd look in the + * vicinity of the AWACS location in a Power Mac [678]100 first, or the + * current location of the Apple Sound Chip--ASC--in other Macs.) The + * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. + * + * Quoted from Apple's Tech Info Library, article number 16405: + * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power + * Macintosh models have 16-bit audio input and output capability + * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer + * codec circuitry in the AVs. The Audio Waveform Amplifier and + * Converter (AWAC) chip in the Power Macintosh performs the same + * 16-bit I/O functionality. The PowerBook 500 series computers + * support 16-bit stereo output, but only mono input." + * + * http://til.info.apple.com/techinfo.nsf/artnum/n16405 + * + * --David Kilzer + */ + + return; + } + if(!inited) { int i=0; int j=0; int k=0; int l=0; + + /* + * The IIfx strikes again! + */ + + if(macintosh_config->ident==MAC_MODEL_IIFX) + asc_base=(void *)0x50010000; + for(i=0;i #include #include #include @@ -216,7 +215,10 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs); -/*#define DEBUG_VIA*/ +/* #define DEBUG_MACINTS */ +/* #define DEBUG_NUBUS_INT */ +/* #define DEBUG_VIA */ +/* #define DEBUG_VIA_NUBUS */ void mac_init_IRQ(void) { @@ -273,13 +275,8 @@ * Currently, one interrupt per channel is used, solely * to pass the correct async_info as parameter! */ -#if 0 /* want to install debug/SCC shutup routine until SCC init */ - sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler); -#else + sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler); -#endif - /* Alan uses IRQ 5 for SCC ?? */ - sys_request_irq(5, mac_debug_handler, IRQ_FLG_STD, "INT5", mac_debug_handler); /* level 6 */ sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang); @@ -289,25 +286,25 @@ /* initialize the handler tables for VIAs */ for (i = 0; i < 8; i++) { - via1_handler[i].handler = mac_default_handler; - via1_handler[i].dev_id = NULL; - via1_param[i].flags = IRQ_FLG_STD; - via1_param[i].devname = NULL; - - via2_handler[i].handler = mac_default_handler; - via2_handler[i].dev_id = NULL; - via2_param[i].flags = IRQ_FLG_STD; - via2_param[i].devname = NULL; - - rbv_handler[i].handler = mac_default_handler; - rbv_handler[i].dev_id = NULL; - rbv_param[i].flags = IRQ_FLG_STD; - rbv_param[i].devname = NULL; - - scc_handler[i].handler = mac_default_handler; - scc_handler[i].dev_id = NULL; - scc_param[i].flags = IRQ_FLG_STD; - scc_param[i].devname = NULL; + via1_handler[i].handler = mac_default_handler; + via1_handler[i].dev_id = NULL; + via1_param[i].flags = IRQ_FLG_STD; + via1_param[i].devname = NULL; + + via2_handler[i].handler = mac_default_handler; + via2_handler[i].dev_id = NULL; + via2_param[i].flags = IRQ_FLG_STD; + via2_param[i].devname = NULL; + + rbv_handler[i].handler = mac_default_handler; + rbv_handler[i].dev_id = NULL; + rbv_param[i].flags = IRQ_FLG_STD; + rbv_param[i].devname = NULL; + + scc_handler[i].handler = mac_default_handler; + scc_handler[i].dev_id = NULL; + scc_param[i].flags = IRQ_FLG_STD; + scc_param[i].devname = NULL; /* NUBUS interrupts routed through VIA2 slot 2 - special */ nubus_handler[i].handler = nubus_wtf; @@ -337,16 +334,16 @@ via_table[2] = NULL; via_table[3] = NULL; - handler_table[2] = &rbv_handler[0]; + handler_table[2] = &rbv_handler[0]; handler_table[3] = &scc_handler[0]; handler_table[4] = NULL; handler_table[5] = NULL; handler_table[6] = NULL; - handler_table[7] = &nubus_handler[0]; + handler_table[7] = &nubus_handler[0]; - param_table[2] = &rbv_param[0]; + param_table[2] = &rbv_param[0]; param_table[3] = &scc_param[0]; - param_table[7] = &nubus_param[0]; + param_table[7] = &nubus_param[0]; mac_irqs[2] = &rbv_irqs[0]; mac_irqs[3] = &scc_irqs[0]; @@ -356,7 +353,8 @@ * AV Macs: shutup the PSC ints */ if (macintosh_config->ident == MAC_MODEL_C660 - || macintosh_config->ident == MAC_MODEL_Q840) { + || macintosh_config->ident == MAC_MODEL_Q840) + { psc_init(); handler_table[2] = &psc3_handler[0]; @@ -463,9 +461,15 @@ * 980429 MS: RBV is ok, OSS seems to be differentt */ if (!via2_is_oss) - /* CB2 (IRQ) indep. interrupt input, positive edge */ - /* CA2 (DRQ) indep. interrupt input, positive edge */ - via_write(via, vPCR, 0x66); + if (macintosh_config->scsi_type == MAC_SCSI_OLD) { + /* CB2 (IRQ) indep. interrupt input, positive edge */ + /* CA2 (DRQ) indep. interrupt input, positive edge */ + via_write(via, vPCR, 0x66); + } else { + /* CB2 (IRQ) indep. interrupt input, negative edge */ + /* CA2 (DRQ) indep. interrupt input, negative edge */ + via_write(via, vPCR, 0x22); + } #if 0 else /* CB2 (IRQ) indep. interrupt input, negative edge */ @@ -614,7 +618,7 @@ via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); else if (srcidx == SRC_VIA2 && via2_is_oss) via_write(oss_regp, oss_map[irqidx]+8, 2); - else if (srcidx >= SRC_VIA2) + else if (srcidx > SRC_VIA2) via_write(via, (0x104 + 0x10*srcidx), via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx))); else @@ -636,7 +640,11 @@ via_write(via, rIER, (via_read(via, rIER)&(1<= SRC_VIA2) + /* + * VIA2 is fixed. The stuff above VIA2 is for later + * macintoshes only. + */ + else if (srcidx > SRC_VIA2) via_write(via, (0x104 + 0x10*srcidx), via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx))); else @@ -677,7 +685,7 @@ pending |= via_read(via, rIFR)&(1<= SRC_VIA2) + else if (srcidx > SRC_VIA2) pending |= via_read(via, (0x100 + 0x10*srcidx))&(1< #include #include #include +#include +#include +#include #include #include #include "via6522.h" -#include "psc.h" +#include volatile unsigned char *via1=(unsigned char *)VIABASE; volatile unsigned char *via2=(unsigned char *)VIABASE2; volatile unsigned char *psc=(unsigned char *)PSCBASE; +volatile long *via_memory_bogon=(long *)&via_memory_bogon; + unsigned char via1_clock, via1_datab; static int rbv=0; @@ -38,9 +44,8 @@ #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -void via_init_clock(void (*func)(int, void *, struct pt_regs *)) +void via_configure_base(void) { - unsigned char c; switch(macintosh_config->via_type) { @@ -66,6 +71,13 @@ break; default: } +} + + +void via_init_clock(void (*func)(int, void *, struct pt_regs *)) +{ + unsigned char c; + via1_clock=via_read(via1, vACR); via1_datab=via_read(via1, vBufB); @@ -179,29 +191,28 @@ } /* - * get time offset between scheduling timer ticks - * Code stolen from arch/m68k/atari/time.c; underflow check probably - * wrong. + * TBI: get time offset between scheduling timer ticks */ #define TICK_SIZE 10000 /* This is always executed with interrupts disabled. */ + unsigned long mac_gettimeoffset (void) { - unsigned long ticks, offset = 0; + unsigned long ticks, offset = 0; - /* read VIA1 timer 2 current value */ - ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); - /* The probability of underflow is less than 2% */ - if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) - /* Check for pending timer interrupt in VIA1 IFR */ - if (via_read(via1, vIFR) & 0x40) - offset = TICK_SIZE; + /* read VIA1 timer 2 current value */ + ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); + /* The probability of underflow is less than 2% */ + if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) + /* Check for pending timer interrupt in VIA1 IFR */ + if (via_read(via1, vIFR) & 0x40) + offset = TICK_SIZE; - ticks = MAC_CLOCK_TICK - ticks; - ticks = ticks * 10000L / MAC_CLOCK_TICK; + ticks = MAC_CLOCK_TICK - ticks; + ticks = ticks * 10000L / MAC_CLOCK_TICK; - return ticks + offset; + return ticks + offset; } /* @@ -218,27 +229,64 @@ } /* - * The power switch - yes its software! + * The power switch - yes it's software! */ - + void mac_poweroff(void) { -#if 0 + /* - * Powerdown, for the Macs that support it + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer */ - if(rbv) { - via_write(via2, rBufB, via_read(via2, rBufB)&~0x04); - } else { - /* Direction of vDirB is output */ - via_write(via2,vDirB,via_read(via2,vDirB)|0x04); - /* Send a value of 0 on that line */ - via_write(via2,vBufB,via_read(via2,vBufB)&~0x04); + + if (macintosh_config->adb_type == MAC_ADB_II) + { + if(rbv) { + via_write(via2, rBufB, via_read(via2, rBufB)&~0x04); + } else { + /* Direction of vDirB is output */ + via_write(via2,vDirB,via_read(via2,vDirB)|0x04); + /* Send a value of 0 on that line */ + via_write(via2,vBufB,via_read(via2,vBufB)&~0x04); + /* Otherwise it prints "It is now.." then shuts off */ + mdelay(1000); + } + + /* We should never make it this far... */ + printk ("It is now safe to switch off your machine.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } + + /* + * Initially discovered this technique in the Mach kernel of MkLinux in + * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC + * code in arch/ppc/kernel/setup.c, which also has a PMU technique for PowerBooks! + * --David Kilzer + */ + + else if (macintosh_config->adb_type == MAC_ADB_IISI + || macintosh_config->adb_type == MAC_ADB_CUDA) + { + struct adb_request req; + + /* + * Print our "safe" message before we send the request + * just in case the request never returns. + */ + + printk ("It is now safe to switch off your machine.\n"); + + adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); + + printk ("ADB powerdown request sent.\n"); + for (;;) + { + adb_poll(); + } } -#endif - /* We should never make it this far... */ - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ } /* @@ -247,28 +295,65 @@ */ void mac_reset(void) { - unsigned long flags; - unsigned long *reset_hook; + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ - save_flags(flags); - cli(); + if (macintosh_config->adb_type == MAC_ADB_II) + { + unsigned long flags; + unsigned long *reset_hook; -#if 0 /* need ROMBASE in booter */ -#if 0 /* works on some */ - rom_reset = (boot_info.bi_mac.rombase + 0xa); -#else /* testing, doesn't work on SE/30 either */ - reset_hook = (unsigned long *) (boot_info.bi_mac.rombase + 0x4); - printk("ROM reset hook: %p\n", *reset_hook); - rom_reset = *reset_hook; -#endif - rom_reset(); + save_flags(flags); + cli(); + + /* need ROMBASE in booter */ + + /* works on some */ + rom_reset = (void *) (mac_bi_data.rombase + 0xa); + +#if 0 + /* testing, doesn't work on SE/30 either */ + reset_hook = (unsigned long *) (mac_bi_data.rombase + 0x4); + printk("ROM reset hook: %p\n", *reset_hook); + rom_reset = *reset_hook; #endif - restore_flags(flags); - /* We never make it this far... */ - printk(" reboot failed, reboot manually!\n"); - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ + rom_reset(); + + restore_flags(flags); + + /* We never make it this far... */ + printk ("Restart failed. Please restart manually.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } + + /* + * Initially discovered this technique in the Mach kernel of MkLinux in + * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC + * code in arch/ppc/kernel/setup.c, which also has a PMU technique! + * --David Kilzer + * + * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines + * but have no way to test this myself. --DDK + */ + + else if (macintosh_config->adb_type == MAC_ADB_IISI + || macintosh_config->adb_type == MAC_ADB_CUDA) + { + struct adb_request req; + + adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); + + printk ("Restart failed. Please restart manually.\n"); + for (;;) + { + adb_poll(); + } + } } /* diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mac/via6522.h linux/arch/m68k/mac/via6522.h --- v2.1.124/linux/arch/m68k/mac/via6522.h Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/mac/via6522.h Mon Oct 5 13:54:39 1998 @@ -6,6 +6,9 @@ * is a bit incomplete as the Mac documentation doesnt cover this well */ +#ifndef _ASM_VIA6522_H_ +#define _ASM_VIA6522_H_ + #define VIABASE 0x50F00000 #define VIABASE2 0x50F02000 @@ -45,17 +48,32 @@ * Register B has the fun stuff in it */ +#define VIA2B_vMode32 0x08 /* 24/32bit switch - doubles as cache flush */ #define VIA2B_vPower 0x04 /* Off switch */ -#define VIA2B_vBusLk 0x02 -#define VIA2B_vCDis 0x01 +#define VIA2B_vBusLk 0x02 /* Nubus in use ?? */ +#define VIA2B_vCDis 0x01 /* Cache disable */ + +/* + * The 6522 via is a 2MHz part, and needs a delay. MacOS seems to + * execute MOV (Ax),(Ax) for this... Oh and we can't use udelay + * here... see we need the via to calibrate the udelay loop ... + */ +extern volatile long *via_memory_bogon; + extern __inline__ void via_write(volatile unsigned char *via,int reg, int v) { + *via_memory_bogon; + *via_memory_bogon; + *via_memory_bogon; via[reg]=v; } extern __inline__ int via_read(volatile unsigned char *via,int reg) { + *via_memory_bogon; + *via_memory_bogon; + *via_memory_bogon; return (int)via[reg]; } @@ -109,3 +127,5 @@ extern void via2_irq(int, void *, struct pt_regs *); extern void via_setup_keyboard(void); + +#endif /* _ASM_VIA6522_H_ */ diff -u --recursive --new-file v2.1.124/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.1.124/linux/arch/m68k/mm/memory.c Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/mm/memory.c Mon Oct 5 13:54:39 1998 @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_AMIGA #include #endif @@ -554,6 +555,14 @@ * this?). So we have to push first and then additionally to invalidate. */ +#ifdef CONFIG_M68K_L2_CACHE +/* + * Jes was worried about performance (urhh ???) so its optional + */ + +extern void (*mach_l2_flush)(int) = NULL; +#endif + /* * cache_clear() semantics: Clear any cache entries for the area in question, * without writing back dirty entries first. This is useful if the data will @@ -593,6 +602,10 @@ "movec %/d0,%/cacr" : : "i" (FLUSH_I_AND_D) : "d0"); +#ifdef CONFIG_M68K_L2_CACHE + if(mach_l2_flush) + mach_l2_flush(0); +#endif } @@ -641,6 +654,10 @@ "movec %/d0,%/cacr" : : "i" (FLUSH_I) : "d0"); +#ifdef CONFIG_M68K_L2_CACHE + if(mach_l2_flush) + mach_l2_flush(1); +#endif } diff -u --recursive --new-file v2.1.124/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.1.124/linux/arch/ppc/config.in Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/config.in Mon Oct 5 13:00:33 1998 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.71 1998/09/18 13:25:17 cort Exp $ +# $Id: config.in,v 1.72 1998/10/01 14:09:40 cort Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -27,7 +27,7 @@ CHRP CONFIG_CHRP \ PowerMac/PReP/CHRP CONFIG_ALL_PPC \ APUS CONFIG_APUS \ - MBX CONFIG_MBX" PReP + MBX CONFIG_MBX" PowerMac endmenu if [ "$CONFIG_MBX" = "y" ];then @@ -184,10 +184,10 @@ tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then if [ "$CONFIG_APUS" = "y" -o "$CONFIG_PMAC" = "y" ]; then - tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND + tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND fi if [ "$CONFIG_PREP" = "y" -o "$CONFIG_CHRP" = "y" ]; then - source drivers/sound/Config.in + source drivers/sound/Config.in fi fi diff -u --recursive --new-file v2.1.124/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.1.124/linux/arch/sparc/kernel/sun4d_smp.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sun4d_smp.c Mon Oct 5 12:28:08 1998 @@ -8,6 +8,7 @@ #include +#include #include #include #include diff -u --recursive --new-file v2.1.124/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.124/linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Oct 5 10:04:35 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.41 1998/10/04 08:44:16 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.42 1998/10/05 03:18:50 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -62,6 +62,7 @@ extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); +extern __kernel_size_t __strlen(const char *); extern char saved_command_line[]; extern char *getname32(u32 name); extern void linux_sparc_syscall(void); diff -u --recursive --new-file v2.1.124/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.1.124/linux/drivers/char/random.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/random.c Mon Oct 5 10:04:34 1998 @@ -1250,7 +1250,7 @@ } #if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */ x = tmp[HASH_BUFFER_SIZE/2]; - add_entropy_words(r, x, (__u32)buf); + add_entropy_words(r, x, (__u32)((unsigned long)buf)); x ^= (x >> 16); /* Fold it in half */ ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x; #endif diff -u --recursive --new-file v2.1.124/linux/drivers/char/serial167.c linux/drivers/char/serial167.c --- v2.1.124/linux/drivers/char/serial167.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/serial167.c Mon Oct 5 14:12:12 1998 @@ -0,0 +1,2984 @@ +/* + * linux/drivers/char/serial167.c + * + * Driver for MVME166/7 board serial ports, which are via a CD2401. + * Based very much on cyclades.c. + * + * MVME166/7 work by Richard Hirst [richard@sleepie.demon.co.uk] + * + * ============================================================== + * + * static char rcsid[] = + * "$Revision: 1.36.1.4 $$Date: 1995/03/29 06:14:14 $"; + * + * linux/kernel/cyclades.c + * + * Maintained by Marcio Saito (cyclades@netcom.com) and + * Randolph Bentson (bentson@grieg.seaslug.org) + * + * Much of the design and some of the code came from serial.c + * which was copyright (C) 1991, 1992 Linus Torvalds. It was + * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, + * and then fixed as suggested by Michael K. Johnson 12/12/92. + * + * This version does not support shared irq's. + * + * This module exports the following rs232 io functions: + * int cy_init(void); + * int cy_open(struct tty_struct *tty, struct file *filp); + * + * $Log: cyclades.c,v $ + * Revision 1.36.1.4 1995/03/29 06:14:14 bentson + * disambiguate between Cyclom-16Y and Cyclom-32Ye; + * + * 200 lines of changes record removed - RGH 11-10-95, starting work on + * converting this to drive serial ports on mvme166 (cd2401). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define cy_put_user put_user + +static unsigned long cy_get_user(unsigned long *addr) +{ + unsigned long result = 0; + int error = get_user (result, addr); + if (error) + printk ("serial167: cy_get_user: error == %d\n", error); + return result; +} + +#define SERIAL_PARANOIA_CHECK +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_THROTTLE +#undef SERIAL_DEBUG_OTHER +#undef SERIAL_DEBUG_IO +#undef SERIAL_DEBUG_COUNT +#undef SERIAL_DEBUG_DTR +#undef CYCLOM_16Y_HACK +#define CYCLOM_ENABLE_MONITORING + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define WAKEUP_CHARS 256 + +#define STD_COM_FLAGS (0) + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + + +DECLARE_TASK_QUEUE(tq_cyclades); + +struct tty_driver cy_serial_driver, cy_callout_driver; +extern int serial_console; +static struct cyclades_port *serial_console_info = NULL; +static unsigned int serial_console_cflag = 0; +u_char initial_console_speed; + +/* Base address of cd2401 chip on mvme166/7 */ + +#define BASE_ADDR (0xfff45000) +#define pcc2chip ((volatile u_char *)0xfff42000) +#define PccSCCMICR 0x1d +#define PccSCCTICR 0x1e +#define PccSCCRICR 0x1f +#define PccTPIACKR 0x25 +#define PccRPIACKR 0x27 +#define PccIMLR 0x3f + +/* This is the per-port data structure */ +struct cyclades_port cy_port[] = { + /* CARD# */ + {-1 }, /* ttyS0 */ + {-1 }, /* ttyS1 */ + {-1 }, /* ttyS2 */ + {-1 }, /* ttyS3 */ +}; +#define NR_PORTS (sizeof(cy_port)/sizeof(struct cyclades_port)) + +static int serial_refcount; + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf = 0; +static struct semaphore tmp_buf_sem = MUTEX; + +/* + * This is used to look up the divisor speeds and the timeouts + * We're normally limited to 15 distinct baud rates. The extra + * are accessed via settings in info->flags. + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + * HI VHI + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, + 0}; + +#if 0 +static char baud_co[] = { /* 25 MHz clock option table */ + /* value => 00 01 02 03 04 */ + /* divide by 8 32 128 512 2048 */ + 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static char baud_bpr[] = { /* 25 MHz baud rate period table */ + 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, + 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15}; +#endif + +/* I think 166 brd clocks 2401 at 20MHz.... */ + +/* These values are written directly to tcor, and >> 5 for writing to rcor */ +static u_char baud_co[] = { /* 20 MHz clock option table */ + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40, + 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* These values written directly to tbpr/rbpr */ +static u_char baud_bpr[] = { /* 20 MHz baud rate period table */ + 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81, + 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10}; + +static u_char baud_cor4[] = { /* receive threshold */ + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07}; + + + +static void shutdown(struct cyclades_port *); +static int startup (struct cyclades_port *); +static void cy_throttle(struct tty_struct *); +static void cy_unthrottle(struct tty_struct *); +static void config_setup(struct cyclades_port *); +extern void console_print(const char *); +#ifdef CYCLOM_SHOW_STATUS +static void show_status(int); +#endif + +#ifdef CONFIG_REMOTE_DEBUG +static void debug_setup(void); +void queueDebugChar (int c); +int getDebugChar(void); + +#define DEBUG_PORT 1 +#define DEBUG_LEN 256 + +typedef struct { + int in; + int out; + unsigned char buf[DEBUG_LEN]; +} debugq; + +debugq debugiq; +#endif + +/* + * I have my own version of udelay(), as it is needed when initialising + * the chip, before the delay loop has been calibrated. Should probably + * reference one of the vmechip2 or pccchip2 counter for an accurate + * delay, but this wild guess will do for now. + */ + +void my_udelay (long us) +{ + u_char x; + volatile u_char *p = &x; + int i; + + while (us--) + for (i = 100; i; i--) + x |= *p; +} + +static inline int +serial_paranoia_check(struct cyclades_port *info, + dev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%d, %d) in %s\n"; + static const char *badinfo = + "Warning: null cyclades_port for (%d, %d) in %s\n"; + static const char *badrange = + "Warning: cyclades_port out of range for (%d, %d) in %s\n"; + + if (!info) { + printk(badinfo, MAJOR(device), MINOR(device), routine); + return 1; + } + + if( (long)info < (long)(&cy_port[0]) + || (long)(&cy_port[NR_PORTS]) < (long)info ){ + printk(badrange, MAJOR(device), MINOR(device), routine); + return 1; + } + + if (info->magic != CYCLADES_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} /* serial_paranoia_check */ + +#if 0 +/* The following diagnostic routines allow the driver to spew + information on the screen, even (especially!) during interrupts. + */ +void +SP(char *data){ + unsigned long flags; + save_flags(flags); cli(); + console_print(data); + restore_flags(flags); +} +char scrn[2]; +void +CP(char data){ + unsigned long flags; + save_flags(flags); cli(); + scrn[0] = data; + console_print(scrn); + restore_flags(flags); +}/* CP */ + +void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */ +void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */ +void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */ +void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */ +#endif + +/* This routine waits up to 1000 micro-seconds for the previous + command to the Cirrus chip to complete and then issues the + new command. An error is returned if the previous command + didn't finish within the time limit. + */ +u_short +write_cy_cmd(volatile u_char *base_addr, u_char cmd) +{ + unsigned long flags; + volatile int i; + + save_flags(flags); cli(); + /* Check to see that the previous command has completed */ + for(i = 0 ; i < 100 ; i++){ + if (base_addr[CyCCR] == 0){ + break; + } + my_udelay(10L); + } + /* if the CCR never cleared, the previous command + didn't finish within the "reasonable time" */ + if ( i == 10 ) { + restore_flags(flags); + return (-1); + } + + /* Issue the new command */ + base_addr[CyCCR] = cmd; + restore_flags(flags); + return(0); +} /* write_cy_cmd */ + + +/* cy_start and cy_stop provide software output flow control as a + function of XON/XOFF, software CTS, and other such stuff. */ + +static void +cy_stop(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_stop ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_stop")) + return; + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)(channel); /* index channel */ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + restore_flags(flags); + + return; +} /* cy_stop */ + +static void +cy_start(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_start ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_start")) + return; + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)(channel); + base_addr[CyIER] |= CyTxMpty; + restore_flags(flags); + + return; +} /* cy_start */ + + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver + * (also known as the "bottom half"). This can be called any + * number of times for any channel without harm. + */ +static inline void +cy_sched_event(struct cyclades_port *info, int event) +{ + info->event |= 1 << event; /* remember what kind of event and who */ + queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */ + mark_bh(CYCLADES_BH); /* then trigger event */ +} /* cy_sched_event */ + + +/* The real interrupt service routines are called + whenever the card wants its hand held--chars + received, out buffer empty, modem change, etc. + */ +static void +cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + unsigned char err, rfoc; + int channel; + char data; + + /* determine the channel and change to that context */ + channel = (u_short ) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + if ((err = base_addr[CyRISR]) & CyTIMEOUT) { + /* This is a receive timeout interrupt, ignore it */ + base_addr[CyREOIR] = CyNOTRANS; + return; + } + + /* Read a byte of data if there is any - assume the error + * is associated with this character */ + + if ((rfoc = base_addr[CyRFOC]) != 0) + data = base_addr[CyRDR]; + else + data = 0; + + /* if there is nowhere to put the data, discard it */ + if(info->tty == 0) { + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return; + } + else { /* there is an open port for this data */ + tty = info->tty; + if(err & info->ignore_status_mask){ + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return; + } + if (tty->flip.count < TTY_FLIPBUF_SIZE){ + tty->flip.count++; + if (err & info->read_status_mask){ + if(err & CyBREAK){ + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + *tty->flip.char_buf_ptr++ = data; + if (info->flags & ASYNC_SAK){ + do_SAK(tty); + } + }else if(err & CyFRAME){ + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + *tty->flip.char_buf_ptr++ = data; + }else if(err & CyPARITY){ + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + *tty->flip.char_buf_ptr++ = data; + }else if(err & CyOVERRUN){ + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + *tty->flip.char_buf_ptr++ = 0; + /* + If the flip buffer itself is + overflowing, we still loose + the next incoming character. + */ + if(tty->flip.count < TTY_FLIPBUF_SIZE){ + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; + } + /* These two conditions may imply */ + /* a normal read should be done. */ + /* else if(data & CyTIMEOUT) */ + /* else if(data & CySPECHAR) */ + }else{ + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = 0; + } + }else{ + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = 0; + } + }else{ + /* there was a software buffer overrun + and nothing could be done about it!!! */ + } + } + queue_task(&tty->flip.tqueue, &tq_timer); + /* end of service */ + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; +} /* cy_rxerr_interrupt */ + +static void +cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int mdm_change; + int mdm_status; + + + /* determine the channel and change to that context */ + channel = (u_short ) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + mdm_change = base_addr[CyMISR]; + mdm_status = base_addr[CyMSVR1]; + + if(info->tty == 0){ /* nowhere to put the data, ignore it */ + ; + }else{ + if((mdm_change & CyDCD) + && (info->flags & ASYNC_CHECK_CD)){ + if(mdm_status & CyDCD){ +/* CP('!'); */ + cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); + }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) + &&(info->flags & ASYNC_CALLOUT_NOHUP))){ +/* CP('@'); */ + cy_sched_event(info, Cy_EVENT_HANGUP); + } + } + if((mdm_change & CyCTS) + && (info->flags & ASYNC_CTS_FLOW)){ + if(info->tty->stopped){ + if(mdm_status & CyCTS){ + /* !!! cy_start isn't used because... */ + info->tty->stopped = 0; + base_addr[CyIER] |= CyTxMpty; + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + }else{ + if(!(mdm_status & CyCTS)){ + /* !!! cy_stop isn't used because... */ + info->tty->stopped = 1; + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + } + } + } + if(mdm_status & CyDSR){ + } + } + base_addr[CyMEOIR] = 0; +} /* cy_modem_interrupt */ + +static void +cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int char_count, saved_cnt; + int outch; + + /* determine the channel and change to that context */ + channel = (u_short ) (base_addr[CyLICR] >> 2); + +#ifdef CONFIG_REMOTE_DEBUG + if (channel == DEBUG_PORT) { + panic ("TxInt on debug port!!!"); + } +#endif + + info = &cy_port[channel]; + + /* validate the port number (as configured and open) */ + if( (channel < 0) || (NR_PORTS <= channel) ){ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + base_addr[CyTEOIR] = CyNOTRANS; + return; + } + info->last_active = jiffies; + if(info->tty == 0){ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = CyNOTRANS; + return; + } + + /* load the on-chip space available for outbound data */ + saved_cnt = char_count = base_addr[CyTFTC]; + + if(info->x_char) { /* send special char */ + outch = info->x_char; + base_addr[CyTDR] = outch; + char_count--; + info->x_char = 0; + } + + if (info->x_break){ + /* The Cirrus chip requires the "Embedded Transmit + Commands" of start break, delay, and end break + sequences to be sent. The duration of the + break is given in TICs, which runs at HZ + (typically 100) and the PPR runs at 200 Hz, + so the delay is duration * 200/HZ, and thus a + break can run from 1/100 sec to about 5/4 sec. + Need to check these values - RGH 141095. + */ + base_addr[CyTDR] = 0; /* start break */ + base_addr[CyTDR] = 0x81; + base_addr[CyTDR] = 0; /* delay a bit */ + base_addr[CyTDR] = 0x82; + base_addr[CyTDR] = info->x_break*200/HZ; + base_addr[CyTDR] = 0; /* terminate break */ + base_addr[CyTDR] = 0x83; + char_count -= 7; + info->x_break = 0; + } + + while (char_count > 0){ + if (!info->xmit_cnt){ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + break; + } + if (info->xmit_buf == 0){ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + break; + } + if (info->tty->stopped || info->tty->hw_stopped){ + base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + break; + } + /* Because the Embedded Transmit Commands have been + enabled, we must check to see if the escape + character, NULL, is being sent. If it is, we + must ensure that there is room for it to be + doubled in the output stream. Therefore we + no longer advance the pointer when the character + is fetched, but rather wait until after the check + for a NULL output character. (This is necessary + because there may not be room for the two chars + needed to send a NULL. + */ + outch = info->xmit_buf[info->xmit_tail]; + if( outch ){ + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + char_count--; + }else{ + if(char_count > 1){ + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + base_addr[CyTDR] = 0; + char_count--; + char_count--; + }else{ + break; + } + } + } + + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; +} /* cy_tx_interrupt */ + +static void +cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + char data; + int char_count; + int save_cnt; + + /* determine the channel and change to that context */ + channel = (u_short ) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + save_cnt = char_count = base_addr[CyRFOC]; + +#ifdef CONFIG_REMOTE_DEBUG + if (channel == DEBUG_PORT) { + while (char_count--) { + data = base_addr[CyRDR]; + queueDebugChar(data); + } + } + else +#endif + /* if there is nowhere to put the data, discard it */ + if(info->tty == 0){ + while(char_count--){ + data = base_addr[CyRDR]; + } + }else{ /* there is an open port for this data */ + tty = info->tty; + /* load # characters available from the chip */ + +#ifdef CYCLOM_ENABLE_MONITORING + ++info->mon.int_count; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + while(char_count--){ + data = base_addr[CyRDR]; + if (tty->flip.count >= TTY_FLIPBUF_SIZE){ + continue; + } + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; +#ifdef CYCLOM_16Y_HACK + udelay(10L); +#endif + } + queue_task(&tty->flip.tqueue, &tq_timer); + } + /* end of service */ + base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; +} /* cy_rx_interrupt */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using cy_sched_event(), and they get done here. + * + * This is done through one level of indirection--the task queue. + * When a hardware interrupt service routine wants service by the + * driver's bottom half, it enqueues the appropriate tq_struct (one + * per port) to the tq_cyclades work queue and sets a request flag + * via mark_bh for processing that queue. When the time is right, + * do_cyclades_bh is called (because of the mark_bh) and it requests + * that the work queue be processed. + * + * Although this may seem unwieldy, it gives the system a way to + * pass an argument (in this case the pointer to the cyclades_port + * structure) to the bottom half of the driver. Previous kernels + * had to poll every port to see if that port needed servicing. + */ +static void +do_cyclades_bh(void) +{ + run_task_queue(&tq_cyclades); +} /* do_cyclades_bh */ + +static void +do_softint(void *private_) +{ + struct cyclades_port *info = (struct cyclades_port *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE| + ASYNC_CALLOUT_ACTIVE); + } + if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { + if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup){ + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); + } +} /* do_softint */ + + +/* This is called whenever a port becomes active; + interrupts are enabled and DTR & RTS are turned on. + */ +static int +startup(struct cyclades_port * info) +{ + unsigned long flags; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + + if (info->flags & ASYNC_INITIALIZED){ + return 0; + } + + if (!info->type){ + if (info->tty){ + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + return 0; + } + if (!info->xmit_buf){ + info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL); + if (!info->xmit_buf){ + return -ENOMEM; + } + } + + config_setup(info); + + channel = info->line; + +#ifdef SERIAL_DEBUG_OPEN + printk("startup channel %d\n", channel); +#endif + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); + + base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */ + base_addr[CyMSVR1] = CyRTS; +/* CP('S');CP('1'); */ + base_addr[CyMSVR2] = CyDTR; + +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + + base_addr[CyIER] |= CyRxData; + info->flags |= ASYNC_INITIALIZED; + + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + restore_flags(flags); + +#ifdef SERIAL_DEBUG_OPEN + printk(" done\n"); +#endif + return 0; +} /* startup */ + +void +start_xmit( struct cyclades_port *info ) +{ + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + + channel = info->line; + save_flags(flags); cli(); + base_addr[CyCAR] = channel; + base_addr[CyIER] |= CyTxMpty; + restore_flags(flags); +} /* start_xmit */ + +/* + * This routine shuts down a serial port; interrupts are disabled, + * and DTR is dropped if the hangup on close termio flag is on. + */ +static void +shutdown(struct cyclades_port * info) +{ + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + + if (!(info->flags & ASYNC_INITIALIZED)){ +/* CP('$'); */ + return; + } + + channel = info->line; + +#ifdef SERIAL_DEBUG_OPEN + printk("shutdown channel %d\n", channel); +#endif + + /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE + SENT BEFORE DROPPING THE LINE !!! (Perhaps + set some flag that is read when XMTY happens.) + Other choices are to delay some fixed interval + or schedule some later processing. + */ + save_flags(flags); cli(); + if (info->xmit_buf){ + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + base_addr[CyCAR] = (u_char)channel; + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + base_addr[CyMSVR1] = 0; +/* CP('C');CP('1'); */ + base_addr[CyMSVR2] = 0; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + } + write_cy_cmd(base_addr,CyDIS_RCVR); + /* it may be appropriate to clear _XMIT at + some later date (after testing)!!! */ + + if (info->tty){ + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + +#ifdef SERIAL_DEBUG_OPEN + printk(" done\n"); +#endif + return; +} /* shutdown */ + +/* + * This routine finds or computes the various line characteristics. + */ +static void +config_setup(struct cyclades_port * info) +{ + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + unsigned cflag; + int i; + unsigned char ti, need_init_chan = 0; + + if (!info->tty || !info->tty->termios){ + return; + } + if (info->line == -1){ + return; + } + cflag = info->tty->termios->c_cflag; + + /* baud rate */ + i = cflag & CBAUD; +#ifdef CBAUDEX +/* Starting with kernel 1.1.65, there is direct support for + higher baud rates. The following code supports those + changes. The conditional aspect allows this driver to be + used for earlier as well as later kernel versions. (The + mapping is slightly different from serial.c because there + is still the possibility of supporting 75 kbit/sec with + the Cyclades board.) + */ + if (i & CBAUDEX) { + if (i == B57600) + i = 16; + else if(i == B115200) + i = 18; +#ifdef B78600 + else if(i == B78600) + i = 17; +#endif + else + info->tty->termios->c_cflag &= ~CBAUDEX; + } +#endif + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 3; + } + /* Don't ever change the speed of the console port. It will + * run at the speed specified in bootinfo, or at 19.2K */ + /* Actually, it should run at whatever speed 166Bug was using */ + /* Note info->timeout isn't used at present */ + if (info != serial_console_info) { + info->tbpr = baud_bpr[i]; /* Tx BPR */ + info->tco = baud_co[i]; /* Tx CO */ + info->rbpr = baud_bpr[i]; /* Rx BPR */ + info->rco = baud_co[i] >> 5; /* Rx CO */ + if (baud_table[i] == 134) { + info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + /* get it right for 134.5 baud */ + } else if (baud_table[i]) { + info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; + /* this needs to be propagated into the card info */ + } else { + info->timeout = 0; + } + } + /* By tradition (is it a standard?) a baud rate of zero + implies the line should be/has been closed. A bit + later in this routine such a test is performed. */ + + /* byte size and parity */ + info->cor7 = 0; + info->cor6 = 0; + info->cor5 = 0; + info->cor4 = (info->default_threshold + ? info->default_threshold + : baud_cor4[i]); /* receive threshold */ + /* Following two lines added 101295, RGH. */ + /* It is obviously wrong to access CyCORx, and not info->corx here, + * try and remember to fix it later! */ + channel = info->line; + base_addr[CyCAR] = (u_char)channel; + if (C_CLOCAL(info->tty)) { + if (base_addr[CyIER] & CyMdmCh) + base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */ + /* ignore 1->0 modem transitions */ + if (base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) + base_addr[CyCOR4] &= ~(CyDSR|CyCTS|CyDCD); + /* ignore 0->1 modem transitions */ + if (base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) + base_addr[CyCOR5] &= ~(CyDSR|CyCTS|CyDCD); + } else { + if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh) + base_addr[CyIER] |= CyMdmCh; /* with modem intr */ + /* act on 1->0 modem transitions */ + if ((base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD)) + base_addr[CyCOR4] |= CyDSR|CyCTS|CyDCD; + /* act on 0->1 modem transitions */ + if ((base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD)) + base_addr[CyCOR5] |= CyDSR|CyCTS|CyDCD; + } + info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP; + info->cor2 = CyETC; + switch(cflag & CSIZE){ + case CS5: + info->cor1 = Cy_5_BITS; + break; + case CS6: + info->cor1 = Cy_6_BITS; + break; + case CS7: + info->cor1 = Cy_7_BITS; + break; + case CS8: + info->cor1 = Cy_8_BITS; + break; + } + if (cflag & PARENB){ + if (cflag & PARODD){ + info->cor1 |= CyPARITY_O; + }else{ + info->cor1 |= CyPARITY_E; + } + }else{ + info->cor1 |= CyPARITY_NONE; + } + + /* CTS flow control flag */ +#if 0 + /* Don't complcate matters for now! RGH 141095 */ + if (cflag & CRTSCTS){ + info->flags |= ASYNC_CTS_FLOW; + info->cor2 |= CyCtsAE; + }else{ + info->flags &= ~ASYNC_CTS_FLOW; + info->cor2 &= ~CyCtsAE; + } +#endif + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /*********************************************** + The hardware option, CyRtsAO, presents RTS when + the chip has characters to send. Since most modems + use RTS as reverse (inbound) flow control, this + option is not used. If inbound flow control is + necessary, DTR can be programmed to provide the + appropriate signals for use with a non-standard + cable. Contact Marcio Saito for details. + ***********************************************/ + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + + /* CyCMR set once only in mvme167_init_serial() */ + if (base_addr[CyLICR] != channel << 2) + base_addr[CyLICR] = channel << 2; + if (base_addr[CyLIVR] != 0x5c) + base_addr[CyLIVR] = 0x5c; + + /* tx and rx baud rate */ + + if (base_addr[CyCOR1] != info->cor1) + need_init_chan = 1; + if (base_addr[CyTCOR] != info->tco) + base_addr[CyTCOR] = info->tco; + if (base_addr[CyTBPR] != info->tbpr) + base_addr[CyTBPR] = info->tbpr; + if (base_addr[CyRCOR] != info->rco) + base_addr[CyRCOR] = info->rco; + if (base_addr[CyRBPR] != info->rbpr) + base_addr[CyRBPR] = info->rbpr; + + /* set line characteristics according configuration */ + + if (base_addr[CySCHR1] != START_CHAR(info->tty)) + base_addr[CySCHR1] = START_CHAR(info->tty); + if (base_addr[CySCHR2] != STOP_CHAR(info->tty)) + base_addr[CySCHR2] = STOP_CHAR(info->tty); + if (base_addr[CySCRL] != START_CHAR(info->tty)) + base_addr[CySCRL] = START_CHAR(info->tty); + if (base_addr[CySCRH] != START_CHAR(info->tty)) + base_addr[CySCRH] = START_CHAR(info->tty); + if (base_addr[CyCOR1] != info->cor1) + base_addr[CyCOR1] = info->cor1; + if (base_addr[CyCOR2] != info->cor2) + base_addr[CyCOR2] = info->cor2; + if (base_addr[CyCOR3] != info->cor3) + base_addr[CyCOR3] = info->cor3; + if (base_addr[CyCOR4] != info->cor4) + base_addr[CyCOR4] = info->cor4; + if (base_addr[CyCOR5] != info->cor5) + base_addr[CyCOR5] = info->cor5; + if (base_addr[CyCOR6] != info->cor6) + base_addr[CyCOR6] = info->cor6; + if (base_addr[CyCOR7] != info->cor7) + base_addr[CyCOR7] = info->cor7; + + if (need_init_chan) + write_cy_cmd(base_addr,CyINIT_CHAN); + + base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */ + + /* 2ms default rx timeout */ + ti = info->default_timeout ? info->default_timeout : 0x02; + if (base_addr[CyRTPRL] != ti) + base_addr[CyRTPRL] = ti; + if (base_addr[CyRTPRH] != 0) + base_addr[CyRTPRH] = 0; + + /* Set up RTS here also ????? RGH 141095 */ + if(i == 0){ /* baud rate is zero, turn off line */ + if ((base_addr[CyMSVR2] & CyDTR) == CyDTR) + base_addr[CyMSVR2] = 0; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + }else{ + if ((base_addr[CyMSVR2] & CyDTR) != CyDTR) + base_addr[CyMSVR2] = CyDTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + } + + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + + restore_flags(flags); + +} /* config_setup */ + + +static void +cy_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + +#ifdef SERIAL_DEBUG_IO + printk("cy_put_char ttyS%d(0x%02x)\n", info->line, ch); +#endif + + if (serial_paranoia_check(info, tty->device, "cy_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= PAGE_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= PAGE_SIZE - 1; + info->xmit_cnt++; + restore_flags(flags); +} /* cy_put_char */ + + +static void +cy_flush_chars(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + +#ifdef SERIAL_DEBUG_IO + printk("cy_flush_chars ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped + || tty->hw_stopped || !info->xmit_buf) + return; + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = channel; + base_addr[CyIER] |= CyTxMpty; + restore_flags(flags); +} /* cy_flush_chars */ + + +/* This routine gets called when tty_write has put something into + the write_queue. If the port is not already transmitting stuff, + start it off by enabling interrupts. The interrupt service + routine will then ensure that the characters are sent. If the + port is already active, there is no need to kick it. + */ +static int +cy_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + int c, total = 0; + +#ifdef SERIAL_DEBUG_IO + printk("cy_write ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_write")){ + return 0; + } + + if (!tty || !info->xmit_buf || !tmp_buf){ + return 0; + } + + while (1) { + save_flags(flags); cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0){ + restore_flags(flags); + break; + } + + if (from_user) { + down(&tmp_buf_sem); + copy_from_user(tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + up(&tmp_buf_sem); + } else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + + + if (info->xmit_cnt + && !tty->stopped + && !tty->hw_stopped ) { + start_xmit(info); + } + return total; +} /* cy_write */ + + +static int +cy_write_room(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + int ret; + +#ifdef SERIAL_DEBUG_IO + printk("cy_write_room ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_write_room")) + return 0; + ret = PAGE_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} /* cy_write_room */ + + +static int +cy_chars_in_buffer(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + +#ifdef SERIAL_DEBUG_IO + printk("cy_chars_in_buffer ttyS%d %d\n", info->line, info->xmit_cnt); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer")) + return 0; + + return info->xmit_cnt; +} /* cy_chars_in_buffer */ + + +static void +cy_flush_buffer(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + +#ifdef SERIAL_DEBUG_IO + printk("cy_flush_buffer ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} /* cy_flush_buffer */ + + +/* This routine is called by the upper-layer tty layer to signal + that incoming characters should be throttled or that the + throttle should be released. + */ +static void +cy_throttle(struct tty_struct * tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); + printk("cy_throttle ttyS%d\n", info->line); +#endif + + if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){ + return; + } + + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ + } + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = 0; + restore_flags(flags); + + return; +} /* cy_throttle */ + + +static void +cy_unthrottle(struct tty_struct * tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); + printk("cy_unthrottle ttyS%d\n", info->line); +#endif + + if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){ + return; + } + + if (I_IXOFF(tty)) { + info->x_char = START_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ + } + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = CyRTS; + restore_flags(flags); + + return; +} /* cy_unthrottle */ + +static int +get_serial_info(struct cyclades_port * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + +/* CP('g'); */ + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->line; + tmp.irq = 0; + tmp.flags = info->flags; + tmp.baud_base = 0; /*!!!*/ + tmp.close_delay = info->close_delay; + tmp.custom_divisor = 0; /*!!!*/ + tmp.hub6 = 0; /*!!!*/ + copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + return 0; +} /* get_serial_info */ + +static int +set_serial_info(struct cyclades_port * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct cyclades_port old_info; + +/* CP('s'); */ + if (!new_info) + return -EFAULT; + copy_from_user(&new_serial,new_info,sizeof(new_serial)); + old_info = *info; + + if (!suser()) { + if ((new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != + (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + goto check_and_exit; + } + + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->close_delay = new_serial.close_delay; + + +check_and_exit: + if (info->flags & ASYNC_INITIALIZED){ + config_setup(info); + return 0; + }else{ + return startup(info); + } +} /* set_serial_info */ + +static int +get_modem_info(struct cyclades_port * info, unsigned int *value) +{ + int channel; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + unsigned char status; + unsigned int result; + + channel = info->line; + + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; + restore_flags(flags); + + result = ((status & CyRTS) ? TIOCM_RTS : 0) + | ((status & CyDTR) ? TIOCM_DTR : 0) + | ((status & CyDCD) ? TIOCM_CAR : 0) + | ((status & CyDSR) ? TIOCM_DSR : 0) + | ((status & CyCTS) ? TIOCM_CTS : 0); + cy_put_user(result,(unsigned long *) value); + return 0; +} /* get_modem_info */ + +static int +set_modem_info(struct cyclades_port * info, unsigned int cmd, + unsigned int *value) +{ + int channel; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + unsigned int arg = cy_get_user((unsigned long *) value); + + channel = info->line; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = CyRTS; + restore_flags(flags); + } + if (arg & TIOCM_DTR){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; +/* CP('S');CP('2'); */ + base_addr[CyMSVR2] = CyDTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + restore_flags(flags); + } + break; + case TIOCMBIC: + if (arg & TIOCM_RTS){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = 0; + restore_flags(flags); + } + if (arg & TIOCM_DTR){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; +/* CP('C');CP('2'); */ + base_addr[CyMSVR2] = 0; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + restore_flags(flags); + } + break; + case TIOCMSET: + if (arg & TIOCM_RTS){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = CyRTS; + restore_flags(flags); + }else{ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = 0; + restore_flags(flags); + } + if (arg & TIOCM_DTR){ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; +/* CP('S');CP('3'); */ + base_addr[CyMSVR2] = CyDTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + restore_flags(flags); + }else{ + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; +/* CP('C');CP('3'); */ + base_addr[CyMSVR2] = 0; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + restore_flags(flags); + } + break; + default: + return -EINVAL; + } + return 0; +} /* set_modem_info */ + +static void +send_break( struct cyclades_port * info, int duration) +{ /* Let the transmit ISR take care of this (since it + requires stuffing characters into the output stream). + */ + info->x_break = duration; + if (!info->xmit_cnt ) { + start_xmit(info); + } +} /* send_break */ + +static int +get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) +{ + + copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)); + info->mon.int_count = 0; + info->mon.char_count = 0; + info->mon.char_max = 0; + info->mon.char_last = 0; + return 0; +} + +static int +set_threshold(struct cyclades_port * info, unsigned long value) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + + channel = info->line; + + info->cor4 &= ~CyREC_FIFO; + info->cor4 |= value & CyREC_FIFO; + base_addr[CyCOR4] = info->cor4; + return 0; +} + +static int +get_threshold(struct cyclades_port * info, unsigned long *value) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + unsigned long tmp; + + channel = info->line; + + tmp = base_addr[CyCOR4] & CyREC_FIFO; + cy_put_user(tmp,value); + return 0; +} + +static int +set_default_threshold(struct cyclades_port * info, unsigned long value) +{ + info->default_threshold = value & 0x0f; + return 0; +} + +static int +get_default_threshold(struct cyclades_port * info, unsigned long *value) +{ + cy_put_user(info->default_threshold,value); + return 0; +} + +static int +set_timeout(struct cyclades_port * info, unsigned long value) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + + channel = info->line; + + base_addr[CyRTPRL] = value & 0xff; + base_addr[CyRTPRH] = (value >> 8) & 0xff; + return 0; +} + +static int +get_timeout(struct cyclades_port * info, unsigned long *value) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + unsigned long tmp; + + channel = info->line; + + tmp = base_addr[CyRTPRL]; + cy_put_user(tmp,value); + return 0; +} + +static int +set_default_timeout(struct cyclades_port * info, unsigned long value) +{ + info->default_timeout = value & 0xff; + return 0; +} + +static int +get_default_timeout(struct cyclades_port * info, unsigned long *value) +{ + cy_put_user(info->default_timeout,value); + return 0; +} + +static int +cy_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + int ret_val = 0; + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_ioctl ttyS%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */ +#endif + + switch (cmd) { + case CYGETMON: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(struct cyclades_monitor)); + if (error){ + ret_val = error; + break; + } + ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); + break; + case CYGETTHRESH: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned long)); + if (error){ + ret_val = error; + break; + } + ret_val = get_threshold(info, (unsigned long *)arg); + break; + case CYSETTHRESH: + ret_val = set_threshold(info, (unsigned long)arg); + break; + case CYGETDEFTHRESH: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned long)); + if (error){ + ret_val = error; + break; + } + ret_val = get_default_threshold(info, (unsigned long *)arg); + break; + case CYSETDEFTHRESH: + ret_val = set_default_threshold(info, (unsigned long)arg); + break; + case CYGETTIMEOUT: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned long)); + if (error){ + ret_val = error; + break; + } + ret_val = get_timeout(info, (unsigned long *)arg); + break; + case CYSETTIMEOUT: + ret_val = set_timeout(info, (unsigned long)arg); + break; + case CYGETDEFTIMEOUT: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned long)); + if (error){ + ret_val = error; + break; + } + ret_val = get_default_timeout(info, (unsigned long *)arg); + break; + case CYSETDEFTIMEOUT: + ret_val = set_default_timeout(info, (unsigned long)arg); + break; + case TCSBRK: /* SVID version: non-zero arg --> no break */ + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; + tty_wait_until_sent(tty,0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + break; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; + tty_wait_until_sent(tty,0); + send_break(info, arg ? arg*(HZ/10) : HZ/4); + break; + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + ret_val = set_modem_info(info, cmd, (unsigned int *) arg); + break; + +/* The following commands are incompletely implemented!!! */ + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned int *)); + if (error){ + ret_val = error; + break; + } + cy_put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + break; + case TIOCSSOFTCAR: + error = verify_area(VERIFY_READ, (void *) arg + ,sizeof(unsigned long *)); + if (error){ + ret_val = error; + break; + } + + arg = cy_get_user((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + break; + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned int *)); + if (error){ + ret_val = error; + break; + } + ret_val = get_modem_info(info, (unsigned int *) arg); + break; + case TIOCGSERIAL: + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(struct serial_struct)); + if (error){ + ret_val = error; + break; + } + ret_val = get_serial_info(info, + (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + ret_val = set_serial_info(info, + (struct serial_struct *) arg); + break; + default: + ret_val = -ENOIOCTLCMD; + } + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_ioctl done\n"); +#endif + + return ret_val; +} /* cy_ioctl */ + + + + +static void +cy_set_termios(struct tty_struct *tty, struct termios * old_termios) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_set_termios ttyS%d\n", info->line); +#endif + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + config_setup(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->stopped = 0; + cy_start(tty); + } +#ifdef tytso_patch_94Nov25_1726 + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif + + return; +} /* cy_set_termios */ + + +static void +cy_close(struct tty_struct * tty, struct file * filp) +{ + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + +/* CP('C'); */ +#ifdef SERIAL_DEBUG_OTHER + printk("cy_close ttyS%d\n", info->line); +#endif + + if (!info + || serial_paranoia_check(info, tty->device, "cy_close")){ + return; + } +#ifdef SERIAL_DEBUG_OPEN + printk("cy_close ttyS%d, count = %d\n", info->line, info->count); +#endif + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("cy_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1); +#endif + if (--info->count < 0) { + printk("cy_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: setting count to 0\n", __LINE__); +#endif + info->count = 0; + } + if (info->count) + return; + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + if (info->flags & ASYNC_INITIALIZED) + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + info->event = 0; + info->tty = 0; + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->close_delay; + schedule(); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_close done\n"); +#endif + + return; +} /* cy_close */ + +/* + * cy_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void +cy_hangup(struct tty_struct *tty) +{ + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + +#ifdef SERIAL_DEBUG_OTHER + printk("cy_hangup ttyS%d\n", info->line); /* */ +#endif + + if (serial_paranoia_check(info, tty->device, "cy_hangup")) + return; + + shutdown(info); +#if 0 + info->event = 0; + info->count = 0; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: setting count to 0\n", __LINE__); +#endif + info->tty = 0; +#endif + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + wake_up_interruptible(&info->open_wait); +} /* cy_hangup */ + + + +/* + * ------------------------------------------------------------ + * cy_open() and friends + * ------------------------------------------------------------ + */ + +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct cyclades_port *info) +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int channel; + int retval; + volatile u_char *base_addr = (u_char *)BASE_ADDR; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&info->close_wait); + if (info->flags & ASYNC_HUP_NOTIFY){ + return -EAGAIN; + }else{ + return -ERESTARTSYS; + } + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE){ + return -EBUSY; + } + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)){ + return -EBUSY; + } + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)){ + return -EBUSY; + } + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + if (info->flags & ASYNC_CALLOUT_ACTIVE){ + return -EBUSY; + } + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * cy_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttyS%d, count = %d\n", + info->line, info->count);/**/ +#endif + info->count--; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count); +#endif + info->blocked_open++; + + channel = info->line; + + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){ + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = CyRTS; +/* CP('S');CP('4'); */ + base_addr[CyMSVR2] = CyDTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); +#endif + } + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) + || !(info->flags & ASYNC_INITIALIZED) ){ + if (info->flags & ASYNC_HUP_NOTIFY) { + retval = -EAGAIN; + }else{ + retval = -ERESTARTSYS; + } + break; + } + save_flags(flags); cli(); + base_addr[CyCAR] = (u_char)channel; +/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */ + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) + && !(info->flags & ASYNC_CLOSING) + && (C_CLOCAL(tty) + || (base_addr[CyMSVR1] & CyDCD))) { + restore_flags(flags); + break; + } + restore_flags(flags); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttyS%d, count = %d\n", + info->line, info->count);/**/ +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)){ + info->count++; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count); +#endif + } + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttyS%d, count = %d\n", + info->line, info->count);/**/ +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} /* block_til_ready */ + +/* + * This routine is called whenever a serial port is opened. It + * performs the serial-specific initialization for the tty structure. + */ +int +cy_open(struct tty_struct *tty, struct file * filp) +{ + struct cyclades_port *info; + int retval, line; + +/* CP('O'); */ + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (NR_PORTS <= line)){ + return -ENODEV; + } + info = &cy_port[line]; + if (info->line < 0){ + return -ENODEV; + } +#ifdef SERIAL_DEBUG_OTHER + printk("cy_open ttyS%d\n", info->line); /* */ +#endif + if (serial_paranoia_check(info, tty->device, "cy_open")){ + return -ENODEV; + } +#ifdef SERIAL_DEBUG_OPEN + printk("cy_open ttyS%d, count = %d\n", info->line, info->count);/**/ +#endif + info->count++; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count); +#endif + tty->driver_data = info; + info->tty = tty; + + if (!tmp_buf) { + tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!tmp_buf){ + return -ENOMEM; + } + } + + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + } + /* + * Start up serial port + */ + retval = startup(info); + if (retval){ + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("cy_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("cy_open done\n");/**/ +#endif + return 0; +} /* cy_open */ + + + +/* + * --------------------------------------------------------------------- + * serial167_init() and friends + * + * serial167_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static void +show_version(void) +{ + printk("MVME166/167 cd2401 driver\n"); +} /* show_version */ + +/* initialize chips on card -- return number of valid + chips (which is number of ports/4) */ + +/* + * This initialises the hardware to a reasonable state. It should + * probe the chip first so as to copy 166-Bug setup as a default for + * port 0. It initialises CMR to CyASYNC; that is never done again, so + * as to limit the number of CyINIT_CHAN commands in normal running. + * + * ... I wonder what I should do if this fails ... + */ + +void +mvme167_serial_console_setup(int cflag) +{ + volatile unsigned char* base_addr = (u_char *)BASE_ADDR; + int ch; + u_char spd; + u_char rcor, rbpr, badspeed = 0; + unsigned long flags; + + save_flags(flags); cli(); + + /* + * First probe channel zero of the chip, to see what speed has + * been selected. + */ + + base_addr[CyCAR] = 0; + + rcor = base_addr[CyRCOR] << 5; + rbpr = base_addr[CyRBPR]; + + for (spd = 0; spd < sizeof(baud_bpr); spd++) + if (rbpr == baud_bpr[spd] && rcor == baud_co[spd]) + break; + if (spd >= sizeof(baud_bpr)) { + spd = 14; /* 19200 */ + badspeed = 1; /* Failed to identify speed */ + } + initial_console_speed = spd; + + /* OK, we have chosen a speed, now reset and reinitialise */ + + my_udelay(20000L); /* Allow time for any active o/p to complete */ + if(base_addr[CyCCR] != 0x00){ + /* printk(" chip is never idle (CCR != 0)\n"); */ + return; + } + + base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */ + my_udelay(1000L); + + if(base_addr[CyGFRCR] == 0x00){ + /* printk(" chip is not responding (GFRCR stayed 0)\n"); */ + return; + } + + /* + * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms + * tick + */ + + base_addr[CyTPR] = 10; + + base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */ + base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */ + base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */ + + /* + * Attempt to set up all channels to something reasonable, and + * bang out a INIT_CHAN command. We should then be able to limit + * the ammount of fiddling we have to do in normal running. + */ + + for (ch = 3; ch >= 0 ; ch--) { + base_addr[CyCAR] = (u_char)ch; + base_addr[CyIER] = 0; + base_addr[CyCMR] = CyASYNC; + base_addr[CyLICR] = (u_char)ch << 2; + base_addr[CyLIVR] = 0x5c; + base_addr[CyTCOR] = baud_co[spd]; + base_addr[CyTBPR] = baud_bpr[spd]; + base_addr[CyRCOR] = baud_co[spd] >> 5; + base_addr[CyRBPR] = baud_bpr[spd]; + base_addr[CySCHR1] = 'Q' & 0x1f; + base_addr[CySCHR2] = 'X' & 0x1f; + base_addr[CySCRL] = 0; + base_addr[CySCRH] = 0; + base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE; + base_addr[CyCOR2] = 0; + base_addr[CyCOR3] = Cy_1_STOP; + base_addr[CyCOR4] = baud_cor4[spd]; + base_addr[CyCOR5] = 0; + base_addr[CyCOR6] = 0; + base_addr[CyCOR7] = 0; + base_addr[CyRTPRL] = 2; + base_addr[CyRTPRH] = 0; + base_addr[CyMSVR1] = 0; + base_addr[CyMSVR2] = 0; + write_cy_cmd(base_addr,CyINIT_CHAN|CyDIS_RCVR|CyDIS_XMTR); + } + + /* + * Now do specials for channel zero.... + */ + + base_addr[CyMSVR1] = CyRTS; + base_addr[CyMSVR2] = CyDTR; + base_addr[CyIER] = CyRxData; + write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); + + restore_flags(flags); + + my_udelay(20000L); /* Let it all settle down */ + + printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]); + if (badspeed) + printk(" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n", + rcor >> 5, rbpr); +} /* serial_console_init */ + +/* The serial driver boot-time initialization code! + Hardware I/O ports are mapped to character special devices on a + first found, first allocated manner. That is, this code searches + for Cyclom cards in the system. As each is found, it is probed + to discover how many chips (and thus how many ports) are present. + These ports are mapped to the tty ports 64 and upward in monotonic + fashion. If an 8-port card is replaced with a 16-port card, the + port mapping on a following card will shift. + + This approach is different from what is used in the other serial + device driver because the Cyclom is more properly a multiplexer, + not just an aggregation of serial ports on one card. + + If there are more cards with more ports than have been statically + allocated above, a warning is printed and the extra ports are ignored. + */ +int +serial167_init(void) +{ + struct cyclades_port *info; + int good_ports = 0; + int port_num = 0; + int index; + int DefSpeed; +#ifdef notyet + struct sigaction sa; +#endif + + if (!(mvme16x_config &MVME16x_CONFIG_GOT_CD2401)) + return 0; + +#if 0 +scrn[1] = '\0'; +#endif + + show_version(); + + /* Has "console=0,9600n8" been used in bootinfo to change speed? */ + if (serial_console_cflag) + DefSpeed = serial_console_cflag & 0017; + else { + DefSpeed = initial_console_speed; + serial_console_info = &cy_port[0]; + serial_console_cflag = DefSpeed | CS8; +#if 0 + serial_console = 64; /*callout_driver.minor_start*/ +#endif + } + + /* Initialize the tty_driver structure */ + + memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); + cy_serial_driver.magic = TTY_DRIVER_MAGIC; + cy_serial_driver.name = "ttyS"; + cy_serial_driver.major = TTY_MAJOR; + cy_serial_driver.minor_start = 64; + cy_serial_driver.num = NR_PORTS; + cy_serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + cy_serial_driver.subtype = SERIAL_TYPE_NORMAL; + cy_serial_driver.init_termios = tty_std_termios; + cy_serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + cy_serial_driver.flags = TTY_DRIVER_REAL_RAW; + cy_serial_driver.refcount = &serial_refcount; + cy_serial_driver.table = serial_table; + cy_serial_driver.termios = serial_termios; + cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.open = cy_open; + cy_serial_driver.close = cy_close; + cy_serial_driver.write = cy_write; + cy_serial_driver.put_char = cy_put_char; + cy_serial_driver.flush_chars = cy_flush_chars; + cy_serial_driver.write_room = cy_write_room; + cy_serial_driver.chars_in_buffer = cy_chars_in_buffer; + cy_serial_driver.flush_buffer = cy_flush_buffer; + cy_serial_driver.ioctl = cy_ioctl; + cy_serial_driver.throttle = cy_throttle; + cy_serial_driver.unthrottle = cy_unthrottle; + cy_serial_driver.set_termios = cy_set_termios; + cy_serial_driver.stop = cy_stop; + cy_serial_driver.start = cy_start; + cy_serial_driver.hangup = cy_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + cy_callout_driver = cy_serial_driver; + cy_callout_driver.name = "cua"; + cy_callout_driver.major = TTYAUX_MAJOR; + cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (tty_register_driver(&cy_serial_driver)) + panic("Couldn't register Cyclom serial driver\n"); + if (tty_register_driver(&cy_callout_driver)) + panic("Couldn't register Cyclom callout driver\n"); + + init_bh(CYCLADES_BH, do_cyclades_bh); + + port_num = 0; + info = cy_port; + for (index = 0; index < 1; index++) { + + good_ports = 4; + + if(port_num < NR_PORTS){ + while( good_ports-- && port_num < NR_PORTS){ + /*** initialize port ***/ + info->magic = CYCLADES_MAGIC; + info->type = PORT_CIRRUS; + info->card = index; + info->line = port_num; + info->flags = STD_COM_FLAGS; + info->tty = 0; + info->xmit_fifo_size = 12; + info->cor1 = CyPARITY_NONE|Cy_8_BITS; + info->cor2 = CyETC; + info->cor3 = Cy_1_STOP; + info->cor4 = 0x08; /* _very_ small receive threshold */ + info->cor5 = 0; + info->cor6 = 0; + info->cor7 = 0; + info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */ + info->tco = baud_co[DefSpeed]; /* Tx CO */ + info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */ + info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */ + info->close_delay = 0; + info->x_char = 0; + info->event = 0; + info->count = 0; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc: %d: setting count to 0\n", __LINE__); +#endif + info->blocked_open = 0; + info->default_threshold = 0; + info->default_timeout = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios =cy_callout_driver.init_termios; + info->normal_termios = cy_serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + /* info->session */ + /* info->pgrp */ +/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/ + info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK + | CyPARITY| CyFRAME| CyOVERRUN; + /* info->timeout */ + + printk("ttyS%1d ", info->line); + port_num++;info++; + if(!(port_num & 7)){ + printk("\n "); + } + } + } + printk("\n"); + } + while( port_num < NR_PORTS){ + info->line = -1; + port_num++;info++; + } +#ifdef CONFIG_REMOTE_DEBUG + debug_setup(); +#endif + if (request_irq (MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0, + "cd2401_errors", cd2401_rxerr_interrupt) || + request_irq (MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0, + "cd2401_modem", cd2401_modem_interrupt) || + request_irq (MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0, + "cd2401_txints", cd2401_tx_interrupt) || + request_irq (MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0, + "cd2401_rxints", cd2401_rx_interrupt)) + { + panic ("Couldn't get serial IRQs"); + } + + /* Now we have registered the interrupt handlers, allow the interrupts */ + + pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */ + pcc2chip[PccSCCTICR] = 0x15; + pcc2chip[PccSCCRICR] = 0x15; + + pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */ + + return 0; +} /* serial167_init */ + + +#ifdef CYCLOM_SHOW_STATUS +static void +show_status(int line_num) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int channel; + struct cyclades_port * info; + unsigned long flags; + + info = &cy_port[line_num]; + channel = info->line; + printk(" channel %d\n", channel);/**/ + + printk(" cy_port\n"); + printk(" card line flags = %d %d %x\n", + info->card, info->line, info->flags); + printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n", + (long)info->tty, info->read_status_mask, + info->timeout, info->xmit_fifo_size); + printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n", + info->cor1, info->cor2, info->cor3, info->cor4, info->cor5, + info->cor6, info->cor7); + printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", + info->tbpr, info->tco, info->rbpr, info->rco); + printk(" close_delay event count = %d %d %d\n", + info->close_delay, info->event, info->count); + printk(" x_char blocked_open = %x %x\n", + info->x_char, info->blocked_open); + printk(" session pgrp open_wait = %lx %lx %lx\n", + info->session, info->pgrp, (long)info->open_wait); + + + save_flags(flags); cli(); + +/* Global Registers */ + + printk(" CyGFRCR %x\n", base_addr[CyGFRCR]); + printk(" CyCAR %x\n", base_addr[CyCAR]); + printk(" CyRISR %x\n", base_addr[CyRISR]); + printk(" CyTISR %x\n", base_addr[CyTISR]); + printk(" CyMISR %x\n", base_addr[CyMISR]); + printk(" CyRIR %x\n", base_addr[CyRIR]); + printk(" CyTIR %x\n", base_addr[CyTIR]); + printk(" CyMIR %x\n", base_addr[CyMIR]); + printk(" CyTPR %x\n", base_addr[CyTPR]); + + base_addr[CyCAR] = (u_char)channel; + +/* Virtual Registers */ + +#if 0 + printk(" CyRIVR %x\n", base_addr[CyRIVR]); + printk(" CyTIVR %x\n", base_addr[CyTIVR]); + printk(" CyMIVR %x\n", base_addr[CyMIVR]); + printk(" CyMISR %x\n", base_addr[CyMISR]); +#endif + +/* Channel Registers */ + + printk(" CyCCR %x\n", base_addr[CyCCR]); + printk(" CyIER %x\n", base_addr[CyIER]); + printk(" CyCOR1 %x\n", base_addr[CyCOR1]); + printk(" CyCOR2 %x\n", base_addr[CyCOR2]); + printk(" CyCOR3 %x\n", base_addr[CyCOR3]); + printk(" CyCOR4 %x\n", base_addr[CyCOR4]); + printk(" CyCOR5 %x\n", base_addr[CyCOR5]); +#if 0 + printk(" CyCCSR %x\n", base_addr[CyCCSR]); + printk(" CyRDCR %x\n", base_addr[CyRDCR]); +#endif + printk(" CySCHR1 %x\n", base_addr[CySCHR1]); + printk(" CySCHR2 %x\n", base_addr[CySCHR2]); +#if 0 + printk(" CySCHR3 %x\n", base_addr[CySCHR3]); + printk(" CySCHR4 %x\n", base_addr[CySCHR4]); + printk(" CySCRL %x\n", base_addr[CySCRL]); + printk(" CySCRH %x\n", base_addr[CySCRH]); + printk(" CyLNC %x\n", base_addr[CyLNC]); + printk(" CyMCOR1 %x\n", base_addr[CyMCOR1]); + printk(" CyMCOR2 %x\n", base_addr[CyMCOR2]); +#endif + printk(" CyRTPRL %x\n", base_addr[CyRTPRL]); + printk(" CyRTPRH %x\n", base_addr[CyRTPRH]); + printk(" CyMSVR1 %x\n", base_addr[CyMSVR1]); + printk(" CyMSVR2 %x\n", base_addr[CyMSVR2]); + printk(" CyRBPR %x\n", base_addr[CyRBPR]); + printk(" CyRCOR %x\n", base_addr[CyRCOR]); + printk(" CyTBPR %x\n", base_addr[CyTBPR]); + printk(" CyTCOR %x\n", base_addr[CyTCOR]); + + restore_flags(flags); +} /* show_status */ +#endif + + +#if 0 +/* Dummy routine in mvme16x/config.c for now */ + +/* Serial console setup. Called from linux/init/main.c */ + +void console_setup(char *str, int *ints) +{ + char *s; + int baud, bits, parity; + int cflag = 0; + + /* Sanity check. */ + if (ints[0] > 3 || ints[1] > 3) return; + + /* Get baud, bits and parity */ + baud = 2400; + bits = 8; + parity = 'n'; + if (ints[2]) baud = ints[2]; + if ((s = strchr(str, ','))) { + do { + s++; + } while(*s >= '0' && *s <= '9'); + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* Now construct a cflag setting. */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 2400: + default: + cflag |= B2400; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + + serial_console_info = &cy_port[ints[1]]; + serial_console_cflag = cflag; + serial_console = ints[1] + 64; /*callout_driver.minor_start*/ +} +#endif + +/* + * The following is probably out of date for 2.1.x serial console stuff. + * + * The console is registered early on from arch/m68k/kernel/setup.c, and + * it therefore relies on the chip being setup correctly by 166-Bug. This + * seems reasonable, as the serial port has been used to invoke the system + * boot. It also means that this function must not rely on any data + * initialisation performed by serial167_init() etc. + * + * Of course, once the console has been registered, we had better ensure + * that serial167_init() doesn't leave the chip non-functional. + */ + +void serial167_write(struct console *co, const char *str, unsigned count) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + volatile u_char sink; + u_char ier; + int port; + u_char do_lf = 0; + int i = 0; + + save_flags(flags); cli(); + + /* Ensure transmitter is enabled! */ + + port = 0; + base_addr[CyCAR] = (u_char)port; + while (base_addr[CyCCR]) + ; + base_addr[CyCCR] = CyENB_XMTR; + + ier = base_addr[CyIER]; + base_addr[CyIER] = CyTxMpty; + + while (1) { + if (pcc2chip[PccSCCTICR] & 0x20) + { + /* We have a Tx int. Acknowledge it */ + sink = pcc2chip[PccTPIACKR]; + if ((base_addr[CyLICR] >> 2) == port) { + if (i == count) { + /* Last char of string is now output */ + base_addr[CyTEOIR] = CyNOTRANS; + break; + } + if (do_lf) { + base_addr[CyTDR] = '\n'; + str++; + i++; + do_lf = 0; + } + else if (*str == '\n') { + base_addr[CyTDR] = '\r'; + do_lf = 1; + } + else { + base_addr[CyTDR] = *str++; + i++; + } + base_addr[CyTEOIR] = 0; + } + else + base_addr[CyTEOIR] = CyNOTRANS; + } + } + + base_addr[CyIER] = ier; + + restore_flags(flags); +} + +#ifdef CONFIG_REMOTE_DEBUG +void putDebugChar (int c) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + volatile u_char sink; + u_char ier; + int port; + + save_flags(flags); cli(); + + /* Ensure transmitter is enabled! */ + + port = DEBUG_PORT; + base_addr[CyCAR] = (u_char)port; + while (base_addr[CyCCR]) + ; + base_addr[CyCCR] = CyENB_XMTR; + + ier = base_addr[CyIER]; + base_addr[CyIER] = CyTxMpty; + + while (1) { + if (pcc2chip[PccSCCTICR] & 0x20) + { + /* We have a Tx int. Acknowledge it */ + sink = pcc2chip[PccTPIACKR]; + if ((base_addr[CyLICR] >> 2) == port) { + base_addr[CyTDR] = c; + base_addr[CyTEOIR] = 0; + break; + } + else + base_addr[CyTEOIR] = CyNOTRANS; + } + } + + base_addr[CyIER] = ier; + + restore_flags(flags); +} + +int getDebugChar() +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + volatile u_char sink; + u_char ier; + int port; + int i, c; + + i = debugiq.out; + if (i != debugiq.in) { + c = debugiq.buf[i]; + if (++i == DEBUG_LEN) + i = 0; + debugiq.out = i; + return c; + } + /* OK, nothing in queue, wait in poll loop */ + + save_flags(flags); cli(); + + /* Ensure receiver is enabled! */ + + port = DEBUG_PORT; + base_addr[CyCAR] = (u_char)port; +#if 0 + while (base_addr[CyCCR]) + ; + base_addr[CyCCR] = CyENB_RCVR; +#endif + ier = base_addr[CyIER]; + base_addr[CyIER] = CyRxData; + + while (1) { + if (pcc2chip[PccSCCRICR] & 0x20) + { + /* We have a Rx int. Acknowledge it */ + sink = pcc2chip[PccRPIACKR]; + if ((base_addr[CyLICR] >> 2) == port) { + int cnt = base_addr[CyRFOC]; + while (cnt-- > 0) + { + c = base_addr[CyRDR]; + if (c == 0) + printk ("!! debug char is null (cnt=%d) !!", cnt); + else + queueDebugChar (c); + } + base_addr[CyREOIR] = 0; + i = debugiq.out; + if (i == debugiq.in) + panic ("Debug input queue empty!"); + c = debugiq.buf[i]; + if (++i == DEBUG_LEN) + i = 0; + debugiq.out = i; + break; + } + else + base_addr[CyREOIR] = CyNOTRANS; + } + } + + base_addr[CyIER] = ier; + + restore_flags(flags); + + return (c); +} + +void queueDebugChar (int c) +{ + int i; + + i = debugiq.in; + debugiq.buf[i] = c; + if (++i == DEBUG_LEN) + i = 0; + if (i != debugiq.out) + debugiq.in = i; +} + +static void +debug_setup() +{ + unsigned long flags; + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + int i, cflag; + + cflag = B19200; + + save_flags(flags); cli(); + + for (i = 0; i < 4; i++) + { + base_addr[CyCAR] = i; + base_addr[CyLICR] = i << 2; + } + + debugiq.in = debugiq.out = 0; + + base_addr[CyCAR] = DEBUG_PORT; + + /* baud rate */ + i = cflag & CBAUD; + + base_addr[CyIER] = 0; + + base_addr[CyCMR] = CyASYNC; + base_addr[CyLICR] = DEBUG_PORT << 2; + base_addr[CyLIVR] = 0x5c; + + /* tx and rx baud rate */ + + base_addr[CyTCOR] = baud_co[i]; + base_addr[CyTBPR] = baud_bpr[i]; + base_addr[CyRCOR] = baud_co[i] >> 5; + base_addr[CyRBPR] = baud_bpr[i]; + + /* set line characteristics according configuration */ + + base_addr[CySCHR1] = 0; + base_addr[CySCHR2] = 0; + base_addr[CySCRL] = 0; + base_addr[CySCRH] = 0; + base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE; + base_addr[CyCOR2] = 0; + base_addr[CyCOR3] = Cy_1_STOP; + base_addr[CyCOR4] = baud_cor4[i]; + base_addr[CyCOR5] = 0; + base_addr[CyCOR6] = 0; + base_addr[CyCOR7] = 0; + + write_cy_cmd(base_addr,CyINIT_CHAN); + write_cy_cmd(base_addr,CyENB_RCVR); + + base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */ + + base_addr[CyRTPRL] = 2; + base_addr[CyRTPRH] = 0; + + base_addr[CyMSVR1] = CyRTS; + base_addr[CyMSVR2] = CyDTR; + + base_addr[CyIER] = CyRxData; + + restore_flags(flags); + +} /* debug_setup */ + +#endif diff -u --recursive --new-file v2.1.124/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.124/linux/drivers/char/tty_io.c Mon Oct 5 13:13:39 1998 +++ linux/drivers/char/tty_io.c Mon Oct 5 14:12:12 1998 @@ -2104,6 +2104,9 @@ #ifdef CONFIG_ROCKETPORT rp_init(); #endif +#ifdef CONFIG_MVME16x + serial167_init(); +#endif #ifdef CONFIG_CYCLADES cy_init(); #endif diff -u --recursive --new-file v2.1.124/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.1.124/linux/drivers/net/daynaport.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/net/daynaport.c Mon Oct 5 13:39:20 1998 @@ -50,14 +50,14 @@ static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void dayna_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, const int start_page); static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void sane_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, const int start_page); static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); diff -u --recursive --new-file v2.1.124/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.124/linux/drivers/net/de4x5.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/net/de4x5.c Mon Oct 5 13:02:58 1998 @@ -409,11 +409,17 @@ Fix lastPCI to correctly work with compiled in kernels and modules from bug report by et al. + 0.542 15-Sep-98 Fix dc2114x_autoconf() to stop multiple messages + when media is unconnected. + Change dev->interrupt to lp->interrupt to ensure + alignment for Alpha's and avoid their unaligned + access traps. This flag is merely for log messages: + should do something more definitive though... ========================================================================= */ -static const char *version = "de4x5.c:V0.541 1998/8/24 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.542 1998/9/15 davies@maniac.ultranet.com\n"; #include #include @@ -744,6 +750,7 @@ struct de4x5_private { char adapter_name[80]; /* Adapter name */ + u_long interrupt; /* Aligned ISR flag */ struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ @@ -1362,7 +1369,7 @@ dev->tbusy = 0; dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; + lp->interrupt = UNMASK_INTERRUPTS; dev->trans_start = jiffies; START_DE4X5; @@ -1506,12 +1513,12 @@ sti(); /* Test if cache is already locked - requeue skb if so */ - if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) + if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) return -1; /* Transmit descriptor ring full or stale skb */ if (dev->tbusy || lp->tx_skb[lp->tx_new]) { - if (dev->interrupt) { + if (lp->interrupt) { de4x5_putb_cache(dev, skb); /* Requeue the buffer */ } else { de4x5_put_cache(dev, skb); @@ -1521,7 +1528,7 @@ } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ - if (lp->cache.skb && !dev->interrupt) { + if (lp->cache.skb && !lp->interrupt) { de4x5_put_cache(dev, skb); skb = de4x5_get_cache(dev); } @@ -1576,10 +1583,11 @@ lp = (struct de4x5_private *)dev->priv; iobase = dev->base_addr; - if (test_and_set_bit(MASK_INTERRUPTS, (void*) &dev->interrupt)) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - DISABLE_IRQs; /* Ensure non re-entrancy */ + + if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt)) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + synchronize_irq(); for (limit=0; limit<8; limit++) { @@ -1618,7 +1626,7 @@ lp->cache.lock = 0; } - dev->interrupt = UNMASK_INTERRUPTS; + lp->interrupt = UNMASK_INTERRUPTS; ENABLE_IRQs; return; @@ -1748,7 +1756,7 @@ if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */ dev->tbusy = 0; /* Clear TX busy flag */ - if (dev->interrupt) mark_bh(NET_BH); + if (lp->interrupt) mark_bh(NET_BH); } return 0; @@ -2351,7 +2359,7 @@ s32 imr; switch (lp->media) { - case INIT: + case INIT: DISABLE_IRQs; lp->tx_enable = NO; lp->timeout = -1; @@ -2369,36 +2377,36 @@ next_tick = dc21040_autoconf(dev); break; - case TP: + case TP: next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, TP_SUSPECT, test_tp); break; - case TP_SUSPECT: + case TP_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); break; - case BNC: - case AUI: - case BNC_AUI: + case BNC: + case AUI: + case BNC_AUI: next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, BNC_AUI_SUSPECT, ping_media); break; - case BNC_AUI_SUSPECT: + case BNC_AUI_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); break; - case EXT_SIA: + case EXT_SIA: next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, NC, EXT_SIA_SUSPECT, ping_media); break; - case EXT_SIA_SUSPECT: + case EXT_SIA_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); break; - case NC: + case NC: /* default to TP for all */ reset_init_sia(dev, 0x8f01, 0xffff, 0x0000); if (lp->media != lp->c_media) { @@ -2423,13 +2431,13 @@ int linkBad; switch (lp->local_state) { - case 0: + case 0: reset_init_sia(dev, csr13, csr14, csr15); lp->local_state++; next_tick = 500; break; - case 1: + case 1: if (!lp->tx_enable) { linkBad = fn(dev, timeout); if (linkBad < 0) { @@ -2462,7 +2470,7 @@ int linkBad; switch (lp->local_state) { - case 1: + case 1: if (lp->linkOK) { lp->media = prev_state; } else { @@ -2471,7 +2479,7 @@ } break; - case 2: + case 2: linkBad = fn(dev, timeout); if (linkBad < 0) { next_tick = linkBad & ~TIMER_CB; @@ -2505,7 +2513,7 @@ int next_tick = DE4X5_AUTOSENSE_MS; switch (lp->media) { - case INIT: + case INIT: DISABLE_IRQs; lp->tx_enable = NO; lp->timeout = -1; @@ -2525,7 +2533,7 @@ next_tick = dc21041_autoconf(dev); break; - case TP_NW: + case TP_NW: if (lp->timeout < 0) { omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */ outl(omr | OMR_FDX, DE4X5_OMR); @@ -2545,7 +2553,7 @@ } break; - case ANS: + case ANS: if (!lp->tx_enable) { irqs = STS_LNP; irq_mask = IMR_LPM; @@ -2567,11 +2575,11 @@ } break; - case ANS_SUSPECT: + case ANS_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); break; - case TP: + case TP: if (!lp->tx_enable) { if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for TP */ @@ -2601,11 +2609,11 @@ } break; - case TP_SUSPECT: + case TP_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); break; - case AUI: + case AUI: if (!lp->tx_enable) { if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ @@ -2631,13 +2639,13 @@ } break; - case AUI_SUSPECT: + case AUI_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); break; - case BNC: + case BNC: switch (lp->local_state) { - case 0: + case 0: if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ outl(omr & ~OMR_FDX, DE4X5_OMR); @@ -2653,7 +2661,7 @@ } break; - case 1: + case 1: if (!lp->tx_enable) { if ((sts = ping_media(dev, 3000)) < 0) { next_tick = sts & ~TIMER_CB; @@ -2673,11 +2681,11 @@ } break; - case BNC_SUSPECT: + case BNC_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); break; - case NC: + case NC: omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ outl(omr | OMR_FDX, DE4X5_OMR); reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */ @@ -3081,9 +3089,9 @@ } next_tick = dc2114x_autoconf(dev); } else if (((lp->media == _100Mb) && is_100_up(dev)) || - ((lp->media == _10Mb) && is_10_up(dev)) || - (lp->media == TP) || - (lp->media == BNC) || (lp->media == AUI)) { + (((lp->media == _10Mb) || (lp->media == TP) || + (lp->media == BNC) || (lp->media == AUI)) && + is_10_up(dev))) { next_tick = dc2114x_autoconf(dev); } else { lp->tcount++; @@ -4049,7 +4057,7 @@ if (data == dev.Sig[0]) { /* rare case.... */ j=1; } else { - j=0; + j=0; } } } @@ -4121,8 +4129,10 @@ srom_repair(dev, broken); #ifdef CONFIG_PMAC - /* If the address starts with 00 a0, we have to bit-reverse - each byte of the address. */ + /* + ** If the address starts with 00 a0, we have to bit-reverse + ** each byte of the address. + */ if (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0xa0) { for (i = 0; i < ETH_ALEN; ++i) { int x = dev->dev_addr[i]; diff -u --recursive --new-file v2.1.124/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.124/linux/drivers/net/ppp.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/net/ppp.c Mon Oct 5 09:56:12 1998 @@ -4,7 +4,7 @@ * Al Longyear * Extensively rewritten by Paul Mackerras * - * ==FILEVERSION 980704== + * ==FILEVERSION 981004== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -115,6 +115,7 @@ static void ppp_output_wakeup(struct ppp *ppp); static void ppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); +static void ppp_send_frames(struct ppp *ppp); static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb); static struct ppp *ppp_find (int pid_value); @@ -439,6 +440,8 @@ return; if (ppp->backup_tty) { ppp->tty = ppp->backup_tty; + if (ppp_tty_push(ppp)) + ppp_output_wakeup(ppp); } else { ppp->tty = 0; ppp->sc_xfer = 0; @@ -448,7 +451,6 @@ ppp_async_release(ppp); ppp_release(ppp); - ppp->inuse = 0; MOD_DEC_USE_COUNT; } } @@ -2113,8 +2115,8 @@ /* * Compress and send an frame to the peer. - * Should be called with dev->tbusy == 1, having been set by the caller. - * That is, we use dev->tbusy as a lock to prevent reentry of this + * Should be called with xmit_busy == 1, having been set by the caller. + * That is, we use xmit_busy as a lock to prevent reentry of this * procedure. */ static void @@ -2186,7 +2188,7 @@ if (new_skb == NULL) { printk(KERN_ERR "ppp_send_frame: no memory\n"); kfree_skb(skb); - ppp->dev.tbusy = 0; + ppp->xmit_busy = 0; return; } @@ -2215,9 +2217,9 @@ ret = ppp_async_send(ppp, skb); if (ret > 0) { /* we can release the lock */ - ppp->dev.tbusy = 0; + ppp->xmit_busy = 0; } else if (ret < 0) { - /* this can't happen, since the caller got the tbusy lock */ + /* can't happen, since the caller got the xmit_busy lock */ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n"); } } @@ -2276,15 +2278,18 @@ { struct sk_buff *skb; - while (!test_and_set_bit(0, &ppp->dev.tbusy)) { + while (!test_and_set_bit(0, &ppp->xmit_busy)) { skb = skb_dequeue(&ppp->xmt_q); if (skb == NULL) { - ppp->dev.tbusy = 0; - mark_bh(NET_BH); + ppp->xmit_busy = 0; break; } ppp_send_frame(ppp, skb); } + if (!ppp->xmit_busy && ppp->dev.tbusy) { + ppp->dev.tbusy = 0; + mark_bh(NET_BH); + } } /* @@ -2296,11 +2301,11 @@ { CHECK_PPP_VOID(); - if (!ppp->dev.tbusy) { - printk(KERN_ERR "ppp_output_wakeup called but tbusy==0\n"); + if (!ppp->xmit_busy) { + printk(KERN_ERR "ppp_output_wakeup called but xmit_busy==0\n"); return; } - ppp->dev.tbusy = 0; + ppp->xmit_busy = 0; ppp_send_frames(ppp); } @@ -2425,9 +2430,15 @@ * The dev->tbusy field acts as a lock to allow only * one packet to be processed at a time. If we can't * get the lock, try again later. + * We deliberately queue as little as possible inside + * the ppp driver in order to minimize the latency + * for high-priority packets. */ - if (test_and_set_bit(0, &dev->tbusy)) + if (test_and_set_bit(0, &ppp->xmit_busy)) { + dev->tbusy = 1; /* can't take it now */ return 1; + } + dev->tbusy = 0; /* * Put the 4-byte PPP header on the packet. @@ -2441,7 +2452,8 @@ printk(KERN_ERR "%s: skb hdr alloc failed\n", ppp->name); dev_kfree_skb(skb); - dev->tbusy = 0; + ppp->xmit_busy = 0; + ppp_send_frames(ppp); return 0; } skb_reserve(new_skb, PPP_HDRLEN); @@ -2457,6 +2469,8 @@ hdr[3] = proto; ppp_send_frame(ppp, skb); + if (!ppp->xmit_busy) + ppp_send_frames(ppp); return 0; } @@ -2600,6 +2614,7 @@ ppp->last_xmit = jiffies; ppp->last_recv = jiffies; + ppp->xmit_busy = 0; /* clear statistics */ memset(&ppp->stats, 0, sizeof (struct pppstat)); @@ -2640,6 +2655,12 @@ kfree_skb(skb); while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL) kfree_skb(skb); + + ppp->inuse = 0; + if (ppp->dev.tbusy) { + ppp->dev.tbusy = 0; + mark_bh(NET_BH); + } } /* diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.1.124/linux/drivers/scsi/53c7xx.c Mon Aug 3 12:45:46 1998 +++ linux/drivers/scsi/53c7xx.c Mon Oct 5 13:43:31 1998 @@ -325,6 +325,7 @@ static int disable (struct Scsi_Host *host); static int NCR53c7xx_run_tests (struct Scsi_Host *host); static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); +static void NCR53c7x0_intfly (struct Scsi_Host *host); static int ncr_halt (struct Scsi_Host *host); static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd); @@ -847,7 +848,6 @@ unsigned char revision; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; - struct Scsi_Host *search; /* * There are some things which we need to know about in order to provide * a semblance of support. Print 'em if they aren't what we expect, @@ -1072,26 +1072,13 @@ NCR53c7x0_driver_init (host); - /* - * Set up an interrupt handler if we aren't already sharing an IRQ - * with another board. - */ - - for (search = first_host; search && !(search->hostt == the_template && - search->irq == host->irq && search != host); search=search->next); - - if (!search) { - if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) - { - printk("scsi%d : IRQ%d not free, detaching\n", + if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", host)) + { + printk("scsi%d : IRQ%d not free, detaching\n", host->host_no, host->irq); - scsi_unregister (host); - return -1; - } - } else { - printk("scsi%d : using interrupt handler previously installed for scsi%d\n", - host->host_no, search->host_no); - } + scsi_unregister (host); + return -1; + } if ((hostdata->run_tests && hostdata->run_tests(host) == -1) || (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) { @@ -2509,18 +2496,7 @@ abnormal_finished (cmd, DID_ERROR << 16); return SPECIFIC_INT_NOTHING; case A_int_norm_emulateintfly: - /* I'm not sure this is the right ! thing to do, but it works - * with the A4000T when copyback is disabled, and also the - * WarpEngine with copyback enabled, so it looks as though - * it does work to some extent. - * - * RGH: I don't really like it - You get an interrupt which - * calls NCR53c7x0_intr(), which calls this function (via - * intr_dma()), which calls NCR53c7x0_intr()..... - * Anyway let's see how it goes for now. - */ - hostdata->emulated_intfly = 1; - NCR53c7x0_intr(host->irq, NULL, NULL); + NCR53c7x0_intfly(host); return SPECIFIC_INT_NOTHING; case A_int_test_1: case A_int_test_2: @@ -4141,288 +4117,230 @@ } #endif + /* - * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) + * Function : static void NCR53c7x0_intfly (struct Scsi_Host *host) * - * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing - * the same IRQ line. + * Purpose : Scan command queue for specified host, looking for completed + * commands. * - * Inputs : Since we're using the SA_INTERRUPT interrupt handler - * semantics, irq indicates the interrupt which invoked - * this handler. + * Inputs : Scsi_Host pointer. * - * On the 710 we simualte an INTFLY with a script interrupt, and the - * script interrupt handler will call back to this function. + * This is called from the interrupt handler, when a simulated INTFLY + * interrupt occurs. */ -static void -NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) { +static void +NCR53c7x0_intfly (struct Scsi_Host *host) +{ NCR53c7x0_local_declare(); - struct Scsi_Host *host; /* Host we are looking at */ - unsigned char istat; /* Values of interrupt regs */ struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */ struct NCR53c7x0_cmd *cmd, /* command which halted */ **cmd_prev_ptr; - u32 *dsa; /* DSA */ - int done = 1; /* Indicates when handler - should terminate */ - int interrupted = 0; /* This HA generated - an interrupt */ - int have_intfly; /* Don't print warning - messages when we stack - INTFLYs */ unsigned long flags; + char search_found = 0; /* Got at least one ? */ -#ifdef NCR_DEBUG - char buf[80]; /* Debugging sprintf buffer */ - size_t buflen; /* Length of same */ -#endif - -#if defined(CONFIG_AMIGA) - custom.intena = IF_PORTS; -#endif - - do { - done = 1; - for (host = first_host; host; host = host->next) - if (host->hostt == the_template -#if defined(MVME16x_INTFLY) - /* We have two different interrupts pointing - * at this routine, so remove this check */ -#else - && host->irq == irq -#endif - ) { - NCR53c7x0_local_setup(host); + hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; + NCR53c7x0_local_setup(host); - hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; - hostdata->dsp_changed = 0; - interrupted = 0; - have_intfly = 0; - - do { - hostdata->dstat_valid = 0; - interrupted = 0; - /* - * Only read istat once, since reading it again will unstack - * interrupts? - */ - istat = NCR53c7x0_read8(hostdata->istat); - - if ((hostdata->options & OPTION_INTFLY) && -#ifdef MVME16x_INTFLY - /* the bit is set which indicates an on-the-fly int */ - (*(volatile unsigned long *)0xfff40068 & 0x8000)) -#else - (hostdata->emulated_intfly != 0)) -#endif - { - char search_found = 0; /* Got at least one ? */ - done = 0; - interrupted = 1; + if (hostdata->options & OPTION_DEBUG_INTR) + printk ("scsi%d : INTFLY\n", host->host_no); -#ifdef MVME16x_INTFLY - /* clear the INTFLY bit */ - *(volatile unsigned long *)0xfff40074 = 0x8000; -#endif + /* + * Traverse our list of running commands, and look + * for those with valid (non-0xff ff) status and message + * bytes encoded in the result which signify command + * completion. + */ - if (hostdata->options & OPTION_DEBUG_INTR) - printk ("scsi%d : INTFLY\n", host->host_no); + save_flags(flags); + cli(); +restart: + for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list), + cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ; + cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), + cmd = (struct NCR53c7x0_cmd *) cmd->next) + { + Scsi_Cmnd *tmp; - /* - * Traverse our list of running commands, and look - * for those with valid (non-0xff ff) status and message - * bytes encoded in the result which signify command - * completion. - */ + if (!cmd) { + printk("scsi%d : very weird.\n", host->host_no); + break; + } + if (!(tmp = cmd->cmd)) { + printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n", + host->host_no); + continue; + } + /* Copy the result over now; may not be complete, + * but subsequent tests may as well be done on + * cached memory. + */ + tmp->result = cmd->result; - save_flags(flags); - cli(); -restart: - for (cmd_prev_ptr = (struct NCR53c7x0_cmd **) - &(hostdata->running_list), cmd = - (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ; - cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), - cmd = (struct NCR53c7x0_cmd *) cmd->next) { - Scsi_Cmnd *tmp; - - if (!cmd) { - printk("scsi%d : very weird.\n", host->host_no); - break; - } - - if (!(tmp = cmd->cmd)) { - printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n", - host->host_no); - continue; - } - /* Copy the result over now; may not be complete, - * but subsequent tests may as well be done on - * cached memory. - */ - tmp->result = cmd->result; -#if 0 - printk ("scsi%d : looking at result of 0x%x\n", - host->host_no, cmd->cmd->result); -#endif - - if (((tmp->result & 0xff) == 0xff) || + if (((tmp->result & 0xff) == 0xff) || ((tmp->result & 0xff00) == 0xff00)) - continue; + continue; - search_found = 1; + search_found = 1; - if (cmd->bounce.len) - memcpy ((void *)cmd->bounce.addr, + if (cmd->bounce.len) + memcpy ((void *)cmd->bounce.addr, (void *)cmd->bounce.buf, cmd->bounce.len); - /* Important - remove from list _before_ done is called */ - if (cmd_prev_ptr) - *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next; - - --hostdata->busy[tmp->target][tmp->lun]; - cmd->next = hostdata->free; - hostdata->free = cmd; - - tmp->host_scribble = NULL; - - if (hostdata->options & OPTION_DEBUG_INTR) { - printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", - host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result); - print_command (tmp->cmnd); - } + /* Important - remove from list _before_ done is called */ + if (cmd_prev_ptr) + *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next; -#if 0 - hostdata->options &= ~OPTION_DEBUG_INTR; -#endif - tmp->scsi_done(tmp); - goto restart; + --hostdata->busy[tmp->target][tmp->lun]; + cmd->next = hostdata->free; + hostdata->free = cmd; - } - restore_flags(flags); - - if (!search_found && !have_intfly) { - printk ("scsi%d : WARNING : INTFLY with no completed commands.\n", - host->host_no); - } else if (!have_intfly) { - have_intfly = 1; - run_process_issue_queue(); - } - } + tmp->host_scribble = NULL; - if (hostdata->emulated_intfly) - { - hostdata->emulated_intfly = 0; - return; - } + if (hostdata->options & OPTION_DEBUG_INTR) { + printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", + host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result); + print_command (tmp->cmnd); + } - if (istat & (ISTAT_SIP|ISTAT_DIP)) { - done = 0; - interrupted = 1; - hostdata->state = STATE_HALTED; + tmp->scsi_done(tmp); + goto restart; + } + restore_flags(flags); - if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) - printk ("scsi%d : SCSI FIFO not empty\n", + if (!search_found) { + printk ("scsi%d : WARNING : INTFLY with no completed commands.\n", host->host_no); + } else { + run_process_issue_queue(); + } + return; +} - /* - * NCR53c700 and NCR53c700-66 change the current SCSI - * process, hostdata->ncrcurrent, in the Linux driver so - * cmd = hostdata->ncrcurrent. - * - * With other chips, we must look through the commands - * executing and find the command structure which - * corresponds to the DSA register. - */ - - if (hostdata->options & OPTION_700) { - cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent; - } else { - dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG)); - for (cmd = (struct NCR53c7x0_cmd *) - hostdata->running_list; cmd && - (dsa + (hostdata->dsa_start / sizeof(u32))) != - cmd->dsa; - cmd = (struct NCR53c7x0_cmd *)(cmd->next)); - } - if (hostdata->options & OPTION_DEBUG_INTR) { - if (cmd) { - printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", - host->host_no, cmd->cmd->pid, (int) cmd->cmd->target, - (int) cmd->cmd->lun); - print_command (cmd->cmd->cmnd); - } else { - printk("scsi%d : no active command\n", host->host_no); - } - } +/* + * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) + * + * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing + * the same IRQ line. + * + * Inputs : Since we're using the SA_INTERRUPT interrupt handler + * semantics, irq indicates the interrupt which invoked + * this handler. + * + * On the 710 we simualte an INTFLY with a script interrupt, and the + * script interrupt handler will call back to this function. + */ - if (istat & ISTAT_SIP) { - if (hostdata->options & OPTION_DEBUG_INTR) - printk ("scsi%d : ISTAT_SIP\n", host->host_no); - intr_scsi (host, cmd); - } - - if (istat & ISTAT_DIP) { - if (hostdata->options & OPTION_DEBUG_INTR) - printk ("scsi%d : ISTAT_DIP\n", host->host_no); - intr_dma (host, cmd); - } +static void +NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) { + NCR53c7x0_local_declare(); + struct Scsi_Host *host; /* Host we are looking at */ + unsigned char istat; /* Values of interrupt regs */ + struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */ + struct NCR53c7x0_cmd *cmd; /* command which halted */ + u32 *dsa; /* DSA */ - if (!hostdata->dstat_valid) { - hostdata->dstat = NCR53c7x0_read8(DSTAT_REG); - hostdata->dstat_valid = 1; - } +#ifdef NCR_DEBUG + char buf[80]; /* Debugging sprintf buffer */ + size_t buflen; /* Length of same */ +#endif - if (!(hostdata->dstat & DSTAT_DFE)) { - printk ("scsi%d : DMA FIFO not empty\n", host->host_no); - /* Really need to check this out for 710 RGH */ - NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF); - while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF); - hostdata->dstat |= DSTAT_DFE; - } - } - } while (interrupted); + host = (struct Scsi_Host *)dev_id; + hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; + NCR53c7x0_local_setup(host); + /* + * Only read istat once per loop, since reading it again will unstack + * interrupts + */ + while ((istat = NCR53c7x0_read8(hostdata->istat)) & (ISTAT_SIP|ISTAT_DIP)) { + hostdata->dsp_changed = 0; + hostdata->dstat_valid = 0; + hostdata->state = STATE_HALTED; - if (hostdata->intrs != -1) - hostdata->intrs++; -#if 0 - if (hostdata->intrs > 40) { - printk("scsi%d : too many interrupts, halting", host->host_no); - disable(host); + if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) + printk ("scsi%d : SCSI FIFO not empty\n", host->host_no); + + /* + * NCR53c700 and NCR53c700-66 change the current SCSI + * process, hostdata->ncrcurrent, in the Linux driver so + * cmd = hostdata->ncrcurrent. + * + * With other chips, we must look through the commands + * executing and find the command structure which + * corresponds to the DSA register. + */ + + if (hostdata->options & OPTION_700) { + cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent; + } else { + dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG)); + for (cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; + cmd && (dsa + (hostdata->dsa_start / sizeof(u32))) != cmd->dsa; + cmd = (struct NCR53c7x0_cmd *)(cmd->next)) + ; + } + if (hostdata->options & OPTION_DEBUG_INTR) { + if (cmd) { + printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", + host->host_no, cmd->cmd->pid, (int) cmd->cmd->target, + (int) cmd->cmd->lun); + print_command (cmd->cmd->cmnd); + } else { + printk("scsi%d : no active command\n", host->host_no); } -#endif + } + + if (istat & ISTAT_SIP) { + if (hostdata->options & OPTION_DEBUG_INTR) + printk ("scsi%d : ISTAT_SIP\n", host->host_no); + intr_scsi (host, cmd); + } + + if (istat & ISTAT_DIP) { + if (hostdata->options & OPTION_DEBUG_INTR) + printk ("scsi%d : ISTAT_DIP\n", host->host_no); + intr_dma (host, cmd); + } + + if (!hostdata->dstat_valid) { + hostdata->dstat = NCR53c7x0_read8(DSTAT_REG); + hostdata->dstat_valid = 1; + } + + if (!(hostdata->dstat & DSTAT_DFE)) { + printk ("scsi%d : DMA FIFO not empty\n", host->host_no); + /* Really need to check this out for 710 RGH */ + NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF); + while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF) + ; + hostdata->dstat |= DSTAT_DFE; + } - if (!hostdata->idle && hostdata->state == STATE_HALTED) { - if (!hostdata->dsp_changed) { - hostdata->dsp = (u32 *) - bus_to_virt(NCR53c7x0_read32(DSP_REG)); - } - + if (!hostdata->idle && hostdata->state == STATE_HALTED) { + if (!hostdata->dsp_changed) + hostdata->dsp = (u32 *)bus_to_virt(NCR53c7x0_read32(DSP_REG)); #if 0 - printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n", - host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp); + printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n", + host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp); #endif - hostdata->state = STATE_RUNNING; - NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp)); - if (hostdata->options & OPTION_DEBUG_TRACE) { + hostdata->state = STATE_RUNNING; + NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp)); + if (hostdata->options & OPTION_DEBUG_TRACE) { #ifdef CYCLIC_TRACE - log_insn (hostdata->dsp); + log_insn (hostdata->dsp); #else - print_insn (host, hostdata->dsp, "t ", 1); + print_insn (host, hostdata->dsp, "t ", 1); #endif - NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | - DCNTL_SSM | DCNTL_STD); - } + NCR53c7x0_write8 (DCNTL_REG, + hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); } } - } while (!done); -#ifdef CONFIG_AMIGA - custom.intena = IF_SETCLR | IF_PORTS; -#endif + } } diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.124/linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Jul 21 00:15:31 1998 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Oct 5 13:40:23 1998 @@ -1,4 +1,26 @@ -Sar Jul 18 13:00 1998 Gerard Roudier (groudier@club-internet.fr) +Sun Oct 4 14:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.0i + - Cosmetic changes for sparc (but not for the driver) that needs + __irq_itoa() to be used for printed IRQ value to be understandable. + - Some problems with the driver that didn't occur using driver 2.5f + were due to a SCSI selection problem triggered by a clearly + documented feature that in fact seems not to work: (53C8XX chips + are claimed by the manuals to be able to execute SCSI scripts just + after abitration while the SCSI core is performing SCSI selection). + This optimization is broken and has been removed. + - Some broken scsi devices are confused when a negotiation is started + on a LUN that does not correspond to a real device. According to + SCSI specs, this is a device firmware bug. This has been worked + around by only starting negotiation if the LUN has previously be + used for at least 1 successful SCSI command. + - The 'last message sent' printed out on M_REJECT message reception + was read from the SFBR i/o register after the previous message had + been sent. + This was not correct and affects all previous driver versions and + the original FreeBSD one as well. The SCSI scripts has been fixed + so that it now provides the right information to the C code. + +Sat Jul 18 13:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.0g - Preliminary fixes for Big Endian (sent by Eddie C. Dost). Big Endian architectures should work again with the driver. diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.124/linux/drivers/scsi/Makefile Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/Makefile Mon Oct 5 13:43:31 1998 @@ -147,6 +147,14 @@ endif endif +ifeq ($(CONFIG_BLZ603EPLUS_SCSI),y) +L_OBJS += amiga7xx.o 53c7xx.o +else + ifeq ($(CONFIG_BLZ603EPLUS_SCSI),m) + M_OBJS += amiga7xx.o 53c7xx.o + endif +endif + ifeq ($(CONFIG_WARPENGINE_SCSI),y) L_OBJS += amiga7xx.o 53c7xx.o else diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/amiga7xx.c linux/drivers/scsi/amiga7xx.c --- v2.1.124/linux/drivers/scsi/amiga7xx.c Mon Aug 3 12:45:46 1998 +++ linux/drivers/scsi/amiga7xx.c Mon Oct 5 13:43:31 1998 @@ -50,6 +50,28 @@ tpnt->proc_dir = &proc_scsi_amiga7xx; +#ifdef CONFIG_BLZ603EPLUS_SCSI + if ((key = zorro_find(ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, 0, 0))) + { + cd = zorro_get_board(key); +/* + unsigned long address; + address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr, + cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL); +*/ + options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; + + clock = 50000000; /* 50MHz SCSI Clock */ + + ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(0x80f40000), + 0, IRQ_AMIGA_PORTS, DMA_NONE, + options, clock); + + zorro_config_board(key, 0); + num++; + } +#endif + #ifdef CONFIG_WARPENGINE_SCSI if ((key = zorro_find(ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, 0, 0))) { diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c --- v2.1.124/linux/drivers/scsi/blz1230.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/blz1230.c Mon Oct 5 13:43:31 1998 @@ -131,7 +131,7 @@ /* Set the command buffer */ esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer); + esp->esp_command_dvma = virt_to_bus((unsigned long) cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c --- v2.1.124/linux/drivers/scsi/blz2060.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/blz2060.c Mon Oct 5 13:43:31 1998 @@ -107,7 +107,7 @@ /* Set the command buffer */ esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer); + esp->esp_command_dvma = virt_to_bus((unsigned long) cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c --- v2.1.124/linux/drivers/scsi/cyberstorm.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/cyberstorm.c Mon Oct 5 13:43:31 1998 @@ -127,7 +127,7 @@ /* Set the command buffer */ esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer); + esp->esp_command_dvma = virt_to_bus((unsigned long) cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c --- v2.1.124/linux/drivers/scsi/cyberstormII.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/cyberstormII.c Mon Oct 5 13:43:31 1998 @@ -118,7 +118,7 @@ /* Set the command buffer */ esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer); + esp->esp_command_dvma = virt_to_bus((unsigned long) cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c --- v2.1.124/linux/drivers/scsi/fastlane.c Mon Aug 3 12:45:46 1998 +++ linux/drivers/scsi/fastlane.c Mon Oct 5 13:43:31 1998 @@ -163,7 +163,7 @@ /* Set the command buffer */ esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer); + esp->esp_command_dvma = virt_to_bus((unsigned long) cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.1.124/linux/drivers/scsi/hosts.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/hosts.c Mon Oct 5 13:47:23 1998 @@ -41,7 +41,15 @@ #include "hosts.h" -#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI) || defined (CONFIG_GVP_TURBO_SCSI) +#if defined(CONFIG_A4000T_SCSI) || \ + defined(CONFIG_WARPENGINE_SCSI) || \ + defined(CONFIG_A4091_SCSI) || \ + defined (CONFIG_GVP_TURBO_SCSI) || \ + defined (CONFIG_BLZ603E) +#define AMIGA7XXCONFIG +#endif + +#ifdef AMIGA7XXCONFIG #include "amiga7xx.h" #endif @@ -317,7 +325,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] = { #ifdef CONFIG_AMIGA -#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI) || defined (CONFIG_GVP_TURBO_SCSI) +#ifdef AMIGA7XXCONFIG AMIGA7XX_SCSI, #endif #ifdef CONFIG_A3000_SCSI diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.124/linux/drivers/scsi/ncr53c8xx.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/scsi/ncr53c8xx.c Mon Oct 5 13:40:23 1998 @@ -73,7 +73,7 @@ */ /* -** 16 July 1998, version 3.0g +** October 4 1998, version 3.0i ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -584,6 +584,7 @@ #endif #ifdef __sparc__ +#include #define remap_pci_mem(base, size) ((vm_offset_t) __va(base)) #define unmap_pci_mem(vaddr, size) #define pcivtophys(p) ((p) & pci_dvma_mask) @@ -2011,9 +2012,9 @@ ncrcmd start [ 5]; ncrcmd startpos [ 1]; ncrcmd select [ 6]; - ncrcmd select2 [ 7]; + ncrcmd select2 [ 9]; ncrcmd loadpos [ 4]; - ncrcmd send_ident [ 7]; + ncrcmd send_ident [ 9]; ncrcmd prepare [ 6]; ncrcmd prepare2 [ 7]; #ifdef SCSI_NCR_PROFILE_SUPPORT @@ -2340,6 +2341,15 @@ */ /* + ** The M_REJECT problem seems to be due to a selection + ** timing problem. + ** Wait immediately for the selection to complete. + ** (2.5x behaves so) + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + 0, + + /* ** Next time use the next slot. */ SCR_COPY (4), @@ -2384,8 +2394,10 @@ offsetof (struct dsb, smsg), SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), PADDRH (resend_ident), + SCR_LOAD_REG (scratcha, 0x80), + 0, SCR_COPY (1), - RADDR (sfbr), + RADDR (scratcha), NADDR (lastmsg), }/*-------------------------< PREPARE >----------------------*/,{ /* @@ -2818,7 +2830,7 @@ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, NADDR (msgout), SCR_COPY (1), - RADDR (sfbr), + NADDR (msgout), NADDR (lastmsg), /* ** If it was no ABORT message ... @@ -3343,7 +3355,7 @@ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, NADDR (msgout), SCR_COPY (1), - RADDR (sfbr), + NADDR (msgout), NADDR (lastmsg), SCR_JUMP, PADDR (msg_out_done), @@ -3399,7 +3411,7 @@ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, NADDR (msgout), SCR_COPY (1), - RADDR (sfbr), + NADDR (msgout), NADDR (lastmsg), SCR_JUMP, PADDR (msg_out_done), @@ -3504,7 +3516,7 @@ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, NADDR (msgout), SCR_COPY (1), - RADDR (sfbr), + NADDR (msgout), NADDR (lastmsg), SCR_CLR (SCR_ACK|SCR_ATN), 0, @@ -4492,9 +4504,9 @@ int i; #ifdef __sparc__ -printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n", +printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%s\n", device->chip.name, unit, device->chip.revision_id, device->slot.base, - device->slot.io_port, device->slot.irq); + device->slot.io_port, __irq_itoa(device->slot.irq)); #else printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n", device->chip.name, unit, device->chip.revision_id, device->slot.base, @@ -4696,15 +4708,25 @@ #ifdef SCSI_NCR_SHARE_IRQ #define NCR_SA_INTERRUPT_FLAGS (SA_INTERRUPT | SA_SHIRQ) if (bootverbose > 1) +#ifdef __sparc__ + printk(KERN_INFO "%s: requesting shared irq %s (dev_id=0x%lx)\n", + ncr_name(np), __irq_itoa(device->slot.irq), (u_long) np); +#else printk(KERN_INFO "%s: requesting shared irq %d (dev_id=0x%lx)\n", ncr_name(np), device->slot.irq, (u_long) np); +#endif #else #define NCR_SA_INTERRUPT_FLAGS SA_INTERRUPT #endif if (request_irq(device->slot.irq, ncr53c8xx_intr, NCR_SA_INTERRUPT_FLAGS, "ncr53c8xx", np)) { +#ifdef __sparc__ + printk(KERN_ERR "%s: request irq %s failure\n", + ncr_name(np), __irq_itoa(device->slot.irq)); +#else printk(KERN_ERR "%s: request irq %d failure\n", ncr_name(np), device->slot.irq); +#endif goto attach_error; } np->irq = device->slot.irq; @@ -4794,7 +4816,8 @@ if (np->irq) { #ifdef DEBUG_NCR53C8XX #ifdef __sparc__ - printk(KERN_INFO "%s: freeing irq 0x%x\n", ncr_name(np), np->irq); + printk(KERN_INFO "%s: freeing irq %s\n", ncr_name(np), + __irq_itoa(np->irq)); #else printk(KERN_INFO "%s: freeing irq %d\n", ncr_name(np), np->irq); #endif @@ -4951,7 +4974,7 @@ nego = 0; - if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) { /* ** negotiate wide transfers ? @@ -5610,8 +5633,12 @@ */ #ifdef DEBUG_NCR53C8XX +#ifdef __sparc__ + printk("%s: freeing irq %s\n", ncr_name(np), __irq_itoa(np->irq)); +#else printk("%s: freeing irq %d\n", ncr_name(np), np->irq); #endif +#endif free_irq(np->irq, np); /* @@ -5866,7 +5893,8 @@ if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { u_char * p = (u_char*) & cmd->sense_buffer; int i; - printk ("\n%s: sense data:", ncr_name (np)); + PRINT_ADDR(cmd); + printk ("sense data:"); for (i=0; i<14; i++) printk (" %x", *p++); printk (".\n"); } @@ -9792,7 +9820,7 @@ } if ((chip->features & FE_CLSE) && !cache_line_size) { - cache_line_size = 16; + cache_line_size = CACHE_LINE_SIZE; if (initverbose >= 2) printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size); pcibios_write_config_byte(bus, device_fn, @@ -10715,7 +10743,11 @@ copy_info(&info, "revision id 0x%x\n", np->revision_id); copy_info(&info, " IO port address 0x%lx, ", (u_long) np->port); +#ifdef __sparc__ + copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq)); +#else copy_info(&info, "IRQ number %d\n", (int) np->irq); +#endif #ifndef NCR_IOMAPPED if (np->reg) diff -u --recursive --new-file v2.1.124/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.1.124/linux/drivers/scsi/ncr53c8xx.h Fri Jul 31 17:07:58 1998 +++ linux/drivers/scsi/ncr53c8xx.h Mon Oct 5 17:34:44 1998 @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.0g" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.0i" /* ** Check supported Linux versions diff -u --recursive --new-file v2.1.124/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.1.124/linux/drivers/video/amifb.c Mon Oct 5 13:13:41 1998 +++ linux/drivers/video/amifb.c Mon Oct 5 12:24:34 1998 @@ -61,6 +61,7 @@ #include #include +#include