source: rtems/c/src/lib/libbsp/i386/shared/irq/irq.c @ 26b5c77f

4.104.114.84.95
Last change on this file since 26b5c77f was 8b2ee37c, checked in by Joel Sherrill <joel.sherrill@…>, on 08/19/98 at 20:09:59

Patch from Eric Valette <valette@…>:

  • Use the "hlt" instruction for the Idle thread,
  • Optimise interrupt PATH leadding to thread wakeup,
  • Preparation for Intel exception management that should come before the end of the week...
  • Property mode set to 100644
File size: 9.6 KB
Line 
1/* irq.c
2 *
3 *  This file contains the implementation of the function described in irq.h
4 *
5 *  CopyRight (C) 1998 valette@crf.canon.fr
6 *
7 *  The license and distribution terms for this file may be
8 *  found in found in the file LICENSE in this distribution or at
9 *  http://www.OARcorp.com/rtems/license.html.
10 *
11 *  $Id$
12 */
13
14
15#include <bsp.h>
16#include <irq.h>
17 
18/*
19 * pointer to the mask representing the additionnal irq vectors
20 * that must be disabled when a particular entry is activated.
21 * They will be dynamically computed from teh prioruty table given
22 * in pc386_rtems_irq_mngt_set();
23 * CAUTION : this table is accessed directly by interrupt routine
24 *           prologue.
25 */
26rtems_i8259_masks       irq_mask_or_tbl[PC_386_IRQ_LINES_NUMBER];
27
28/*
29 * Copy of data given via initial pc386_rtems_irq_mngt_set() for
30 * the sake of efficiency.
31 * CAUTION : this table is accessed directly by interrupt routine
32 *           prologue.
33 */
34rtems_irq_hdl           current_irq[PC_386_IRQ_LINES_NUMBER];
35/*
36 * default handler connected on each irq after bsp initialization
37 */
38static rtems_irq_connect_data   default_rtems_entry;
39
40/*
41 * location used to store initial tables used for interrupt
42 * management.
43 */
44static rtems_irq_global_settings*       internal_config;
45static rtems_irq_connect_data*          rtems_hdl_tbl;
46/*-------------------------------------------------------------------------+
47| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
48+--------------------------------------------------------------------------*/
49/*
50 * lower byte is interrupt mask on the master PIC.
51 * while upper bits are interrupt on the slave PIC.
52 * This cache is initialized in ldseg.s
53 */
54rtems_i8259_masks i8259s_cache;
55
56/*-------------------------------------------------------------------------+
57|         Function:  PC386_irq_disable_at_i8259s
58|      Description: Mask IRQ line in appropriate PIC chip.
59| Global Variables: i8259s_cache
60|        Arguments: vector_offset - number of IRQ line to mask.
61|          Returns: Nothing.
62+--------------------------------------------------------------------------*/
63int pc386_irq_disable_at_i8259s    (const rtems_irq_symbolic_name irqLine)
64{
65  unsigned short mask;
66  unsigned int  level;
67
68  if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
69       ((int)irqLine > PC_386_MAX_OFFSET )
70       )
71    return 1;
72 
73  _CPU_ISR_Disable(level);
74 
75  mask = 1 << irqLine;
76  i8259s_cache |= mask;
77 
78  if (irqLine < 8)
79  {
80    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
81  }
82  else
83  {
84    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) > 8));
85  }
86  _CPU_ISR_Enable (level);
87
88  return 0;
89}
90
91/*-------------------------------------------------------------------------+
92|         Function:  pc386_irq_enable_at_i8259s
93|      Description: Unmask IRQ line in appropriate PIC chip.
94| Global Variables: i8259s_cache
95|        Arguments: irqLine - number of IRQ line to mask.
96|          Returns: Nothing.
97+--------------------------------------------------------------------------*/
98int pc386_irq_enable_at_i8259s    (const rtems_irq_symbolic_name irqLine)
99{
100  unsigned short mask;
101  unsigned int  level;
102
103  if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
104       ((int)irqLine > PC_386_MAX_OFFSET )
105       )
106    return 1;
107
108  _CPU_ISR_Disable(level);
109 
110  mask = ~(1 << irqLine);
111  i8259s_cache &= mask;
112 
113  if (irqLine < 8)
114  {
115    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
116  }
117  else
118  {
119    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) > 8));
120  }
121  _CPU_ISR_Enable (level);
122
123  return 0;
124} /* mask_irq */
125
126int pc386_irq_enabled_at_i8259s         (const rtems_irq_symbolic_name irqLine)
127{
128  unsigned short mask;
129
130  if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
131       ((int)irqLine > PC_386_MAX_OFFSET )
132     )
133    return 1;
134
135  mask = (1 << irqLine);
136  return  (~(i8259s_cache & mask));
137}
138 
139
140/*-------------------------------------------------------------------------+
141|         Function: pc386_irq_ack_at_i8259s
142|      Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
143| Global Variables: None.
144|        Arguments: irqLine - number of IRQ line to acknowledge.
145|          Returns: Nothing.
146+--------------------------------------------------------------------------*/
147int pc386_irq_ack_at_i8259s     (const rtems_irq_symbolic_name irqLine)
148{
149  if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
150       ((int)irqLine > PC_386_MAX_OFFSET )
151       )
152    return 1;
153
154  if (irqLine >= 8) {
155   outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
156  }
157  outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
158
159  return 0;
160
161} /* ackIRQ */
162
163/*
164 * ------------------------ RTEMS Irq helper functions ----------------
165 */
166 
167/*
168 * Caution : this function assumes the variable "internal_config"
169 * is already set and that the tables it contains are still valid
170 * and accessible.
171 */
172static void compute_i8259_masks_from_prio ()
173{
174  unsigned int i;
175  unsigned int j;
176  /*
177   * Always mask at least current interrupt to prevent re-entrance
178   */
179  for (i=0; i < internal_config->irqNb; i++) {
180    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
181    for (j = 0; j < internal_config->irqNb; j++) {
182      /*
183       * Mask interrupts at i8259 level that have a lower priority
184       */
185      if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
186        * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
187      }
188    }
189  }
190}
191
192/*
193 * Caution : this function assumes the variable "internal_config"
194 * is already set and that the tables it contains are still valid
195 * and accessible.
196 */
197static void make_copy_of_handlers ()
198{
199  int i;
200  for (i=0; i < internal_config->irqNb; i++) {
201    current_irq [i] = internal_config->irqHdlTbl[i].hdl;
202  }
203}
204
205
206/*
207 * This function check that the value given for the irq line
208 * is valid.
209 */
210
211static int isValidInterrupt(int irq)
212{
213  if ( (irq < PC_386_LOWEST_OFFSET) || (irq > PC_386_MAX_OFFSET))
214    return 0;
215  return 1;
216}
217
218/*
219 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
220 */
221
222int pc386_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
223{
224    unsigned int level;
225 
226    if (!isValidInterrupt(irq->name)) {
227      return 0;
228    }
229    /*
230     * Check if default handler is actually connected. If not issue an error.
231     * You must first get the current handler via i386_get_current_idt_entry
232     * and then disconnect it using i386_delete_idt_entry.
233     * RATIONALE : to always have the same transition by forcing the user
234     * to get the previous handler before accepting to disconnect.
235     */
236    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
237      return 0;
238    }
239    _CPU_ISR_Disable(level);
240
241    /*
242     * store the data provided by user
243     */
244    rtems_hdl_tbl[irq->name] = *irq;
245    /*
246     * update table used directly by rtems interrupt prologue
247     */
248    current_irq [irq->name] = irq->hdl;
249    /*
250     * Enable interrupt at PIC level
251     */
252    pc386_irq_enable_at_i8259s (irq->name);
253    /*
254     * Enable interrupt on device
255     */
256    irq->on(irq);
257   
258    _CPU_ISR_Enable(level);
259
260    return 1;
261}
262
263
264int pc386_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
265{
266     if (!isValidInterrupt(irq->name)) {
267      return 0;
268     }
269     *irq = rtems_hdl_tbl[irq->name];
270     return 1;
271}
272
273int pc386_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
274{
275    unsigned int level;
276 
277    if (!isValidInterrupt(irq->name)) {
278      return 0;
279    }
280    /*
281     * Check if default handler is actually connected. If not issue an error.
282     * You must first get the current handler via i386_get_current_idt_entry
283     * and then disconnect it using i386_delete_idt_entry.
284     * RATIONALE : to always have the same transition by forcing the user
285     * to get the previous handler before accepting to disconnect.
286     */
287    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
288      return 0;
289    }
290    _CPU_ISR_Disable(level);
291
292    /*
293     * disable interrupt at PIC level
294     */
295    pc386_irq_disable_at_i8259s (irq->name);
296
297    /*
298     * Disable interrupt on device
299     */
300    irq->off(irq);
301
302    /*
303     * restore the default irq value
304     */
305    rtems_hdl_tbl[irq->name] = default_rtems_entry;
306
307    current_irq[irq->name] = default_rtems_entry.hdl;
308   
309    _CPU_ISR_Enable(level);
310
311    return 1;
312}
313
314/*
315 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
316 */
317
318int pc386_rtems_irq_mngt_set(rtems_irq_global_settings* config)
319{
320    int i;
321    unsigned int level;
322   /*
323    * Store various code accelerators
324    */
325    internal_config             = config;
326    default_rtems_entry         = config->defaultEntry;
327    rtems_hdl_tbl               = config->irqHdlTbl;
328
329    _CPU_ISR_Disable(level);
330    /*
331     * set up internal tables used by rtems interrupt prologue
332     */
333    compute_i8259_masks_from_prio ();
334    make_copy_of_handlers ();
335
336    for (i=0; i < internal_config->irqNb; i++) {
337      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
338        pc386_irq_enable_at_i8259s (i);
339        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
340      }
341      else {
342        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
343        pc386_irq_disable_at_i8259s (i);
344      }
345    }
346    /*
347     * must disable slave pic anyway
348     */
349    pc386_irq_enable_at_i8259s (2);
350    _CPU_ISR_Enable(level);
351    return 1;
352}
353
354int pc386_rtems_irq_mngt_get(rtems_irq_global_settings** config)
355{
356    *config = internal_config;
357    return 0;
358}   
359
360void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
361{
362  /*
363   * If I understand the _Thread_Dispatch routine correctly
364   * I do not see how this routine can be called given the
365   * actual code. I plan to use this so far unused feature
366   * to implement remote debugger ptrace("attach", ...)
367   * command.
368   */
369  printk(" _ThreadProcessSignalsFromIrq called! mail valette@crf.canon.fr\n");
370}
Note: See TracBrowser for help on using the repository browser.