[1] | 1 | /* |
---|
| 2 | * pic.h - Programmable Interrupt Controller driver implementation |
---|
| 3 | * |
---|
| 4 | * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless |
---|
| 5 | * Copyright (c) 2011,2012 UPMC Sorbonne Universites |
---|
| 6 | * |
---|
| 7 | * This file is part of ALMOS-kernel. |
---|
| 8 | * |
---|
| 9 | * ALMOS-kernel is free software; you can redistribute it and/or modify it |
---|
| 10 | * under the terms of the GNU General Public License as published by |
---|
| 11 | * the Free Software Foundation; version 2.0 of the License. |
---|
| 12 | * |
---|
| 13 | * ALMOS-kernel is distributed in the hope that it will be useful, but |
---|
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 16 | * General Public License for more details. |
---|
| 17 | * |
---|
| 18 | * You should have received a copy of the GNU General Public License |
---|
| 19 | * along with ALMOS-kernel; if not, write to the Free Software Foundation, |
---|
| 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | #include <types.h> |
---|
| 24 | #include <cpu.h> |
---|
[4] | 25 | #include <chdev.h> |
---|
[1] | 26 | #include <driver.h> |
---|
| 27 | #include <cpu-io.h> |
---|
| 28 | #include <kmem.h> |
---|
| 29 | #include <string.h> |
---|
| 30 | #include <kdmsg.h> |
---|
| 31 | #include <pic.h> |
---|
| 32 | |
---|
| 33 | #define PIC_PRIMARY_PIO 0x20 |
---|
| 34 | #define PIC_SECONDARY_PIO 0xA0 |
---|
| 35 | |
---|
| 36 | struct irq_action_s *irq_vector[PIC_IRQ_MAX]; |
---|
| 37 | |
---|
| 38 | static void pic_set_mask(struct device_s *pic, uint_t mask, uint_t type, uint_t output_irq) |
---|
| 39 | { |
---|
| 40 | switch(type) |
---|
| 41 | { |
---|
| 42 | case 0: |
---|
| 43 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_IMR_REG, ~(mask & 0xFF)); |
---|
| 44 | break; |
---|
| 45 | case 1: |
---|
| 46 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_IMR_REG, ~(mask & 0xFF)); |
---|
| 47 | break; |
---|
| 48 | default: |
---|
| 49 | printk(ERROR, "ERROR: Un expected mask value, PIC has 16 IRQ line only [ type 0 & 1 ]"); |
---|
| 50 | } |
---|
| 51 | } |
---|
| 52 | |
---|
| 53 | static uint_t pic_get_mask(struct device_s *icu, uint_t type, uint_t output_irq) |
---|
| 54 | { |
---|
| 55 | register uint_t mask = ~0; |
---|
| 56 | |
---|
| 57 | switch(type) |
---|
| 58 | { |
---|
| 59 | case 0: |
---|
| 60 | mask = cpu_io_in8(PIC_PRIMARY_PIO + PIC_IMR_REG); |
---|
| 61 | break; |
---|
| 62 | case 1: |
---|
| 63 | mask = cpu_io_in8(PIC_SECONDARY_PIO + PIC_IMR_REG); |
---|
| 64 | break; |
---|
| 65 | default: |
---|
| 66 | printk(ERROR, "ERROR: Un expected mask value, PIC has 16 IRQ line only [ type 0 & 1 ]"); |
---|
| 67 | } |
---|
| 68 | |
---|
| 69 | return ((~mask) & 0xFF); |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | static sint_t pic_get_highest_irq(struct device_s *icu, uint_t type, uint_t output_irq) |
---|
| 73 | { |
---|
| 74 | return -1; |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | static void pic_default_irq_handler(struct irq_action_s *action) |
---|
| 78 | { |
---|
| 79 | register unsigned int irq_num = (unsigned int) action->data; |
---|
| 80 | register unsigned int cpu_id = cpu_get_id(); |
---|
| 81 | |
---|
| 82 | isr_dmsg(WARNING, "WARNING: No ISR registered handler for IRQ %d on CPU %d\n",irq_num, cpu_id); |
---|
| 83 | } |
---|
| 84 | |
---|
| 85 | static void pic_ICWs() |
---|
| 86 | { |
---|
| 87 | /* ICW1 */ |
---|
| 88 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_CMD_REG, 0x11); /* Put Primary PIC in Initialization mode with ICW4 enabled */ |
---|
| 89 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_CMD_REG, 0x11); /* Same ICW1 as Primary */ |
---|
| 90 | |
---|
| 91 | /* ICW2 */ |
---|
| 92 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x20); /* Set Primary PIC's interrupt vector base number */ |
---|
| 93 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x28); /* Set Secondary PIC's interrupt vector base number */ |
---|
| 94 | |
---|
| 95 | /* ICW3 */ |
---|
| 96 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x4); /* Informe Primary that Secondary is connected to line 2 */ |
---|
| 97 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x2); /* Inform Secondary of it's identification */ |
---|
| 98 | |
---|
| 99 | /* ICW4 */ |
---|
| 100 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x1); /* Put Primary in x86 mode */ |
---|
| 101 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x1); /* Put Primary in x86 mode */ |
---|
| 102 | |
---|
| 103 | /* CLEAR DATA REGISTERS */ |
---|
| 104 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0); |
---|
| 105 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0); |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | |
---|
| 109 | void pic_irq_handler(struct irq_action_s *action) |
---|
| 110 | { |
---|
| 111 | register uint_t irq = (uint_t)action->data; |
---|
| 112 | irq_vector[irq]->data = (void*)irq; |
---|
| 113 | irq_vector[irq]->irq_handler(irq_vector[irq]); |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | void ibmpc_pic_init(struct device_s *pic, void *base, uint_t irq) |
---|
| 117 | { |
---|
| 118 | register uint_t _irq; |
---|
| 119 | struct irq_action_s *action_ptr; |
---|
| 120 | |
---|
| 121 | pic->base = base; |
---|
| 122 | pic->type = DEV_ICU; |
---|
| 123 | pic->action.irq_handler = &pic_irq_handler; |
---|
| 124 | |
---|
| 125 | strcpy(pic->name, "PIC"); |
---|
| 126 | metafs_init(&pic->node, pic->name); |
---|
| 127 | |
---|
| 128 | pic->op.icu.set_mask = &pic_set_mask; |
---|
| 129 | pic->op.icu.get_mask = &pic_get_mask; |
---|
| 130 | pic->op.icu.get_highest_irq = &pic_get_highest_irq; |
---|
| 131 | |
---|
| 132 | for(_irq=0; _irq < PIC_IRQ_MAX; _irq++) |
---|
| 133 | { |
---|
| 134 | action_ptr = kbootMem_calloc(sizeof(*action_ptr)); |
---|
| 135 | action_ptr->dev = pic; |
---|
| 136 | action_ptr->irq_handler = &pic_default_irq_handler; |
---|
| 137 | action_ptr->data = (void*) _irq; |
---|
| 138 | irq_vector[_irq] = action_ptr; |
---|
| 139 | } |
---|
| 140 | |
---|
| 141 | pic_ICWs(); |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | void ibmpc_pic_bind(struct device_s *pic, struct device_s *dev) |
---|
| 145 | { |
---|
| 146 | assert(dev->irq < PIC_IRQ_MAX && "Unexpected IRQ, connot bind this device"); |
---|
| 147 | |
---|
| 148 | if(dev->irq < PIC_IRQ_MAX) |
---|
| 149 | { |
---|
| 150 | irq_vector[dev->irq] = &dev->action; |
---|
| 151 | metafs_register(&pic->node, &dev->node); |
---|
| 152 | } |
---|
| 153 | } |
---|