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

4.104.114.95
Last change on this file since cad1f38 was cad1f38, checked in by Till Straumann <strauman@…>, on 11/06/07 at 21:44:07

2007-11-06 Till Straumann <strauman@…>

  • shared/irq/irq.c: test for non-NULL-ness before calling 'on'/'off' methods so that users don't have to provide no-ops if they don't want this feature.
  • Property mode set to 100644
File size: 9.5 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_number irqLine)
58{
59  unsigned short        mask;
60  rtems_interrupt_level level;
61
62  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
63       ((int)irqLine > BSP_MAX_OFFSET )
64       )
65    return 1;
66
67  rtems_interrupt_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  rtems_interrupt_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_number irqLine)
93{
94  unsigned short        mask;
95  rtems_interrupt_level level;
96
97  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
98       ((int)irqLine > BSP_MAX_OFFSET )
99       )
100    return 1;
101
102  rtems_interrupt_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  rtems_interrupt_enable(level);
116
117  return 0;
118} /* mask_irq */
119
120int BSP_irq_enabled_at_i8259s           (const rtems_irq_number 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_number 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    rtems_interrupt_level       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    rtems_interrupt_disable(level);
216    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
217          rtems_interrupt_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        if (irq->on)
233        irq->on(irq);
234
235    rtems_interrupt_enable(level);
236
237    return 1;
238}
239
240int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
241{
242    rtems_interrupt_level       level;
243
244    if (!isValidInterrupt(irq->name)) {
245      return 0;
246    }
247    rtems_interrupt_disable(level);
248      *irq = rtems_hdl_tbl[irq->name];
249    rtems_interrupt_enable(level);
250    return 1;
251}
252
253int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
254{
255    rtems_interrupt_level       level;
256
257    if (!isValidInterrupt(irq->name)) {
258      return 0;
259    }
260    /*
261     * Check if default handler is actually connected. If not issue an error.
262     * You must first get the current handler via i386_get_current_idt_entry
263     * and then disconnect it using i386_delete_idt_entry.
264     * RATIONALE : to always have the same transition by forcing the user
265     * to get the previous handler before accepting to disconnect.
266     */
267    rtems_interrupt_disable(level);
268    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
269      rtems_interrupt_enable(level);
270      return 0;
271    }
272
273    /*
274     * disable interrupt at PIC level
275     */
276    BSP_irq_disable_at_i8259s (irq->name);
277
278    /*
279     * Disable interrupt on device
280     */
281        if (irq->off)
282        irq->off(irq);
283
284    /*
285     * restore the default irq value
286     */
287    rtems_hdl_tbl[irq->name] = default_rtems_entry;
288
289    rtems_interrupt_enable(level);
290
291    return 1;
292}
293
294/*
295 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
296 */
297
298int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
299{
300    int                    i;
301    rtems_interrupt_level  level;
302
303    /*
304     * Store various code accelerators
305     */
306    internal_config             = config;
307    default_rtems_entry         = config->defaultEntry;
308    rtems_hdl_tbl               = config->irqHdlTbl;
309
310    rtems_interrupt_disable(level);
311    /*
312     * set up internal tables used by rtems interrupt prologue
313     */
314    compute_i8259_masks_from_prio ();
315
316    for (i=0; i < internal_config->irqNb; i++) {
317      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
318        BSP_irq_enable_at_i8259s (i);
319        if (rtems_hdl_tbl[i].on)
320                rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
321      }
322      else {
323        if (rtems_hdl_tbl[i].off)
324                rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
325        BSP_irq_disable_at_i8259s (i);
326      }
327    }
328    /*
329     * must enable slave pic anyway
330     */
331    BSP_irq_enable_at_i8259s (2);
332    rtems_interrupt_enable(level);
333    return 1;
334}
335
336int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
337{
338    *config = internal_config;
339    return 0;
340}
341
342void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
343{
344  /*
345   * Process pending signals that have not already been
346   * processed by _Thread_Displatch. This happens quite
347   * unfrequently : the ISR must have posted an action
348   * to the current running thread.
349   */
350  if ( _Thread_Do_post_task_switch_extension ||
351       _Thread_Executing->do_post_task_switch_extension ) {
352    _Thread_Executing->do_post_task_switch_extension = FALSE;
353    _API_extensions_Run_postswitch();
354  }
355  /*
356   * I plan to process other thread related events here.
357   * This will include DEBUG session requested from keyboard...
358   */
359}
360
361void processIrq(unsigned index)
362{
363  rtems_hdl_tbl[index].hdl(rtems_hdl_tbl[index].handle);
364}
365
Note: See TracBrowser for help on using the repository browser.