source: rtems/c/src/lib/libbsp/i386/shared/irq/irq.c @ 529cebf0

4.104.114.84.95
Last change on this file since 529cebf0 was 529cebf0, checked in by Jennifer Averett <Jennifer.Averett@…>, on 05/06/05 at 19:55:45

2005-05-06 Jennifer Averett <jennifer.averett@…>

  • Makefile.am, comm/i386-stub-glue.c, comm/tty_drv.c, comm/uart.c, irq/idt.c, irq/irq.c, irq/irq.h, irq/irq_asm.S, irq/irq_init.c: Moved irq.h and irq_asm.h to bsp subdirectory.
  • Property mode set to 100644
File size: 9.3 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.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#include <bsp.h>
15#include <bsp/irq.h>
16#include <rtems/score/thread.h>
17#include <rtems/score/apiext.h>
18
19/*
20 * pointer to the mask representing the additionnal irq vectors
21 * that must be disabled when a particular entry is activated.
22 * They will be dynamically computed from teh prioruty table given
23 * in BSP_rtems_irq_mngt_set();
24 * CAUTION : this table is accessed directly by interrupt routine
25 *           prologue.
26 */
27rtems_i8259_masks       irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
28
29/*
30 * default handler connected on each irq after bsp initialization
31 */
32static rtems_irq_connect_data   default_rtems_entry;
33
34/*
35 * location used to store initial tables used for interrupt
36 * management.
37 */
38static rtems_irq_global_settings*       internal_config;
39rtems_irq_connect_data*                 rtems_hdl_tbl;
40/*-------------------------------------------------------------------------+
41| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
42+--------------------------------------------------------------------------*/
43/*
44 * lower byte is interrupt mask on the master PIC.
45 * while upper bits are interrupt on the slave PIC.
46 * This cache is initialized in ldseg.s
47 */
48rtems_i8259_masks i8259s_cache = 0xFFFB;
49
50/*-------------------------------------------------------------------------+
51|         Function:  BSP_irq_disable_at_i8259s
52|      Description: Mask IRQ line in appropriate PIC chip.
53| Global Variables: i8259s_cache
54|        Arguments: vector_offset - number of IRQ line to mask.
55|          Returns: Nothing.
56+--------------------------------------------------------------------------*/
57int BSP_irq_disable_at_i8259s    (const rtems_irq_symbolic_name irqLine)
58{
59  unsigned short mask;
60  unsigned int  level;
61
62  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
63       ((int)irqLine > BSP_MAX_OFFSET )
64       )
65    return 1;
66
67  _CPU_ISR_Disable(level);
68
69  mask = 1 << irqLine;
70  i8259s_cache |= mask;
71
72  if (irqLine < 8)
73  {
74    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
75  }
76  else
77  {
78    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
79  }
80  _CPU_ISR_Enable (level);
81
82  return 0;
83}
84
85/*-------------------------------------------------------------------------+
86|         Function:  BSP_irq_enable_at_i8259s
87|      Description: Unmask IRQ line in appropriate PIC chip.
88| Global Variables: i8259s_cache
89|        Arguments: irqLine - number of IRQ line to mask.
90|          Returns: Nothing.
91+--------------------------------------------------------------------------*/
92int BSP_irq_enable_at_i8259s    (const rtems_irq_symbolic_name irqLine)
93{
94  unsigned short mask;
95  unsigned int  level;
96
97  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
98       ((int)irqLine > BSP_MAX_OFFSET )
99       )
100    return 1;
101
102  _CPU_ISR_Disable(level);
103
104  mask = ~(1 << irqLine);
105  i8259s_cache &= mask;
106
107  if (irqLine < 8)
108  {
109    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
110  }
111  else
112  {
113    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
114  }
115  _CPU_ISR_Enable (level);
116
117  return 0;
118} /* mask_irq */
119
120int BSP_irq_enabled_at_i8259s           (const rtems_irq_symbolic_name irqLine)
121{
122  unsigned short mask;
123
124  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
125       ((int)irqLine > BSP_MAX_OFFSET )
126     )
127    return 1;
128
129  mask = (1 << irqLine);
130  return  (~(i8259s_cache & mask));
131}
132
133/*-------------------------------------------------------------------------+
134|         Function: BSP_irq_ack_at_i8259s
135|      Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
136| Global Variables: None.
137|        Arguments: irqLine - number of IRQ line to acknowledge.
138|          Returns: Nothing.
139+--------------------------------------------------------------------------*/
140int BSP_irq_ack_at_i8259s       (const rtems_irq_symbolic_name irqLine)
141{
142  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
143       ((int)irqLine > BSP_MAX_OFFSET )
144       )
145    return 1;
146
147  if (irqLine >= 8) {
148   outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
149  }
150  outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
151
152  return 0;
153
154} /* ackIRQ */
155
156/*
157 * ------------------------ RTEMS Irq helper functions ----------------
158 */
159
160/*
161 * Caution : this function assumes the variable "internal_config"
162 * is already set and that the tables it contains are still valid
163 * and accessible.
164 */
165static void compute_i8259_masks_from_prio ()
166{
167  unsigned int i;
168  unsigned int j;
169  /*
170   * Always mask at least current interrupt to prevent re-entrance
171   */
172  for (i=0; i < internal_config->irqNb; i++) {
173    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
174    for (j = 0; j < internal_config->irqNb; j++) {
175      /*
176       * Mask interrupts at i8259 level that have a lower priority
177       */
178      if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
179        * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
180      }
181    }
182  }
183}
184
185/*
186 * This function check that the value given for the irq line
187 * is valid.
188 */
189
190static int isValidInterrupt(int irq)
191{
192  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
193    return 0;
194  return 1;
195}
196
197/*
198 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
199 */
200
201int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
202{
203    unsigned int level;
204
205    if (!isValidInterrupt(irq->name)) {
206      return 0;
207    }
208    /*
209     * Check if default handler is actually connected. If not issue an error.
210     * You must first get the current handler via i386_get_current_idt_entry
211     * and then disconnect it using i386_delete_idt_entry.
212     * RATIONALE : to always have the same transition by forcing the user
213     * to get the previous handler before accepting to disconnect.
214     */
215    _CPU_ISR_Disable(level);
216    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
217          _CPU_ISR_Enable(level);
218      return 0;
219    }
220
221    /*
222     * store the data provided by user
223     */
224    rtems_hdl_tbl[irq->name] = *irq;
225    /*
226     * Enable interrupt at PIC level
227     */
228    BSP_irq_enable_at_i8259s (irq->name);
229    /*
230     * Enable interrupt on device
231     */
232    irq->on(irq);
233
234    _CPU_ISR_Enable(level);
235
236    return 1;
237}
238
239int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
240{
241     unsigned int level;
242
243     if (!isValidInterrupt(irq->name)) {
244      return 0;
245     }
246    _CPU_ISR_Disable(level);
247     *irq = rtems_hdl_tbl[irq->name];
248    _CPU_ISR_Enable(level);
249     return 1;
250}
251
252int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
253{
254    unsigned int level;
255
256    if (!isValidInterrupt(irq->name)) {
257      return 0;
258    }
259    /*
260     * Check if default handler is actually connected. If not issue an error.
261     * You must first get the current handler via i386_get_current_idt_entry
262     * and then disconnect it using i386_delete_idt_entry.
263     * RATIONALE : to always have the same transition by forcing the user
264     * to get the previous handler before accepting to disconnect.
265     */
266    _CPU_ISR_Disable(level);
267    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
268      _CPU_ISR_Enable(level);
269      return 0;
270    }
271
272    /*
273     * disable interrupt at PIC level
274     */
275    BSP_irq_disable_at_i8259s (irq->name);
276
277    /*
278     * Disable interrupt on device
279     */
280    irq->off(irq);
281
282    /*
283     * restore the default irq value
284     */
285    rtems_hdl_tbl[irq->name] = default_rtems_entry;
286
287    _CPU_ISR_Enable(level);
288
289    return 1;
290}
291
292/*
293 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
294 */
295
296int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
297{
298    int i;
299    unsigned int level;
300   /*
301    * Store various code accelerators
302    */
303    internal_config             = config;
304    default_rtems_entry         = config->defaultEntry;
305    rtems_hdl_tbl               = config->irqHdlTbl;
306
307    _CPU_ISR_Disable(level);
308    /*
309     * set up internal tables used by rtems interrupt prologue
310     */
311    compute_i8259_masks_from_prio ();
312
313    for (i=0; i < internal_config->irqNb; i++) {
314      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
315        BSP_irq_enable_at_i8259s (i);
316        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
317      }
318      else {
319        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
320        BSP_irq_disable_at_i8259s (i);
321      }
322    }
323    /*
324     * must enable slave pic anyway
325     */
326    BSP_irq_enable_at_i8259s (2);
327    _CPU_ISR_Enable(level);
328    return 1;
329}
330
331int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
332{
333    *config = internal_config;
334    return 0;
335}
336
337void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
338{
339  /*
340   * Process pending signals that have not already been
341   * processed by _Thread_Displatch. This happens quite
342   * unfrequently : the ISR must have posted an action
343   * to the current running thread.
344   */
345  if ( _Thread_Do_post_task_switch_extension ||
346       _Thread_Executing->do_post_task_switch_extension ) {
347    _Thread_Executing->do_post_task_switch_extension = FALSE;
348    _API_extensions_Run_postswitch();
349  }
350  /*
351   * I plan to process other thread related events here.
352   * This will include DEBUG session requested from keyboard...
353   */
354}
355
356void processIrq(unsigned index)
357{
358  rtems_hdl_tbl[index].hdl(rtems_hdl_tbl[index].handle);
359}
360
Note: See TracBrowser for help on using the repository browser.