## Automatically generated incremental diff ## From: linux-2.4.22-bk4 ## To: linux-2.4.22-bk5 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.4.22-bk4/Documentation/Configure.help linux-2.4.22-bk5/Documentation/Configure.help --- linux-2.4.22-bk4/Documentation/Configure.help 2003-08-30 02:51:13.000000000 -0700 +++ linux-2.4.22-bk5/Documentation/Configure.help 2003-08-30 02:51:16.000000000 -0700 @@ -2037,6 +2037,17 @@ The board uses the R4300 and a R5230 CPUs. For more information about this board see . +SGI SN2 L1 serial port support +CONFIG_SGI_L1_SERIAL + If you have an SGI SN2 and you want to use the serial port connected + to the system controller (you want this!), say Y. Otherwise, say N. + +SGI SN2 L1 serial console support +CONFIG_SGI_L1_SERIAL_CONSOLE + If you have an SGI SN2 and you would like to use the system + controller serial port as your console (you want this!), say Y. + Otherwise, say N. + Support for BAGET MIPS series CONFIG_BAGET_MIPS This enables support for the Baget, a Russian embedded system. For diff -urN linux-2.4.22-bk4/Documentation/networking/00-INDEX linux-2.4.22-bk5/Documentation/networking/00-INDEX --- linux-2.4.22-bk4/Documentation/networking/00-INDEX 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.22-bk5/Documentation/networking/00-INDEX 2003-08-30 02:51:16.000000000 -0700 @@ -97,8 +97,8 @@ sis900.txt - SiS 900/7016 Fast Ethernet device driver info. sk98lin.txt - - SysKonnect SK-98xx and SK-98xx Gigabit Ethernet Adapter family - driver info. + - Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit + Ethernet Adapter family driver info skfp.txt - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. smc9.txt diff -urN linux-2.4.22-bk4/Documentation/wolfson-touchscreen.txt linux-2.4.22-bk5/Documentation/wolfson-touchscreen.txt --- linux-2.4.22-bk4/Documentation/wolfson-touchscreen.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.22-bk5/Documentation/wolfson-touchscreen.txt 2003-08-30 02:51:16.000000000 -0700 @@ -0,0 +1,178 @@ + +Wolfson Microelectronics WM9705 and WM9712 Touchscreen Controllers +=================================================================== + +The WM9705 and WM9712 are high performance AC97 audio codecs with built +in touchscreen controllers that are mainly found in portable devices. +i.e. Dell Axim and Toshiba e740. + +This driver uses the AC97 link controller for all communication with the +codec and can be either built into the kernel or built as a module. + +Build Instructions +================== + +The driver will be built into the kernel if "sound card support" = y and +"wolfson AC97 touchscreen support" = y in the kernel sound configuration. + +To build as a module, "wolfson AC97 touchscreen support" = m +in the kernel sound configuration. + + +Driver Features +=============== + + * supports WM9705, WM9712 + * polling mode + * coordinate polling + * adjustable rpu/dpp settings + * adjustable pressure current + * adjustable sample settle delay + * 4 and 5 wire touchscreens (5 wire is WM9712 only) + * pen down detection + * power management + * AUX ADC sampling + + +Driver Usage +============ + +In order to use this driver, a char device called wm97xx with a major +number of 10 and minor number 16 will have to be created under +/dev/touchscreen. + +e.g. +mknod /dev/touchscreen/wm97xx c 10 16 + + +Driver Parameters +================= +The driver can accept several parameters for fine tuning the touchscreen. +However, the syntax is different between module options and passing the +options in the kernel command line. + +e.g. + +rpu=1 (module) +rpu:1 (kernel command line) + + +1. Codec sample mode. (mode) + + The WM9712 can sample touchscreen data in 3 different operating + modes. i.e. polling, coordinate and continous. + + Polling:- The driver polls the codec and issues 3 seperate commands + over the AC97 link to read X,Y and pressure. + + Coordinate: - The driver polls the codec and only issues 1 command over + the AC97 link to read X,Y and pressure. This mode has + strict timing requirements and may drop samples if + interrupted. However, it is less demanding on the AC97 + link. Note: this mode requires a larger delay than polling + mode. + + Continuous:- The codec automatically samples X,Y and pressure and then + sends the data over the AC97 link in slots. This is then + same method used by the codec when recording audio. + + Set mode = 0 for polling, 1 for coordinate and 2 for continuous. + + Default mode = 0 + + + +2. WM9712 Internal pull up for pen detect. (rpu) + + Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive) + i.e. pull up resistance = 64k Ohms / rpu. + + Adjust this value if you are having problems with pen detect not + detecting any down events. + + Set rpu = value + + Default rpu = 1 + + + +3. WM9705 Pen detect comparator threshold. (pdd) + + 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold + i.e. 1 = Vmid/15 threshold + 15 = Vmid/1 threshold + + Adjust this value if you are having problems with pen detect not + detecting any down events. + + Set pdd = value + + Default pdd = 0 + + + +4. Set current used for pressure measurement. (pil) + + Set pil = 2 to use 400uA + pil = 1 to use 200uA and + pil = 0 to disable pressure measurement. + + This is used to increase the range of values returned by the adc + when measureing touchpanel pressure. + + Default pil = 0 + + + +5. WM9712 Set 5 wire touchscreen mode. (five_wire) + + Set five_wire = 1 to enable 5 wire mode on the WM9712. + + Default five_wire = 0 + + NOTE: Five wire mode does not allow for readback of pressure. + + + +6. ADC sample delay. (delay) + + For accurate touchpanel measurements, some settling time may be + required between the switch matrix applying a voltage across the + touchpanel plate and the ADC sampling the signal. + + This delay can be set by setting delay = n, where n is the array + position of the delay in the array delay_table below. + Long delays > 1ms are supported for completeness, but are not + recommended. + + Default delay = 4 + + wm_delay uS AC97 link frames + ==================================== + 0 21 1 + 1 42 2 + 2 84 4 + 3 167 8 + 4 333 16 + 5 667 32 + 6 1000 48 + 7 1333 64 + 8 2000 96 + 9 2667 128 + 10 3333 160 + 11 4000 192 + 12 4667 224 + 13 5333 256 + 14 6000 288 + 15 0 0 (No delay, switch matrix always on) + + + +Contact +======= + +Further information about the WM9705 and WM9712 can be found on the +Wolfson Website. http://www.wolfsonmicro.com + +Please report bugs to liam.girdwood@wolfsonmicro.com or + linux@wolfsonmicro.com diff -urN linux-2.4.22-bk4/Makefile linux-2.4.22-bk5/Makefile --- linux-2.4.22-bk4/Makefile 2003-08-30 02:51:13.000000000 -0700 +++ linux-2.4.22-bk5/Makefile 2003-08-30 02:51:16.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 22 -EXTRAVERSION = -bk4 +EXTRAVERSION = -bk5 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.4.22-bk4/arch/i386/kernel/dmi_scan.c linux-2.4.22-bk5/arch/i386/kernel/dmi_scan.c --- linux-2.4.22-bk4/arch/i386/kernel/dmi_scan.c 2003-08-30 02:51:13.000000000 -0700 +++ linux-2.4.22-bk5/arch/i386/kernel/dmi_scan.c 2003-08-30 02:51:16.000000000 -0700 @@ -400,37 +400,6 @@ } /* - * The Intel 440GX hall of shame. - * - * On many (all we have checked) of these boxes the $PIRQ table is wrong. - * The MP1.4 table is right however and so SMP kernels tend to work. - */ - -#ifdef CONFIG_PCI -extern int broken_440gx_bios; -extern unsigned int pci_probe; -#endif -static __init int broken_pirq(struct dmi_blacklist *d) -{ - printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n"); - printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n"); - printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n"); - printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n"); - printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n"); -#ifdef CONFIG_X86_IO_APIC - { - extern int skip_ioapic_setup; - skip_ioapic_setup = 0; - } -#endif -#ifdef CONFIG_PCI - broken_440gx_bios = 1; - pci_probe |= PCI_BIOS_IRQ_SCAN; -#endif - return 0; -} - -/* * ASUS K7V-RM has broken ACPI table defining sleep modes */ @@ -824,77 +793,17 @@ NO_MATCH, NO_MATCH } }, - /* Problem Intel 440GX bioses */ - - { broken_pirq, "SABR1 Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"SABR1"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "IBM xseries 370", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "IBM"), - MATCH(DMI_BIOS_VERSION,"MMKT33AUS"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0115.P12"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"C440GX0.86B"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0133.P14"), - NO_MATCH, NO_MATCH - } }, - { broken_pirq, "l44GX Bios", { /* Bad $PIR */ - MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), - MATCH(DMI_BIOS_VERSION,"L440GX0"), - NO_MATCH, NO_MATCH - } }, - - /* Intel in disgiuse - In this case they can't hide and they don't run - too well either... */ - { broken_pirq, "Dell PowerEdge 8450", { /* Bad $PIR */ - MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"), + { init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */ + MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), NO_MATCH, NO_MATCH, NO_MATCH } }, - + { broken_acpi_Sx, "ASUS K7V-RM", { /* Bad ACPI Sx table */ MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"), MATCH(DMI_BOARD_NAME, ""), NO_MATCH, NO_MATCH } }, - { init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */ - MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), - NO_MATCH, NO_MATCH, NO_MATCH - } }, - { print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", { MATCH(DMI_SYS_VENDOR, "IBM"), MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"), diff -urN linux-2.4.22-bk4/arch/i386/kernel/pci-irq.c linux-2.4.22-bk5/arch/i386/kernel/pci-irq.c --- linux-2.4.22-bk4/arch/i386/kernel/pci-irq.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.22-bk5/arch/i386/kernel/pci-irq.c 2003-08-30 02:51:16.000000000 -0700 @@ -23,7 +23,6 @@ #define PIRQ_VERSION 0x0100 int broken_hp_bios_irq9; -int broken_440gx_bios; static struct irq_routing_table *pirq_table; @@ -46,6 +45,11 @@ int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); }; +struct irq_router_handler { + u16 vendor; + int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); +}; + /* * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. */ @@ -257,111 +261,221 @@ } /* - * PIRQ routing for SiS 85C503 router used in several SiS chipsets - * According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997) - * the related registers work as follows: - * - * general: one byte per re-routable IRQ, + * PIRQ routing for SiS 85C503 router used in several SiS chipsets. + * We have to deal with the following issues here: + * - vendors have different ideas about the meaning of link values + * - some onboard devices (integrated in the chipset) have special + * links and are thus routed differently (i.e. not via PCI INTA-INTD) + * - different revision of the router have a different layout for + * the routing registers, particularly for the onchip devices + * + * For all routing registers the common thing is we have one byte + * per routeable link which is defined as: * bit 7 IRQ mapping enabled (0) or disabled (1) - * bits [6:4] reserved + * bits [6:4] reserved (sometimes used for onchip devices) * bits [3:0] IRQ to map to * allowed: 3-7, 9-12, 14-15 * reserved: 0, 1, 2, 8, 13 * - * individual registers in device config space: + * The config-space registers located at 0x41/0x42/0x43/0x44 are + * always used to route the normal PCI INT A/B/C/D respectively. + * Apparently there are systems implementing PCI routing table using + * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. + * We try our best to handle both link mappings. + * + * Currently (2003-05-21) it appears most SiS chipsets follow the + * definition of routing registers from the SiS-5595 southbridge. + * According to the SiS 5595 datasheets the revision id's of the + * router (ISA-bridge) should be 0x01 or 0xb0. * - * 0x41/0x42/0x43/0x44: PCI INT A/B/C/D - bits as in general case + * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. + * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. + * They seem to work with the current routing code. However there is + * some concern because of the two USB-OHCI HCs (original SiS 5595 + * had only one). YMMV. * - * 0x61: IDEIRQ: bits as in general case - but: - * bits [6:5] must be written 01 - * bit 4 channel-select primary (0), secondary (1) + * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: * - * 0x62: USBIRQ: bits as in general case - but: - * bit 4 OHCI function disabled (0), enabled (1) + * 0x61: IDEIRQ: + * bits [6:5] must be written 01 + * bit 4 channel-select primary (0), secondary (1) + * + * 0x62: USBIRQ: + * bit 6 OHCI function disabled (0), enabled (1) * - * 0x6a: ACPI/SCI IRQ - bits as in general case + * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved + * + * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved + * + * We support USBIRQ (in addition to INTA-INTD) and keep the + * IDE, ACPI and DAQ routing untouched as set by the BIOS. + * + * Currently the only reported exception is the new SiS 65x chipset + * which includes the SiS 69x southbridge. Here we have the 85C503 + * router revision 0x04 and there are changes in the register layout + * mostly related to the different USB HCs with USB 2.0 support. * - * 0x7e: Data Acq. Module IRQ - bits as in general case + * Onchip routing for router rev-id 0x04 (try-and-error observation) * - * Apparently there are systems implementing PCI routing table using both - * link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets - * like 0x62 as link values for USBIRQ e.g. So there is no simple - * "register = offset + pirq" relation. - * Currently we support PCI INTA..D and USBIRQ and try our best to handle - * both link mappings. - * IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS). + * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs + * bit 6-4 are probably unused, not like 5595 */ -static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +#define PIRQ_SIS_IRQ_MASK 0x0f +#define PIRQ_SIS_IRQ_DISABLE 0x80 +#define PIRQ_SIS_USB_ENABLE 0x40 +#define PIRQ_SIS_DETECT_REGISTER 0x40 + +/* return value: + * -1 on error + * 0 for PCI INTA-INTD + * 0 or enable bit mask to check or set for onchip functions + */ +static inline int pirq_sis5595_onchip(int pirq, int *reg) { - u8 x; - int reg = pirq; + int ret = -1; + *reg = pirq; switch(pirq) { - case 0x01: - case 0x02: - case 0x03: - case 0x04: - reg += 0x40; - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x62: - pci_read_config_byte(router, reg, &x); - if (reg != 0x62) - break; - if (!(x & 0x40)) - return 0; - break; - case 0x61: - case 0x6a: - case 0x7e: - printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); - return 0; - default: - printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); - return 0; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + *reg += 0x40; + case 0x41: + case 0x42: + case 0x43: + case 0x44: + ret = 0; + break; + + case 0x62: + ret = PIRQ_SIS_USB_ENABLE; /* documented for 5595 */ + break; + + case 0x61: + case 0x6a: + case 0x7e: + printk(KERN_INFO "SiS pirq: IDE/ACPI/DAQ mapping not implemented: (%u)\n", + (unsigned) pirq); + /* fall thru */ + default: + printk(KERN_INFO "SiS router unknown request: (%u)\n", + (unsigned) pirq); + break; + } + return ret; +} + +/* return value: + * -1 on error + * 0 for PCI INTA-INTD + * 0 or enable bit mask to check or set for onchip functions + */ +static inline int pirq_sis96x_onchip(int pirq, int *reg) +{ + int ret = -1; + + *reg = pirq; + switch(pirq) { + case 0x01: + case 0x02: + case 0x03: + case 0x04: + *reg += 0x40; + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + ret = 0; + break; + + default: + printk(KERN_INFO "SiS router unknown request: (%u)\n", + (unsigned) pirq); + break; } - return (x & 0x80) ? 0 : (x & 0x0f); + return ret; +} + + +static int pirq_sis5595_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 x; + int reg, check; + + check = pirq_sis5595_onchip(pirq, ®); + if (check < 0) + return 0; + + pci_read_config_byte(router, reg, &x); + if (check != 0 && !(x & check)) + return 0; + + return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); } -static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +static int pirq_sis96x_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { u8 x; - int reg = pirq; + int reg, check; + + check = pirq_sis96x_onchip(pirq, ®); + if (check < 0) + return 0; + + pci_read_config_byte(router, reg, &x); + if (check != 0 && !(x & check)) + return 0; + + return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); +} + +static int pirq_sis5595_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + u8 x; + int reg, set; + + set = pirq_sis5595_onchip(pirq, ®); + if (set < 0) + return 0; + + x = (irq & PIRQ_SIS_IRQ_MASK); + if (x == 0) + x = PIRQ_SIS_IRQ_DISABLE; + else + x |= set; - switch(pirq) { - case 0x01: - case 0x02: - case 0x03: - case 0x04: - reg += 0x40; - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x62: - x = (irq&0x0f) ? (irq&0x0f) : 0x80; - if (reg != 0x62) - break; - /* always mark OHCI enabled, as nothing else knows about this */ - x |= 0x40; - break; - case 0x61: - case 0x6a: - case 0x7e: - printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n"); - return 0; - default: - printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); - return 0; - } pci_write_config_byte(router, reg, x); return 1; } +static int pirq_sis96x_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + u8 x; + int reg, set; + + set = pirq_sis96x_onchip(pirq, ®); + if (set < 0) + return 0; + + x = (irq & PIRQ_SIS_IRQ_MASK); + if (x == 0) + x = PIRQ_SIS_IRQ_DISABLE; + else + x |= set; + + pci_write_config_byte(router, reg, x); + + return 1; +} + + /* * VLSI: nibble offset 0x74 - educated guess due to routing table and * config space of VLSI 82C534 PCI-bridge/router (1004:0102) @@ -454,96 +568,262 @@ return pcibios_set_irq_routing(bridge, pin, irq); } -static struct irq_router pirq_bios_router = - { "BIOS", 0, 0, NULL, pirq_bios_set }; - #endif -static struct irq_router pirq_routers[] = { - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, pirq_piix_get, pirq_piix_set }, - { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_0, pirq_piix_get, pirq_piix_set }, - - { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, - - { "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set }, - - { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set }, - { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set }, - { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set }, - - { "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set }, - - { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set }, - { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set }, - { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set }, - { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, - pirq_serverworks_get, pirq_serverworks_set }, - { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5, - pirq_serverworks_get, pirq_serverworks_set }, - { "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B, - pirq_amd756_get, pirq_amd756_set }, - { "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, - pirq_amd756_get, pirq_amd756_set }, - { "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, - pirq_amd756_get, pirq_amd756_set }, - { "default", 0, 0, NULL, NULL } -}; +static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + /* We must not touch 440GX even if we have tables. 440GX has + different IRQ routing weirdness */ + if(pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82450GX, NULL)) + return 0; + switch(device) + { + case PCI_DEVICE_ID_INTEL_82371FB_0: + case PCI_DEVICE_ID_INTEL_82371SB_0: + case PCI_DEVICE_ID_INTEL_82371AB_0: + case PCI_DEVICE_ID_INTEL_82371MX: + case PCI_DEVICE_ID_INTEL_82443MX_0: + case PCI_DEVICE_ID_INTEL_82801AA_0: + case PCI_DEVICE_ID_INTEL_82801AB_0: + case PCI_DEVICE_ID_INTEL_82801BA_0: + case PCI_DEVICE_ID_INTEL_82801BA_10: + case PCI_DEVICE_ID_INTEL_82801CA_0: + case PCI_DEVICE_ID_INTEL_82801CA_12: + case PCI_DEVICE_ID_INTEL_82801DB_0: + case PCI_DEVICE_ID_INTEL_82801E_0: + case PCI_DEVICE_ID_INTEL_82801EB_0: + case PCI_DEVICE_ID_INTEL_ESB_0: + r->name = "PIIX/ICH"; + r->get = pirq_piix_get; + r->set = pirq_piix_set; + return 1; + } + return 0; +} -static struct irq_router *pirq_router; +static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + /* FIXME: We should move some of the quirk fixup stuff here */ + switch(device) + { + case PCI_DEVICE_ID_VIA_82C586_0: + case PCI_DEVICE_ID_VIA_82C596: + case PCI_DEVICE_ID_VIA_82C686: + /* FIXME: add new ones for 8233/5 */ + r->name = "VIA"; + r->get = pirq_via_get; + r->set = pirq_via_set; + return 1; + } + return 0; +} + +static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_VLSI_82C534: + r->name = "VLSI 82C534"; + r->get = pirq_vlsi_get; + r->set = pirq_vlsi_set; + return 1; + } + return 0; +} + + +static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_SERVERWORKS_OSB4: + case PCI_DEVICE_ID_SERVERWORKS_CSB5: + r->name = "ServerWorks"; + r->get = pirq_serverworks_get; + r->set = pirq_serverworks_set; + return 1; + } + return 0; +} + +static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + u8 reg; + u16 devid; + + if (device != PCI_DEVICE_ID_SI_503) + return 0; + + /* + * In case of SiS south bridge, we need to detect the two + * kinds of routing tables we have seen so far (5595 and 96x). + * Since the maintain the same device ID, we need to do poke + * the PCI configuration space to find the router type we are + * dealing with. + */ + + /* + * Factoid: writing bit6 of register 0x40 of the router config space + * will make the SB to show up 0x096x inside the device id. Note, + * we need to restore register 0x40 after the device id poke. + */ + + pci_read_config_byte(router, PIRQ_SIS_DETECT_REGISTER, ®); + pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg | (1 << 6)); + pci_read_config_word(router, PCI_DEVICE_ID, &devid); + pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg); + + if ((devid & 0xfff0) == 0x0960) { + r->name = "SIS96x"; + r->get = pirq_sis96x_get; + r->set = pirq_sis96x_set; + DBG("PCI: Detecting SiS router at %02x:%02x : SiS096x detected\n", + rt->rtr_bus, rt->rtr_devfn); + } else { + r->name = "SIS5595"; + r->get = pirq_sis5595_get; + r->set = pirq_sis5595_set; + DBG("PCI: Detecting SiS router at %02x:%02x : SiS5595 detected\n", + rt->rtr_bus, rt->rtr_devfn); + } + return 1; +} + +static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_CYRIX_5520: + r->name = "NatSemi"; + r->get = pirq_cyrix_get; + r->set = pirq_cyrix_set; + return 1; + } + return 0; +} + +static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_OPTI_82C700: + r->name = "OPTI"; + r->get = pirq_opti_get; + r->set = pirq_opti_set; + return 1; + } + return 0; +} + +static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_ITE_IT8330G_0: + r->name = "ITE"; + r->get = pirq_ite_get; + r->set = pirq_ite_set; + return 1; + } + return 0; +} + +static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_AL_M1533: + r->name = "ALI"; + r->get = pirq_ali_get; + r->set = pirq_ali_set; + return 1; + /* Should add 156x some day */ + } + return 0; +} + +static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_AMD_VIPER_740B: + r->name = "AMD756"; + break; + case PCI_DEVICE_ID_AMD_VIPER_7413: + r->name = "AMD766"; + break; + case PCI_DEVICE_ID_AMD_VIPER_7443: + r->name = "AMD768"; + break; + default: + return 0; + } + r->get = pirq_amd756_get; + r->set = pirq_amd756_set; + return 1; +} + +static __initdata struct irq_router_handler pirq_routers[] = { + { PCI_VENDOR_ID_INTEL, intel_router_probe }, + { PCI_VENDOR_ID_AL, ali_router_probe }, + { PCI_VENDOR_ID_ITE, ite_router_probe }, + { PCI_VENDOR_ID_VIA, via_router_probe }, + { PCI_VENDOR_ID_OPTI, opti_router_probe }, + { PCI_VENDOR_ID_SI, sis_router_probe }, + { PCI_VENDOR_ID_CYRIX, cyrix_router_probe }, + { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, + { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, + { PCI_VENDOR_ID_AMD, amd_router_probe }, + /* Someone with docs needs to add the ATI Radeon IGP */ + { 0, NULL } +}; +static struct irq_router pirq_router; static struct pci_dev *pirq_router_dev; -static void __init pirq_find_router(void) +/* + * FIXME: should we have an option to say "generic for + * chipset" ? + */ + +static void __init pirq_find_router(struct irq_router *r) { struct irq_routing_table *rt = pirq_table; - struct irq_router *r; + struct irq_router_handler *h; #ifdef CONFIG_PCI_BIOS if (!rt->signature) { printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); - pirq_router = &pirq_bios_router; + r->set = pirq_bios_set; + r->name = "BIOS"; return; } #endif + /* Default unless a driver reloads it */ + r->name = "default"; + r->get = NULL; + r->set = NULL; + DBG("PCI: Attempting to find IRQ router for %04x:%04x\n", rt->rtr_vendor, rt->rtr_device); - /* fall back to default router if nothing else found */ - pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1]; - pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn); if (!pirq_router_dev) { DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); return; } - for(r=pirq_routers; r->vendor; r++) { - /* Exact match against router table entry? Use it! */ - if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) { - pirq_router = r; + for( h = pirq_routers; h->vendor; h++) { + /* First look for a router match */ + if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) + break; + /* Fall back to a device match */ + if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) break; - } - /* Match against router device entry? Use it as a fallback */ - if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) { - pirq_router = r; - } } printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", - pirq_router->name, + pirq_router.name, pirq_router_dev->vendor, pirq_router_dev->device, pirq_router_dev->slot_name); @@ -572,7 +852,7 @@ int i, pirq, newirq; int irq = 0; u32 mask; - struct irq_router *r = pirq_router; + struct irq_router *r = &pirq_router; struct pci_dev *dev2; char *msg = NULL; @@ -685,17 +965,14 @@ void __init pcibios_irq_init(void) { DBG("PCI: IRQ init\n"); - if (broken_440gx_bios) - pirq_table = NULL; - else - pirq_table = pirq_find_routing_table(); + pirq_table = pirq_find_routing_table(); #ifdef CONFIG_PCI_BIOS if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) pirq_table = pcibios_get_irq_routing_table(); #endif if (pirq_table) { pirq_peer_trick(); - pirq_find_router(); + pirq_find_router(&pirq_router); if (pirq_table->exclusive_irqs) { int i; for (i=0; i<16; i++) diff -urN linux-2.4.22-bk4/drivers/char/Config.in linux-2.4.22-bk5/drivers/char/Config.in --- linux-2.4.22-bk4/drivers/char/Config.in 2003-08-30 02:51:13.000000000 -0700 +++ linux-2.4.22-bk5/drivers/char/Config.in 2003-08-30 02:51:16.000000000 -0700 @@ -105,6 +105,12 @@ fi fi fi +if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then + bool 'SGI SN2 l1 serial port support' CONFIG_SGI_L1_SERIAL + if [ "$CONFIG_SGI_L1_SERIAL" = "y" ]; then + bool ' SGI SN2 l1 Console support' CONFIG_SGI_L1_SERIAL_CONSOLE + fi +fi if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 fi diff -urN linux-2.4.22-bk4/drivers/char/Makefile linux-2.4.22-bk5/drivers/char/Makefile --- linux-2.4.22-bk4/drivers/char/Makefile 2003-08-30 02:51:13.000000000 -0700 +++ linux-2.4.22-bk5/drivers/char/Makefile 2003-08-30 02:51:17.000000000 -0700 @@ -211,6 +211,7 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o +obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o subdir-$(CONFIG_RIO) += rio subdir-$(CONFIG_INPUT) += joystick diff -urN linux-2.4.22-bk4/drivers/char/amd7xx_tco.c linux-2.4.22-bk5/drivers/char/amd7xx_tco.c --- linux-2.4.22-bk4/drivers/char/amd7xx_tco.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.22-bk5/drivers/char/amd7xx_tco.c 2003-08-30 02:51:17.000000000 -0700 @@ -1,6 +1,6 @@ /* * AMD 766/768 TCO Timer Driver - * (c) Copyright 2002 Zwane Mwaikambo + * (c) Copyright 2002 Zwane Mwaikambo * All Rights Reserved. * * Parts from; @@ -34,35 +34,48 @@ #include #include -#define AMDTCO_MODULE_VER "build 20020601" +#define AMDTCO_MODULE_VER "build 20021116" #define AMDTCO_MODULE_NAME "amd7xx_tco" #define PFX AMDTCO_MODULE_NAME ": " -#define MAX_TIMEOUT 38 /* max of 38 seconds */ +#define MAX_TIMEOUT 38 /* max of 38 seconds, although the system will only + * reset itself after the second timeout */ /* pmbase registers */ -#define GLOBAL_SMI_REG 0x2a -#define TCO_EN (1 << 1) /* bit 1 in global SMI register */ #define TCO_RELOAD_REG 0x40 /* bits 0-5 are current count, 6-7 are reserved */ #define TCO_INITVAL_REG 0x41 /* bits 0-5 are value to load, 6-7 are reserved */ #define TCO_TIMEOUT_MASK 0x3f +#define TCO_STATUS1_REG 0x44 #define TCO_STATUS2_REG 0x46 #define NDTO_STS2 (1 << 1) /* we're interested in the second timeout */ #define BOOT_STS (1 << 2) /* will be set if NDTO_STS2 was set before reboot */ #define TCO_CTRL1_REG 0x48 #define TCO_HALT (1 << 11) +#define NO_REBOOT (1 << 10) /* in DevB:3x48 */ -static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER; +static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n"; static int timeout = 38; static u32 pmbase; /* PMxx I/O base */ static struct pci_dev *dev; static struct semaphore open_sem; -spinlock_t amdtco_lock; /* only for device access */ +static spinlock_t amdtco_lock; /* only for device access */ static int expect_close = 0; MODULE_PARM(timeout, "i"); MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38"); +static inline u8 seconds_to_ticks(int seconds) +{ + /* the internal timer is stored as ticks which decrement + * every 0.6 seconds */ + return (seconds * 10) / 6; +} + +static inline int ticks_to_seconds(u8 ticks) +{ + return (ticks * 6) / 10; +} + static inline int amdtco_status(void) { u16 reg; @@ -81,28 +94,19 @@ static inline void amdtco_ping(void) { - u8 reg; - - spin_lock(&amdtco_lock); - reg = inb(pmbase+TCO_RELOAD_REG); - outb(1 | reg, pmbase+TCO_RELOAD_REG); - spin_unlock(&amdtco_lock); + outb(1, pmbase+TCO_RELOAD_REG); } static inline int amdtco_gettimeout(void) { - return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; + u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; + return ticks_to_seconds(reg); } static inline void amdtco_settimeout(unsigned int timeout) { - u8 reg; - - spin_lock(&amdtco_lock); - reg = inb(pmbase+TCO_INITVAL_REG); - reg |= timeout & TCO_TIMEOUT_MASK; + u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK; outb(reg, pmbase+TCO_INITVAL_REG); - spin_unlock(&amdtco_lock); } static inline void amdtco_global_enable(void) @@ -110,9 +114,12 @@ u16 reg; spin_lock(&amdtco_lock); - reg = inw(pmbase+GLOBAL_SMI_REG); - reg |= TCO_EN; - outw(reg, pmbase+GLOBAL_SMI_REG); + + /* clear NO_REBOOT on DevB:3x48 p97 */ + pci_read_config_word(dev, 0x48, ®); + reg &= ~NO_REBOOT; + pci_write_config_word(dev, 0x48, reg); + spin_unlock(&amdtco_lock); } @@ -150,10 +157,12 @@ if (timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT; + amdtco_disable(); amdtco_settimeout(timeout); amdtco_global_enable(); + amdtco_enable(); amdtco_ping(); - printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds", + printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n", amdtco_gettimeout(), timeout); return 0; @@ -202,7 +211,7 @@ case WDIOC_GETTIMEOUT: return put_user(amdtco_gettimeout(), (int *)arg); - + case WDIOC_SETOPTIONS: if (copy_from_user(&tmp, (int *)arg, sizeof tmp)) return -EFAULT; @@ -225,7 +234,7 @@ printk(KERN_INFO PFX "Watchdog disabled\n"); } else { amdtco_ping(); - printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout); + printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout); } up(&open_sem); @@ -253,10 +262,9 @@ } #endif amdtco_ping(); - return len; } - return 0; + return len; } @@ -291,7 +299,6 @@ }; static struct pci_device_id amdtco_pci_tbl[] __initdata = { - /* AMD 766 PCI_IDs here */ { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; @@ -361,6 +368,9 @@ if (ints[0] > 0) timeout = ints[1]; + if (!timeout || timeout > 38) + timeout = MAX_TIMEOUT; + return 1; } @@ -370,7 +380,7 @@ module_init(amdtco_init); module_exit(amdtco_exit); -MODULE_AUTHOR("Zwane Mwaikambo "); +MODULE_AUTHOR("Zwane Mwaikambo "); MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver"); MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS; diff -urN linux-2.4.22-bk4/drivers/char/i810-tco.c linux-2.4.22-bk5/drivers/char/i810-tco.c --- linux-2.4.22-bk4/drivers/char/i810-tco.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.22-bk5/drivers/char/i810-tco.c 2003-08-30 02:51:17.000000000 -0700 @@ -25,7 +25,8 @@ * 82801AA & 82801AB chip : document number 290655-003, 290677-004, * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, * 82801CA & 82801CAM chip : document number 290716-001, 290718-001, - * 82801DB & 82801E chip : document number 290744-001, 273599-001 + * 82801DB & 82801E chip : document number 290744-001, 273599-001, + * 82801EB & 82801ER chip : document number 252516-001 * * 20000710 Nils Faerber * Initial Version 0.01 @@ -42,9 +43,11 @@ * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and * WDIOC_SETOPTIONS), made i810tco_getdevice __init, * removed boot_status, removed tco_timer_read, - * added support for 82801DB and 82801E chipset, general cleanup. + * added support for 82801DB and 82801E chipset, + * added support for 82801EB and 8280ER chipset, + * general cleanup. */ - + #include #include #include @@ -167,7 +170,7 @@ * Reload (trigger) the timer. Lock is needed so we dont reload it during * a reprogramming event */ - + static void tco_timer_reload (void) { spin_lock(&tco_lock); @@ -310,6 +313,7 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); diff -urN linux-2.4.22-bk4/drivers/char/i810-tco.h linux-2.4.22-bk5/drivers/char/i810-tco.h --- linux-2.4.22-bk4/drivers/char/i810-tco.h 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.22-bk5/drivers/char/i810-tco.h 2003-08-30 02:51:17.000000000 -0700 @@ -1,5 +1,5 @@ /* - * i810-tco 0.05: TCO timer driver for i8xx chipsets + * i810-tco: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -8,7 +8,7 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. - * + * * Neither kernel concepts nor Nils Faerber admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. diff -urN linux-2.4.22-bk4/drivers/char/keyboard.c linux-2.4.22-bk5/drivers/char/keyboard.c --- linux-2.4.22-bk4/drivers/char/keyboard.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.22-bk5/drivers/char/keyboard.c 2003-08-30 02:51:17.000000000 -0700 @@ -198,6 +198,7 @@ unsigned char keycode; char up_flag = down ? 0 : 0200; char raw_mode; + char have_keycode; pm_access(pm_kbd); add_keyboard_randomness(scancode | up_flag); @@ -214,16 +215,30 @@ tty = NULL; } kbd = kbd_table + fg_console; - if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + /* + * Convert scancode to keycode + */ + raw_mode = (kbd->kbdmode == VC_RAW); + have_keycode = kbd_translate(scancode, &keycode, raw_mode); + if (raw_mode) { /* * The following is a workaround for hardware * which sometimes send the key release event twice */ unsigned char next_scancode = scancode|up_flag; - if (up_flag && next_scancode==prev_scancode) { + if (have_keycode && up_flag && next_scancode==prev_scancode) { /* unexpected 2nd release event */ } else { - prev_scancode=next_scancode; + /* + * Only save previous scancode if it was a key-up + * and had a single-byte scancode. + */ + if (!have_keycode) + prev_scancode = 1; + else if (!up_flag || prev_scancode == 1) + prev_scancode = 0; + else + prev_scancode = next_scancode; put_queue(next_scancode); } /* we do not return yet, because we want to maintain @@ -231,10 +246,7 @@ values when finishing RAW mode or when changing VT's */ } - /* - * Convert scancode to keycode - */ - if (!kbd_translate(scancode, &keycode, raw_mode)) + if (!have_keycode) goto out; /* diff -urN linux-2.4.22-bk4/drivers/char/sn_serial.c linux-2.4.22-bk5/drivers/char/sn_serial.c --- linux-2.4.22-bk4/drivers/char/sn_serial.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.22-bk5/drivers/char/sn_serial.c 2003-08-30 02:51:17.000000000 -0700 @@ -0,0 +1,1190 @@ +/* + * C-Brick Serial Port (and console) driver for SGI Altix machines. + * + * This driver is NOT suitable for talking to the l1-controller for + * anything other than 'console activities' --- please use the l1 + * driver for that. + * + * + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KDB +#include +#include + +/* + * The following KDB configuration info is borrowed from + * linux/drivers/char/serial.c: + */ + +/* + * "kdb_serial_str[] is the sequence that the user must enter on the serial + * console to invoke kdb. It can be a single character such as "\001" + * (control-A) or multiple characters such as "\eKdB". NOTE: All except the + * last character are passed through to the application reading from the serial + * console. + * + * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope + * with '\' in strings, CML2 should be able to do it. KAO." + */ + +static int kdb_serial_line = -1; +static const char kdb_serial_str[] = "\eKDB"; +static char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ + +#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; +#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ + +static char *serial_revdate = "2003-07-31"; + +/* driver subtype - what does this mean? */ +#define SN_SAL_SUBTYPE 1 + +/* minor device number */ +#define SN_SAL_MINOR 64 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 128 + +/* number of characters we can transmit to the SAL console at a time */ +#define SN_SAL_MAX_CHARS 120 + +/* event types for our task queue -- so far just one */ +#define SN_SAL_EVENT_WRITE_WAKEUP 0 + +#define CONSOLE_RESTART 1 + +/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to + * avoid losing chars, (always has to be a power of 2) */ +#if 1 +#define SN_SAL_BUFFER_SIZE (64 * (1 << 10)) +#else +#define SN_SAL_BUFFER_SIZE (64) +#endif + +#define SN_SAL_UART_FIFO_DEPTH 16 +#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10 + +/* we don't kmalloc/get_free_page these as we want them available + * before either of those are initialized */ +static volatile char xmit_buff_mem[SN_SAL_BUFFER_SIZE]; + +struct volatile_circ_buf { + volatile char *buf; + int head; + int tail; +}; + +static volatile struct volatile_circ_buf xmit = { .buf = xmit_buff_mem }; +static char sal_tmp_buffer[SN_SAL_BUFFER_SIZE]; + +static volatile struct tty_struct *sn_sal_tty; + +static struct timer_list sn_sal_timer; +static int sn_sal_event; /* event type for task queue */ +static int sn_sal_refcount; + +static volatile int sn_sal_is_asynch; +static volatile int sn_sal_irq; +static spinlock_t sn_sal_lock = SPIN_LOCK_UNLOCKED; +static volatile int tx_count; +static volatile int rx_count; + +static struct tty_struct *sn_sal_table; +static struct termios *sn_sal_termios; +static struct termios *sn_sal_termios_locked; + +static void sn_sal_tasklet_action(unsigned long data); +static DECLARE_TASKLET(sn_sal_tasklet, sn_sal_tasklet_action, 0); + +static volatile unsigned long interrupt_timeout; + +extern u64 master_node_bedrock_address; + +int debug_printf(const char *fmt, ...); + +#undef DEBUG +#ifdef DEBUG +#define DPRINTF(x...) debug_printf(x) +#else +#define DPRINTF(x...) do { } while (0) +#endif + +static void intr_transmit_chars(void); +static void poll_transmit_chars(void); +static int sn_sal_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count); + +struct sn_sal_ops { + int (*puts)(const char *s, int len); + int (*getc)(void); + int (*input_pending)(void); + void (*wakeup_transmit)(void); +}; + +static volatile struct sn_sal_ops *sn_sal_ops; + + +/* the console does output in two distinctly different ways: + * synchronous and asynchronous (buffered). initally, early_printk + * does synchronous output. any data written goes directly to the SAL + * to be output (incidentally, it is internally buffered by the SAL) + * after interrupts and timers are initialized and available for use, + * the console init code switches to asynchronous output. this is + * also the earliest opportunity to begin polling for console input. + * after console initialization, console output and tty (serial port) + * output is buffered and sent to the SAL asynchronously (either by + * timer callback or by UART interrupt) */ + + +/* routines for running the console in polling mode */ + +static int hw_puts(const char *s, int len) +{ + /* looking at the PROM source code, putb calls the flush + * routine, so if we send characters in FIFO sized chunks, it + * should go out by the next time the timer gets called */ + return ia64_sn_console_putb(s, len); +} + +static int poll_getc(void) +{ + int ch; + ia64_sn_console_getc(&ch); + return ch; +} + +static int poll_input_pending(void) +{ + int status, input; + + status = ia64_sn_console_check(&input); + return !status && input; +} + +static struct sn_sal_ops poll_ops = { + .puts = hw_puts, + .getc = poll_getc, + .input_pending = poll_input_pending +}; + + +/* routines for running the console on the simulator */ + +static int sim_puts(const char *str, int count) +{ + int counter = count; + +#ifdef FLAG_DIRECT_CONSOLE_WRITES + /* This is an easy way to pre-pend the output to know whether the output + * was done via sal or directly */ + writeb('[', master_node_bedrock_address + (UART_TX << 3)); + writeb('+', master_node_bedrock_address + (UART_TX << 3)); + writeb(']', master_node_bedrock_address + (UART_TX << 3)); + writeb(' ', master_node_bedrock_address + (UART_TX << 3)); +#endif /* FLAG_DIRECT_CONSOLE_WRITES */ + while (counter > 0) { + writeb(*str, master_node_bedrock_address + (UART_TX << 3)); + counter--; + str++; + } + + return count; +} + +static int sim_getc(void) +{ + return readb(master_node_bedrock_address + (UART_RX << 3)); +} + +static int sim_input_pending(void) +{ + return readb(master_node_bedrock_address + (UART_LSR << 3)) & UART_LSR_DR; +} + +static struct sn_sal_ops sim_ops = { + .puts = sim_puts, + .getc = sim_getc, + .input_pending = sim_input_pending +}; + + +/* routines for an interrupt driven console (normal) */ + +static int intr_getc(void) +{ + return ia64_sn_console_readc(); +} + +static int intr_input_pending(void) +{ + return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV; +} + +static struct sn_sal_ops intr_ops = { + .puts = hw_puts, + .getc = intr_getc, + .input_pending = intr_input_pending, + .wakeup_transmit = intr_transmit_chars +}; + +extern void early_sn_setup(void); + +void +early_printk_sn_sal(const char *s, unsigned count) +{ + if (!sn_sal_ops) { + if (IS_RUNNING_ON_SIMULATOR()) + sn_sal_ops = &sim_ops; + else + sn_sal_ops = &poll_ops; + + early_sn_setup(); + } + sn_sal_ops->puts(s, count); +} + +/* this is as "close to the metal" as we can get, used when the driver + * itself may be broken */ +int debug_printf(const char *fmt, ...) +{ + static char printk_buf[1024]; + int printed_len; + va_list args; + va_start(args, fmt); + printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + early_printk_sn_sal(printk_buf, printed_len); + va_end(args); + return printed_len; +} + +/********************************************************************* + * Interrupt handling routines. + */ + +static void +sn_sal_sched_event(int event) +{ + sn_sal_event |= (1 << event); + tasklet_schedule(&sn_sal_tasklet); +} + +/* receive_chars can be called before sn_sal_tty is initialized. in + * that case, its only use is to trigger sysrq and kdb */ +static void +receive_chars(struct pt_regs *regs) +{ + int ch; + + while (sn_sal_ops->input_pending()) { + ch = sn_sal_ops->getc(); + if (ch < 0) { + printk(KERN_ERR "sn_serial: An error occured while " + "obtaining data from the console (0x%0x)\n", ch); + break; + } +#ifdef CONFIG_KDB + if (kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + if (!regs) + KDB_ENTER(); /* to get some registers */ + else + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ + +#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + spin_unlock(&sn_sal_lock); + handle_sysrq(ch, regs, NULL, NULL); + spin_lock(&sn_sal_lock); + /* don't record this char */ + continue; + } + } + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + } else + sysrq_serial_ptr = sysrq_serial_str; +#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ + + /* record the character to pass up to the tty layer */ + if (sn_sal_tty) { + *sn_sal_tty->flip.char_buf_ptr = ch; + sn_sal_tty->flip.char_buf_ptr++; + sn_sal_tty->flip.count++; + if (sn_sal_tty->flip.count == TTY_FLIPBUF_SIZE) + break; + } + rx_count++; + } + + if (sn_sal_tty) + tty_flip_buffer_push(sn_sal_tty); +} + + +/* synch_flush_xmit must be called with sn_sal_lock */ +static void +synch_flush_xmit(void) +{ + int xmit_count, tail, head, loops, ii; + int result; + char *start; + + if (xmit.head == xmit.tail) + /* Nothing to do. */ + return; + + head = xmit.head; + tail = xmit.tail; + start = &xmit.buf[tail]; + + /* twice around gets the tail to the end of the buffer and + * then to the head, if needed */ + loops = (head < tail) ? 2 : 1; + + for (ii = 0; ii < loops; ii++) { + xmit_count = (head < tail) ? + (SN_SAL_BUFFER_SIZE - tail) : (head - tail); + + if (xmit_count > 0) { + result = sn_sal_ops->puts(start, xmit_count); + if (!result) + debug_printf("\n*** synch_flush_xmit failed to flush\n"); + if (result > 0) { + xmit_count -= result; + tx_count += result; + tail += result; + tail &= SN_SAL_BUFFER_SIZE - 1; + xmit.tail = tail; + start = &xmit.buf[tail]; + } + } + } + +} + +/* must be called with a lock protecting the circular buffer and + * sn_sal_tty */ +static void +poll_transmit_chars(void) +{ + int xmit_count, tail, head; + int result; + char *start; + + BUG_ON(!sn_sal_is_asynch); + + if (xmit.head == xmit.tail || + (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) { + /* Nothing to do. */ + return; + } + + head = xmit.head; + tail = xmit.tail; + start = &xmit.buf[tail]; + + xmit_count = (head < tail) ? + (SN_SAL_BUFFER_SIZE - tail) : (head - tail); + + if (xmit_count == 0) + debug_printf("\n*** empty xmit_count\n"); + + if (xmit_count > SN_SAL_UART_FIFO_DEPTH) + xmit_count = SN_SAL_UART_FIFO_DEPTH; + + /* use the ops, as we could be on the simulator */ + result = sn_sal_ops->puts(start, xmit_count); + if (!result) + debug_printf("\n*** error in synchronous puts\n"); + /* XXX chadt clean this up */ + if (result > 0) { + xmit_count -= result; + tx_count += result; + tail += result; + tail &= SN_SAL_BUFFER_SIZE - 1; + xmit.tail = tail; + start = &xmit.buf[tail]; + } + + /* if there's few enough characters left in the xmit buffer + * that we could stand for the upper layer to send us some + * more, ask for it. */ + if (sn_sal_tty) + if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS) + sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP); +} + + +/* must be called with a lock protecting the circular buffer and + * sn_sal_tty */ +static void +intr_transmit_chars(void) +{ + int xmit_count, tail, head, loops, ii; + int result; + char *start; + + BUG_ON(!sn_sal_is_asynch); + + if (xmit.head == xmit.tail || + (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) { + /* Nothing to do. */ + return; + } + + head = xmit.head; + tail = xmit.tail; + start = &xmit.buf[tail]; + + /* twice around gets the tail to the end of the buffer and + * then to the head, if needed */ + loops = (head < tail) ? 2 : 1; + + for (ii = 0; ii < loops; ii++) { + xmit_count = (head < tail) ? + (SN_SAL_BUFFER_SIZE - tail) : (head - tail); + + if (xmit_count > 0) { + result = ia64_sn_console_xmit_chars(start, xmit_count); +#ifdef DEBUG + if (!result) + debug_printf("`"); +#endif + if (result > 0) { + xmit_count -= result; + tx_count += result; + tail += result; + tail &= SN_SAL_BUFFER_SIZE - 1; + xmit.tail = tail; + start = &xmit.buf[tail]; + } + } + } + + /* if there's few enough characters left in the xmit buffer + * that we could stand for the upper layer to send us some + * more, ask for it. */ + if (sn_sal_tty) + if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS) + sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP); +} + + +static void +sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* this call is necessary to pass the interrupt back to the + * SAL, since it doesn't intercept the UART interrupts + * itself */ + int status = ia64_sn_console_intr_status(); + + spin_lock(&sn_sal_lock); + if (status & SAL_CONSOLE_INTR_RECV) + receive_chars(regs); + if (status & SAL_CONSOLE_INTR_XMIT) + intr_transmit_chars(); + spin_unlock(&sn_sal_lock); +} + + +/* returns the console irq if interrupt is successfully registered, + * else 0 */ +static int +sn_sal_connect_interrupt(void) +{ + cpuid_t intr_cpuid; + unsigned int intr_cpuloc; + nasid_t console_nasid; + unsigned int console_irq; + int result; + + /* if it is an old prom, run in poll mode */ + if ((sn_sal_rev_major() <= 1) && (sn_sal_rev_minor() <= 3)) { + /* before version 1.06 doesn't work */ + printk(KERN_INFO "sn_serial: old prom version %x.%02x" + " - running in polled mode\n", + sn_sal_rev_major(), sn_sal_rev_minor()); + return 0; + } + + console_nasid = ia64_sn_get_console_nasid(); + intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid)) + ->node_first_cpu; + intr_cpuloc = cpu_physical_id(intr_cpuid); + console_irq = CPU_VECTOR_TO_IRQ(intr_cpuloc, SGI_UART_VECTOR); + + result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR, + 0 /*not used*/, 0 /*not used*/); + BUG_ON(result != SGI_UART_VECTOR); + + result = request_irq(console_irq, sn_sal_interrupt, + SA_INTERRUPT, "SAL console driver", &sn_sal_tty); + if (result >= 0) + return console_irq; + + printk(KERN_INFO "sn_serial: console proceeding in polled mode\n"); + return 0; +} + +/* + * End of the interrupt routines. + *********************************************************************/ + + +static void +sn_sal_tasklet_action(unsigned long data) +{ + unsigned long flags; + + if (sn_sal_tty) { + spin_lock_irqsave(&sn_sal_lock, flags); + if (sn_sal_tty) + if (test_and_clear_bit(SN_SAL_EVENT_WRITE_WAKEUP, &sn_sal_event)) { + if ((sn_sal_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + sn_sal_tty->ldisc.write_wakeup) + (sn_sal_tty->ldisc.write_wakeup)(sn_sal_tty); + wake_up_interruptible(&sn_sal_tty->write_wait); + } + spin_unlock_irqrestore(&sn_sal_lock, flags); + } +} + + +/* + * This function handles polled mode. + */ +static void +sn_sal_timer_poll(unsigned long dummy) +{ + if (!sn_sal_irq) { + spin_lock(&sn_sal_lock); + receive_chars(NULL); + poll_transmit_chars(); + spin_unlock(&sn_sal_lock); + mod_timer(&sn_sal_timer, jiffies + interrupt_timeout); + } +} + +static void +sn_sal_timer_restart(unsigned long dummy) +{ + unsigned long flags; + + local_irq_save(flags); + sn_sal_interrupt(0, NULL, NULL); + local_irq_restore(flags); + mod_timer(&sn_sal_timer, jiffies + interrupt_timeout); +} + +/* + * End of "sofware interrupt" routines. + *********************************************************************/ + + +/********************************************************************* + * User-level console routines + */ + +static int +sn_sal_open(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + + DPRINTF("sn_sal_open: sn_sal_tty = %p, tty = %p, filp = %p\n", + sn_sal_tty, tty, filp); + + spin_lock_irqsave(&sn_sal_lock, flags); + if (!sn_sal_tty) + sn_sal_tty = tty; + spin_unlock_irqrestore(&sn_sal_lock, flags); + + return 0; +} + + +/* We're keeping all our resources. We're keeping interrupts turned + * on. Maybe just let the tty layer finish its stuff...? GMSH + */ +static void +sn_sal_close(struct tty_struct *tty, struct file * filp) +{ + if (atomic_read(&tty->count) == 1) { + unsigned long flags; + tty->closing = 1; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + spin_lock_irqsave(&sn_sal_lock, flags); + sn_sal_tty = NULL; + spin_unlock_irqrestore(&sn_sal_lock, flags); + } +} + + +static int +sn_sal_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + unsigned long flags; + + if (from_user) { + while (1) { + int c1; + c = CIRC_SPACE_TO_END(xmit.head, xmit.tail, + SN_SAL_BUFFER_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(sal_tmp_buffer, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + + /* Turn off interrupts and see if the xmit buffer has + * moved since the last time we looked. + */ + spin_lock_irqsave(&sn_sal_lock, flags); + c1 = CIRC_SPACE_TO_END(xmit.head, xmit.tail, + SN_SAL_BUFFER_SIZE); + + if (c1 < c) + c = c1; + + memcpy(xmit.buf + xmit.head, sal_tmp_buffer, c); + xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1)); + spin_unlock_irqrestore(&sn_sal_lock, flags); + + buf += c; + count -= c; + ret += c; + } + } else { + /* The buffer passed in isn't coming from userland, + * so cut out the middleman (sal_tmp_buffer). + */ + spin_lock_irqsave(&sn_sal_lock, flags); + while (1) { + c = CIRC_SPACE_TO_END(xmit.head, xmit.tail, + SN_SAL_BUFFER_SIZE); + + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(xmit.buf + xmit.head, buf, c); + xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1)); + buf += c; + count -= c; + ret += c; + } + spin_unlock_irqrestore(&sn_sal_lock, flags); + } + + spin_lock_irqsave(&sn_sal_lock, flags); + if (xmit.head != xmit.tail && + !(tty && (tty->stopped || tty->hw_stopped))) + if (sn_sal_ops->wakeup_transmit) + sn_sal_ops->wakeup_transmit(); + spin_unlock_irqrestore(&sn_sal_lock, flags); + + return ret; +} + + +static void +sn_sal_put_char(struct tty_struct *tty, unsigned char ch) +{ + unsigned long flags; + + spin_lock_irqsave(&sn_sal_lock, flags); + if (CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) != 0) { + xmit.buf[xmit.head] = ch; + xmit.head = (xmit.head + 1) & (SN_SAL_BUFFER_SIZE-1); + sn_sal_ops->wakeup_transmit(); + } + spin_unlock_irqrestore(&sn_sal_lock, flags); +} + + +static void +sn_sal_flush_chars(struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&sn_sal_lock, flags); + if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE)) + if (sn_sal_ops->wakeup_transmit) + sn_sal_ops->wakeup_transmit(); + spin_unlock_irqrestore(&sn_sal_lock, flags); +} + + +static int +sn_sal_write_room(struct tty_struct *tty) +{ + unsigned long flags; + int space; + + spin_lock_irqsave(&sn_sal_lock, flags); + space = CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE); + spin_unlock_irqrestore(&sn_sal_lock, flags); + return space; +} + + +static int +sn_sal_chars_in_buffer(struct tty_struct *tty) +{ + unsigned long flags; + int space; + + spin_lock_irqsave(&sn_sal_lock, flags); + space = CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE); + DPRINTF("<%d>", space); + spin_unlock_irqrestore(&sn_sal_lock, flags); + return space; +} + + +static int +sn_sal_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + /* nothing supported */ + + return -ENOIOCTLCMD; +} + + +static void +sn_sal_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + + /* drop everything */ + spin_lock_irqsave(&sn_sal_lock, flags); + xmit.head = xmit.tail = 0; + spin_unlock_irqrestore(&sn_sal_lock, flags); + + /* wake up tty level */ + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + + +static void +sn_sal_hangup(struct tty_struct *tty) +{ + sn_sal_flush_buffer(tty); +} + + +static void +sn_sal_wait_until_sent(struct tty_struct *tty, int timeout) +{ + /* this is SAL's problem */ + DPRINTF(""); +} + + +/* + * sn_sal_read_proc + * + * Console /proc interface + */ + +static int +sn_sal_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + extern nasid_t get_console_nasid(void); + + len += sprintf(page, "sn_serial: revision:%s nasid:%d irq:%d tx:%d rx:%d\n", + serial_revdate, get_console_nasid(), sn_sal_irq, + tx_count, rx_count); + *eof = 1; + + if (off >= len+begin) + return 0; + *start = page + (off-begin); + + return count < begin+len-off ? count : begin+len-off; +} + + +static struct tty_driver sn_sal_driver = { + .magic = TTY_DRIVER_MAGIC, + .driver_name = "sn_serial", +#if defined(CONFIG_DEVFS_FS) + .name = "tts/%d", +#else + .name = "ttyS", +#endif + .major = TTY_MAJOR, + .minor_start = SN_SAL_MINOR, + .num = 1, + .type = TTY_DRIVER_TYPE_SERIAL, + .subtype = SN_SAL_SUBTYPE, + .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, + .refcount = &sn_sal_refcount, + .table = &sn_sal_table, + .termios = &sn_sal_termios, + .termios_locked = &sn_sal_termios_locked, + + .open = sn_sal_open, + .close = sn_sal_close, + .write = sn_sal_write, + .put_char = sn_sal_put_char, + .flush_chars = sn_sal_flush_chars, + .write_room = sn_sal_write_room, + .chars_in_buffer = sn_sal_chars_in_buffer, + .ioctl = sn_sal_ioctl, + .hangup = sn_sal_hangup, + .wait_until_sent = sn_sal_wait_until_sent, + .read_proc = sn_sal_read_proc, +}; + +/* sn_sal_init wishlist: + * - allocate sal_tmp_buffer + * - fix up the tty_driver struct + * - turn on receive interrupts + * - do any termios twiddling once and for all + */ + +/* + * Boot-time initialization code + */ + +static void __init +sn_sal_switch_to_asynch(void) +{ + debug_printf("sn_serial: about to switch to asynchronous console\n"); + + /* without early_printk, we may be invoked late enough to race + * with other cpus doing console IO at this point, however + * console interrupts will never be enabled */ + spin_lock(&sn_sal_lock); + + /* early_printk invocation may have done this for us */ + if (!sn_sal_ops) { + if (IS_RUNNING_ON_SIMULATOR()) + sn_sal_ops = &sim_ops; + else + sn_sal_ops = &poll_ops; + } + + /* we can't turn on the console interrupt (as request_irq + * calls kmalloc, which isn't set up yet), so we rely on a + * timer to poll for input and push data from the console + * buffer. + */ + init_timer(&sn_sal_timer); + sn_sal_timer.function = sn_sal_timer_poll; + + if (IS_RUNNING_ON_SIMULATOR()) + interrupt_timeout = 6; + else + /* 960cps / 16 char FIFO = 60HZ + HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */ + interrupt_timeout = HZ * SN_SAL_UART_FIFO_DEPTH / + SN_SAL_UART_FIFO_SPEED_CPS; + + mod_timer(&sn_sal_timer, jiffies + interrupt_timeout); + + sn_sal_is_asynch = 1; + spin_unlock(&sn_sal_lock); +} + +static void __init +sn_sal_switch_to_interrupts(void) +{ + int irq; + + debug_printf("sn_serial: switching to interrupt driven console\n"); + + irq = sn_sal_connect_interrupt(); + if (irq) { + unsigned long flags; + spin_lock_irqsave(&sn_sal_lock, flags); + /* sn_sal_irq is a global variable. When it's set to + * a non-zero value, we stop polling for input (since + * interrupts should now be enabled). */ + sn_sal_irq = irq; + sn_sal_ops = &intr_ops; + /* turn on receive interrupts */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + + /* the polling timer is already set up, we just change the + * frequency. if we've successfully enabled interrupts (and + * CONSOLE_RESTART isn't defined) the next timer expiration + * will be the last, otherwise we continue polling */ + if (CONSOLE_RESTART) { + /* kick the console every once in a while in + * case we miss an interrupt */ + interrupt_timeout = 20*HZ; + sn_sal_timer.function = sn_sal_timer_restart; + mod_timer(&sn_sal_timer, jiffies + interrupt_timeout); + } + spin_unlock_irqrestore(&sn_sal_lock, flags); + } +} + +static int __init +sn_sal_module_init(void) +{ + int retval; + + printk("sn_serial: sn_sal_module_init\n"); + + if (!ia64_platform_is("sn2")) + return -ENODEV; + + /* when this driver is compiled in, the console initialization + * will have already switched us into asynchronous operation + * before we get here through the module initcalls */ + if (!sn_sal_is_asynch) + sn_sal_switch_to_asynch(); + + /* at this point (module_init) we can try to turn on + * interrupts */ + if (!IS_RUNNING_ON_SIMULATOR()) + sn_sal_switch_to_interrupts(); + + sn_sal_driver.init_termios = tty_std_termios; + sn_sal_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + + if ((retval = tty_register_driver(&sn_sal_driver))) { + printk(KERN_ERR "sn_serial: Unable to register tty driver\n"); + return retval; + } + + tty_register_devfs(&sn_sal_driver, 0, sn_sal_driver.minor_start); + + return 0; +} + + +static void __exit +sn_sal_module_exit(void) +{ + unsigned long flags; + int e; + + del_timer_sync(&sn_sal_timer); + spin_lock_irqsave(&sn_sal_lock, flags); + if ((e = tty_unregister_driver(&sn_sal_driver))) + printk(KERN_ERR "sn_serial: failed to unregister driver (%d)\n", e); + + spin_unlock_irqrestore(&sn_sal_lock, flags); +} + +module_init(sn_sal_module_init); +module_exit(sn_sal_module_exit); + +/* + * End of user-level console routines. + *********************************************************************/ + + +/********************************************************************* + * Kernel console definitions + */ + +#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE +/* + * Print a string to the SAL console. The console_lock must be held + * when we get here. + */ +static void +sn_sal_console_write(struct console *co, const char *s, unsigned count) +{ + BUG_ON(!sn_sal_is_asynch); + + if (count > CIRC_SPACE_TO_END(xmit.head, xmit.tail, + SN_SAL_BUFFER_SIZE)) + debug_printf("\n*** SN_SAL_BUFFER_SIZE too small, lost chars\n"); + + /* somebody really wants this output, might be an + * oops, kdb, panic, etc. make sure they get it. */ + if (spin_is_locked(&sn_sal_lock)) { + synch_flush_xmit(); + sn_sal_ops->puts(s, count); + } else if (in_interrupt()) { + spin_lock(&sn_sal_lock); + synch_flush_xmit(); + spin_unlock(&sn_sal_lock); + sn_sal_ops->puts(s, count); + } else + sn_sal_write(NULL, 0, s, count); +} + +static kdev_t +sn_sal_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int __init +sn_sal_console_setup(struct console *co, char *options) +{ +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; + } +#endif /* CONFIG_KDB */ + + return 0; +} + + +static struct console sal_console = { + .name = "ttyS", + .write = sn_sal_console_write, + .device = sn_sal_console_device, + .setup = sn_sal_console_setup, + .index = -1 +}; + +/* + * End of kernel console definitions. + *********************************************************************/ + + +void __init +sn_sal_serial_console_init(void) +{ + if (ia64_platform_is("sn2")) { + sn_sal_switch_to_asynch(); + register_console(&sal_console); + } +} + + +#ifdef CONFIG_KDB +int +l1_control_in_polled(int offset) +{ + int sal_call_status = 0, input; + int ret = 0; + + if (IS_RUNNING_ON_SIMULATOR()) { + ret = readb((unsigned long)master_node_bedrock_address + + (offset<< 3)); + return(ret); + } + if (offset == REG_LSR) { + ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ + sal_call_status = ia64_sn_console_check(&input); + if (!sal_call_status && input) { + /* input pending */ + ret |= LSR_RCA; + } + } + return ret; +} + +int +l1_serial_in_polled(void) +{ + int ch; + + if (IS_RUNNING_ON_SIMULATOR()) { + return readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + } + + if (!ia64_sn_console_getc(&ch)) + return ch; + else + return 0; +} +#endif /* CONFIG_KDB */ + +#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */ diff -urN linux-2.4.22-bk4/drivers/char/tty_io.c linux-2.4.22-bk5/drivers/char/tty_io.c --- linux-2.4.22-bk4/drivers/char/tty_io.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.22-bk5/drivers/char/tty_io.c 2003-08-30 02:51:17.000000000 -0700 @@ -154,6 +154,7 @@ extern void rs285_console_init(void); extern void sa1100_rs_console_init(void); extern void sgi_serial_console_init(void); +extern void sn_sal_serial_console_init(void); extern void sci_console_init(void); extern void dec_serial_console_init(void); extern void tx3912_console_init(void); @@ -2391,6 +2392,12 @@ kbd_init(); #endif +#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE + if (ia64_platform_is("sn2")) { + sn_sal_serial_console_init(); + return; /* only one console right now for SN2 */ + } +#endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ espserial_init(); #endif diff -urN linux-2.4.22-bk4/drivers/scsi/scsi_scan.c linux-2.4.22-bk5/drivers/scsi/scsi_scan.c --- linux-2.4.22-bk4/drivers/scsi/scsi_scan.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.22-bk5/drivers/scsi/scsi_scan.c 2003-08-30 02:51:21.000000000 -0700 @@ -114,7 +114,8 @@ {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ {"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */ {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */ - {"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */ + {"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */ + {"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */ {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 * extra reset */