1/* $NetBSD: i8259.c,v 1.14 2008/07/03 14:02:25 drochner Exp $ */ 2 3/* 4 * Copyright 2002 (c) Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Frank van der Linden for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/*- 39 * Copyright (c) 1991 The Regents of the University of California. 40 * All rights reserved. 41 * 42 * This code is derived from software contributed to Berkeley by 43 * William Jolitz. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 * 69 * @(#)isa.c 7.2 (Berkeley) 5/13/91 70 */ 71 72#include <sys/cdefs.h> 73__KERNEL_RCSID(0, "$NetBSD: i8259.c,v 1.14 2008/07/03 14:02:25 drochner Exp $"); 74 75#include <sys/param.h> 76#include <sys/systm.h> 77#include <sys/kernel.h> 78#include <sys/syslog.h> 79#include <sys/device.h> 80#include <sys/proc.h> 81 82#include <dev/isa/isareg.h> 83#include <dev/ic/i8259reg.h> 84 85#include <machine/pio.h> 86#include <machine/cpufunc.h> 87#include <machine/cpu.h> 88#include <machine/pic.h> 89#include <machine/i8259.h> 90 91 92#ifndef __x86_64__ 93#include "mca.h" 94#if NMCA > 0 95#include <machine/mca_machdep.h> /* for MCA_system */ 96#endif 97#endif 98 99static void i8259_hwmask(struct pic *, int); 100static void i8259_hwunmask(struct pic *, int); 101static void i8259_setup(struct pic *, struct cpu_info *, int, int, int); 102static void i8259_reinit_irqs(void); 103 104unsigned i8259_imen; 105 106/* 107 * Perhaps this should be made into a real device. 108 */ 109struct pic i8259_pic = { 110 .pic_name = "pic0", 111 .pic_type = PIC_I8259, 112 .pic_vecbase = 0, 113 .pic_apicid = 0, 114 .pic_lock = __SIMPLELOCK_UNLOCKED, 115 .pic_hwmask = i8259_hwmask, 116 .pic_hwunmask = i8259_hwunmask, 117 .pic_addroute = i8259_setup, 118 .pic_delroute = i8259_setup, 119 .pic_level_stubs = i8259_stubs, 120 .pic_edge_stubs = i8259_stubs, 121}; 122 123void 124i8259_default_setup(void) 125{ 126#if NMCA > 0 127 /* level-triggered interrupts on MCA PS/2s */ 128 if (MCA_system) 129 /* reset; program device, level-triggered, four bytes */ 130 outb(IO_ICU1 + PIC_ICW1, ICW1_SELECT | ICW1_LTIM | ICW1_IC4); 131 else 132#endif 133 /* reset; program device, four bytes */ 134 outb(IO_ICU1 + PIC_ICW1, ICW1_SELECT | ICW1_IC4); 135 136 /* starting at this vector index */ 137 outb(IO_ICU1 + PIC_ICW2, ICU_OFFSET); 138 /* slave on line 2 */ 139 outb(IO_ICU1 + PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE)); 140 141#ifdef AUTO_EOI_1 142 /* auto EOI, 8086 mode */ 143 outb(IO_ICU1 + PIC_ICW4, ICW4_AEOI | ICW4_8086); 144#else 145 /* 8086 mode */ 146 outb(IO_ICU1 + PIC_ICW4, ICW4_8086); 147#endif 148 /* leave interrupts masked */ 149 outb(IO_ICU1 + PIC_OCW1, 0xff); 150 /* special mask mode (if available) */ 151 outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 152 /* Read IRR by default. */ 153 outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_RR); 154#ifdef REORDER_IRQ 155 /* pri order 3-7, 0-2 (com2 first) */ 156 outb(IO_ICU1 + PIC_OCW2, OCW2_SELECT | OCW2_R | OCW2_SL | 157 OCW2_ILS(3 - 1)); 158#endif 159 160#if NMCA > 0 161 /* level-triggered interrupts on MCA PS/2s */ 162 if (MCA_system) 163 /* reset; program device, level-triggered, four bytes */ 164 outb(IO_ICU2 + PIC_ICW1, ICW1_SELECT | ICW1_LTIM | ICW1_IC4); 165 else 166#endif 167 /* reset; program device, four bytes */ 168 outb(IO_ICU2 + PIC_ICW1, ICW1_SELECT | ICW1_IC4); 169 170 /* staring at this vector index */ 171 outb(IO_ICU2 + PIC_ICW2, ICU_OFFSET + 8); 172 /* slave connected to line 2 of master */ 173 outb(IO_ICU2 + PIC_ICW3, ICW3_SIC(IRQ_SLAVE)); 174#ifdef AUTO_EOI_2 175 /* auto EOI, 8086 mode */ 176 outb(IO_ICU2 + PIC_ICW4, ICW4_AEOI | ICW4_8086); 177#else 178 /* 8086 mode */ 179 outb(IO_ICU2 + PIC_ICW4, ICW4_8086); 180#endif 181 /* leave interrupts masked */ 182 outb(IO_ICU2 + PIC_OCW1, 0xff); 183 /* special mask mode (if available) */ 184 outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 185 /* Read IRR by default. */ 186 outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_RR); 187} 188 189static void 190i8259_hwmask(struct pic *pic, int pin) 191{ 192 unsigned port; 193 uint8_t byte; 194 195 i8259_imen |= (1 << pin); 196#ifdef PIC_MASKDELAY 197 delay(10); 198#endif 199 if (pin > 7) { 200 port = IO_ICU2 + PIC_OCW1; 201 byte = i8259_imen >> 8; 202 } else { 203 port = IO_ICU1 + PIC_OCW1; 204 byte = i8259_imen & 0xff; 205 } 206 outb(port, byte); 207} 208 209static void 210i8259_hwunmask(struct pic *pic, int pin) 211{ 212 unsigned port; 213 uint8_t byte; 214 215 x86_disable_intr(); /* XXX */ 216 i8259_imen &= ~(1 << pin); 217#ifdef PIC_MASKDELAY 218 delay(10); 219#endif 220 if (pin > 7) { 221 port = IO_ICU2 + PIC_OCW1; 222 byte = i8259_imen >> 8; 223 } else { 224 port = IO_ICU1 + PIC_OCW1; 225 byte = i8259_imen & 0xff; 226 } 227 outb(port, byte); 228 x86_enable_intr(); 229} 230 231static void 232i8259_reinit_irqs(void) 233{ 234 int irqs, irq; 235 struct cpu_info *ci = &cpu_info_primary; 236 237 irqs = 0; 238 for (irq = 0; irq < NUM_LEGACY_IRQS; irq++) 239 if (ci->ci_isources[irq] != NULL) 240 irqs |= 1 << irq; 241 if (irqs >= 0x100) /* any IRQs >= 8 in use */ 242 irqs |= 1 << IRQ_SLAVE; 243 i8259_imen = ~irqs; 244 245 outb(IO_ICU1 + PIC_OCW1, i8259_imen); 246 outb(IO_ICU2 + PIC_OCW1, i8259_imen >> 8); 247} 248 249static void 250i8259_setup(struct pic *pic, struct cpu_info *ci, 251 int pin, int idtvec, int type) 252{ 253 if (CPU_IS_PRIMARY(ci)) 254 i8259_reinit_irqs(); 255} 256 257void 258i8259_reinit(void) 259{ 260 i8259_default_setup(); 261 i8259_reinit_irqs(); 262} 263 264unsigned 265i8259_setmask(unsigned mask) 266{ 267 unsigned old = i8259_imen; 268 269 i8259_imen = mask; 270 outb(IO_ICU1 + PIC_OCW1, i8259_imen); 271 outb(IO_ICU2 + PIC_OCW1, i8259_imen >> 8); 272 return old; 273} 274