source: multiio/pcmmio/mio_io_rtems.c

Last change on this file was 03aa739, checked in by Joel Sherrill <joel.sherrill@…>, on 10/05/11 at 18:07:48

2011-10-05 Joel Sherrill <joel.sherrill@…>

  • mio_io_rtems.c, multiio_pcmmio.c: Rework interrupt handler to reduce overhead per pin change.
  • Property mode set to 100644
File size: 21.9 KB
Line 
1/* mio_io.c WinSystems support module file for the  PCM-MIO RTEMS driver
2 *
3 *  $Id$
4 *
5 *  This file implements the hardware access routines as implemented for RTEMS.
6 *  This is very likely close to what is required with no OS.
7 */
8
9/* #define DEBUG 1 */
10
11#include "mio_io.h"   
12
13#include <stdio.h>
14#include <fcntl.h>      /* open */
15#include <unistd.h>     /* exit */
16#include <sys/ioctl.h>  /* ioctl */
17#include <stdlib.h>     /* for exit */
18
19#include <rtems.h>
20#include <i386_io.h>
21#include <bsp/irq.h>
22
23/*
24 *  These are configured by the initialization call.
25 */
26
27/* IRQ source or 0 ==> polled */
28static unsigned short irq = 0;
29/* This holds the base addresses of the board */
30static unsigned short base_port = 0;
31
32/* Function prototypes for local functions */
33static int get_buffered_int(
34  struct timespec *timestamp
35);
36static void init_io(unsigned short io_address);
37static void clr_int(int bit_number);
38static int get_int(void);
39
40int report_dio_ints(void);
41
42/* RTEMS Ids for Wait Queues */
43rtems_id wq_a2d_1;
44rtems_id wq_a2d_2;
45rtems_id wq_dac_1;
46rtems_id wq_dac_2;
47rtems_id wq_dio;
48
49/*
50 *  Limits on number of buffered discrete input interrupts in
51 *  the message queue.
52 */
53#define MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS 1024
54
55///////////////////////////////////////////////////////////////////////////////
56typedef struct {
57  struct timespec timestamp;
58  int             pin;
59} din_message_t;
60
61unsigned int pcmmio_dio_missed_interrupts;
62
63int interruptible_sleep_on(
64  rtems_id *id,
65  int       milliseconds
66);
67void wake_up_interruptible(
68  rtems_id *id
69);
70
71//
72//    MIO_READ_IRQ_ASSIGNED
73//
74//////////////////////////////////////////////////////////////////////////////
75
76int mio_read_irq_assigned(void)
77{
78  mio_error_code = MIO_SUCCESS;
79
80  if (check_handle())   /* Check for chip available */
81    return -1;
82
83  /* All of our programming of the hardware is handled at this level so that
84     all of the routines that need to shove and IRQ value into hardware will
85     use this call.
86  */
87
88  return (irq & 0xff);
89}
90
91///////////////////////////////////////////////////////////////////////////////
92//
93//    READ_DIO_BYTE
94//
95//////////////////////////////////////////////////////////////////////////////
96
97unsigned char read_dio_byte(int offset)
98{
99  unsigned char byte_val;
100  unsigned char offset_val;
101
102  mio_error_code = MIO_SUCCESS;
103
104  if (check_handle())   /* Check for chip available */
105    return -1;
106
107  /* All bit operations are handled at this level so we need only
108     read and write bytes from the actual hardware.
109  */
110
111  offset_val = offset & 0xff;
112  byte_val = inb(base_port + 0x10 + offset_val);
113  return (byte_val & 0xff);
114}
115
116///////////////////////////////////////////////////////////////////////////////
117//
118//    MIO_READ_REG
119//
120//////////////////////////////////////////////////////////////////////////////
121
122unsigned char mio_read_reg(int offset)
123{
124  unsigned char byte_val;
125  unsigned char offset_val;
126
127  mio_error_code = MIO_SUCCESS;
128
129  if (check_handle())   /* Check for chip available */
130    return -1;
131
132
133  /* This is a catchall register read routine that allows reading of
134     ANY of the registers on the PCM-MIO. It is used primarily for
135     retreiving control and access values in the hardware.
136   */
137
138  offset_val = offset & 0xff;
139  byte_val = inb(base_port + offset_val);
140  return (byte_val & 0xff);
141}
142
143///////////////////////////////////////////////////////////////////////////////
144//
145//    MIO_WRITE_REG
146//
147//////////////////////////////////////////////////////////////////////////////
148
149int mio_write_reg(int offset, unsigned char value)
150{
151  unsigned char byte_val;
152  unsigned char offset_val;
153
154  mio_error_code = MIO_SUCCESS;
155
156  if (check_handle())   /* Check for chip available */
157    return -1;
158
159  /* This function like the previous allow unlimited
160     write access to ALL of the registers on the PCM-MIO
161   */
162
163  offset_val = offset & 0xff;
164  byte_val = value;
165  outb(byte_val, base_port + offset_val);
166 
167  return 0;
168}
169
170
171///////////////////////////////////////////////////////////////////////////////
172//
173//    WRITE_DIO_BYTE
174//
175//////////////////////////////////////////////////////////////////////////////
176
177int write_dio_byte(int offset, unsigned char value)
178{
179  unsigned char byte_val;
180  unsigned char offset_val;
181
182  mio_error_code = MIO_SUCCESS;
183
184  if (check_handle())   /* Check for chip available */
185    return -1;
186
187  /* All bit operations for the DIO are handled at this level
188     and we need the driver to allow access to the actual
189     DIO registers to update the value.
190  */
191
192  offset_val = offset & 0xff;
193  byte_val = value;
194  outb(byte_val, base_port + 0x10 + offset_val);
195
196  return 0;
197}
198
199
200///////////////////////////////////////////////////////////////////////////////
201//
202//    WRITE_DAC_COMMAND
203//
204//////////////////////////////////////////////////////////////////////////////
205
206int write_dac_command(int dac_num,unsigned char value)
207{
208  unsigned char  byte_val;
209  unsigned char  offset_val;
210
211  mio_error_code = MIO_SUCCESS;
212
213  if (check_handle())   /* Check for chip available */
214    return -1;
215
216  byte_val = dac_num & 0xff;            /* This is the DAC number */
217  offset_val = value;                   /* This is the data value */
218  if (byte_val)
219    outb(offset_val,base_port + 0x0e);
220  else
221    outb(offset_val,base_port + 0x0a);
222
223  return 0;
224}
225
226///////////////////////////////////////////////////////////////////////////////
227//
228//    WRITE_ADC_COMMAND
229//
230//////////////////////////////////////////////////////////////////////////////
231
232int write_adc_command(int adc_num,unsigned char value)
233{
234  unsigned char byte_val;
235  unsigned char offset_val;
236
237  mio_error_code = MIO_SUCCESS;
238
239  if (check_handle())   /* Check for chip available */
240    return -1;
241
242  byte_val = adc_num & 0xff;            /* This is the ADC number */
243  offset_val = value;                   /* This is the data value */
244
245  if(byte_val)
246    outb(offset_val,base_port + 0x06);
247  else
248    outb(offset_val,base_port + 0x02);
249  return 0;
250}
251
252///////////////////////////////////////////////////////////////////////////////
253//
254//    WRITE_DAC_DATA
255//
256//////////////////////////////////////////////////////////////////////////////
257
258int write_dac_data(int dac_num, unsigned short value)
259{
260  unsigned short word_val;
261  unsigned char byte_val;
262
263  mio_error_code = MIO_SUCCESS;
264
265  if (check_handle())   /* Check for chip available */
266    return -1;
267
268  byte_val = dac_num;
269  word_val = value;
270
271  if(byte_val)          /* DAC 1 */
272    outw(word_val,base_port+0x0c);
273  else
274    outw(word_val,base_port+8);
275 
276  return 0;
277}
278
279///////////////////////////////////////////////////////////////////////////////
280//
281//    DAC_READ_STATUS
282//
283//////////////////////////////////////////////////////////////////////////////
284
285unsigned char dac_read_status(int dac_num)
286{
287  mio_error_code = MIO_SUCCESS;
288
289  if (check_handle())   /* Check for chip available */
290    return -1;
291
292  if (dac_num)
293    return inb(base_port + 0x0f);
294
295  return inb(base_port + 0x0b);
296}
297
298///////////////////////////////////////////////////////////////////////////////
299//
300//    ADC_READ_STATUS
301//
302//////////////////////////////////////////////////////////////////////////////
303
304unsigned char adc_read_status(int adc_num)
305{
306  mio_error_code = MIO_SUCCESS;
307
308  if (check_handle())   /* Check for chip available */
309    return -1;
310
311  if (adc_num)
312    return inb(base_port + 7);
313  return inb(base_port + 3);
314}
315
316///////////////////////////////////////////////////////////////////////////////
317//
318//    ADC_READ_CONVERSION_DATA
319//
320//////////////////////////////////////////////////////////////////////////////
321
322unsigned short adc_read_conversion_data(int channel)
323{
324  int adc_num;
325
326  mio_error_code = MIO_SUCCESS;
327
328  if (check_handle())   /* Check for chip available */
329    return -1;
330
331  if (channel > 7)
332    adc_num = 1;
333  else
334    adc_num = 0;
335
336  if (adc_num)
337    return inw(base_port + 4);
338
339  return inw(base_port);
340}
341
342
343int dio_get_int_with_timestamp(
344  struct timespec *timestamp
345)
346{
347  mio_error_code = MIO_SUCCESS;
348
349  if (check_handle())   /* Check for chip available */
350    return -1;
351
352  return get_buffered_int(timestamp) & 0xff;
353}
354
355int dio_get_int(void)
356{
357  mio_error_code = MIO_SUCCESS;
358
359  return dio_get_int_with_timestamp(NULL);
360}
361
362int wait_adc_int_with_timeout(int adc_num, int milliseconds)
363{
364  int sc;
365
366  mio_error_code = MIO_SUCCESS;
367
368  if (check_handle())   /* Check for chip available */
369    return -1;
370
371  if (adc_num) {
372    sc = interruptible_sleep_on(&wq_a2d_1, milliseconds);
373  } else {
374    sc = interruptible_sleep_on(&wq_a2d_2, milliseconds);
375  }
376
377  return sc;
378}
379
380int wait_adc_int(int adc_num)
381{
382  return wait_adc_int_with_timeout(adc_num, 0);
383}
384
385int wait_dac_int_with_timeout(int dac_num, int milliseconds)
386{
387  int sc;
388
389  mio_error_code = MIO_SUCCESS;
390
391  if (check_handle())   /* Check for chip available */
392    return -1;
393
394  if (dac_num) {
395    sc = interruptible_sleep_on(&wq_dac_1, milliseconds);
396  } else {
397    sc = interruptible_sleep_on(&wq_dac_2, milliseconds);
398  }
399
400  return sc;
401}
402
403int wait_dac_int(int dac_num)
404{
405  return wait_dac_int_with_timeout(dac_num, 0);
406}
407
408int wait_dio_int_with_timestamp(
409  int              milliseconds,
410  struct timespec *timestamp
411)
412{
413  rtems_status_code  rc;
414  din_message_t      din;
415  size_t             received;
416
417  mio_error_code = MIO_SUCCESS;
418
419  if (check_handle())   /* Check for chip available */
420    return -1;
421
422  rc = rtems_message_queue_receive(
423    wq_dio,
424    &din,
425    &received,
426    RTEMS_DEFAULT_OPTIONS,
427    RTEMS_MILLISECONDS_TO_TICKS(milliseconds)
428  );
429  if ( rc == RTEMS_UNSATISFIED ) {
430    mio_error_code = MIO_READ_DATA_FAILURE;
431    return -1;
432  }
433
434  if ( rc == RTEMS_TIMEOUT ) {
435    mio_error_code = MIO_TIMEOUT_ERROR;
436    return -1;
437  }
438
439  if ( rc != RTEMS_SUCCESSFUL ) {
440    printk( "wait_dio_int_with_timestamp - error %d\n", rc );
441    exit( 0 );
442  }
443
444  if (timestamp)
445    *timestamp = din.timestamp;
446  return din.pin;
447}
448
449int wait_dio_int_with_timeout(int milliseconds)
450{
451  return wait_dio_int_with_timestamp(milliseconds, NULL);
452}
453
454int wait_dio_int(void)
455{
456  return wait_dio_int_with_timestamp(0, NULL);
457}
458
459static int handle = 0; /* XXX move to lower */
460
461int check_handle(void)
462{
463  if (handle > 0)  /* If it's already a valid handle */
464    return 0;
465
466  if (handle == -1)  /* If it's already been tried */
467  {
468    mio_error_code = MIO_OPEN_ERROR;
469    sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
470    return -1;
471  }
472
473  /*
474   * 0  ==> not initialized
475   * 1+ ==> valid file handle, thus initialized
476   * -1 ==> already attempted to open
477   */
478  handle = 1;
479  return 0;
480
481  /* if an error happens, go here */
482  mio_error_code = MIO_OPEN_ERROR;
483  sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
484  handle = -1;
485  return -1;
486}
487
488/*
489 *  RTEMS barrier create helper
490 */
491void pcmmio_barrier_create(
492  rtems_name  name,
493  rtems_id   *id
494)
495{
496  rtems_status_code rc;
497
498  rc = rtems_barrier_create( name, RTEMS_BARRIER_MANUAL_RELEASE, 0, id );
499  if ( rc == RTEMS_SUCCESSFUL )
500    return;
501
502 printk( "Unable to create PCMMIO Barrier\n" );
503 exit(1);
504}
505
506/*
507 *  RTEMS barrier create helper
508 */
509void pcmmio_din_queue_create(
510  rtems_name  name,
511  rtems_id   *id
512)
513{
514  rtems_status_code rc;
515
516  rc = rtems_message_queue_create(
517    name,
518    MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS,
519    sizeof(din_message_t),
520    RTEMS_DEFAULT_ATTRIBUTES,
521    id
522  );
523  if ( rc == RTEMS_SUCCESSFUL )
524    return;
525
526  printk( "Unable to create PCMMIO DIN IRQ Message Queue\n" );
527  exit(1);
528}
529
530int interruptible_sleep_on(
531  rtems_id *id,
532  int       milliseconds
533)
534{
535  rtems_status_code rc;
536
537  rc = rtems_barrier_wait(*id, RTEMS_MILLISECONDS_TO_TICKS(milliseconds));
538  if ( rc == RTEMS_SUCCESSFUL )
539    return 0;
540
541  mio_error_code = MIO_TIMEOUT_ERROR;
542  return -1;
543}
544
545void wake_up_interruptible(
546  rtems_id *id
547)
548{
549  uint32_t  unblocked;
550
551  (void) rtems_barrier_release(*id, &unblocked);
552}
553
554/*
555 *  RTEMS specific interrupt handler
556 */
557#include <bsp/irq.h>
558
559void common_handler(void);
560
561void pcmmio_irq_handler(
562  rtems_irq_hdl_param param
563)
564{
565  common_handler();
566}
567
568static void pcmmio_irq_disable(const rtems_irq_connect_data *irq)
569{
570  BSP_irq_disable_at_i8259s(irq->name);
571}
572static void pcmmio_irq_enable(const rtems_irq_connect_data *irq)
573{
574  BSP_irq_enable_at_i8259s(irq->name);
575}
576
577static int pcmmio_irq_is_on(const rtems_irq_connect_data *irq)
578{
579  return BSP_irq_enabled_at_i8259s( irq->name );
580}
581
582rtems_irq_connect_data pcmmio_irq = {
583  0,                            // name
584  pcmmio_irq_handler,           // handler
585  NULL,                         // parameter
586  pcmmio_irq_enable,            // enable IRQ
587  pcmmio_irq_disable,           // disable IRQ
588  pcmmio_irq_is_on,             // is IRQ enabled
589};
590
591/* from pcmmio.c - GNU/Linux driver */
592void init_io(unsigned short io_address)
593{
594  int x;
595  unsigned short port;
596
597  /* save the address for later use */
598  port = io_address + 0X10;
599
600  /* Clear all of the I/O ports. This also makes them inputs */
601  for(x=0; x < 7; x++)
602    outb(0,port+x);
603
604  /* Set page 2 access, for interrupt enables */
605  outb(0x80,port+7);
606
607  /* Clear all interrupt enables */
608  outb(0,port+8);
609  outb(0,port+9);
610  outb(0,port+0x0a);
611
612  /* Restore page 0 register access */
613  outb(0,port+7);
614}
615
616/*
617 * RTEMS specific initialization routine
618 */
619void pcmmio_initialize(
620  unsigned short _base_port,
621  unsigned short _irq
622)
623{
624  /* hardware configuration information */
625  base_port                    = _base_port;
626  irq                          = _irq;
627  pcmmio_dio_missed_interrupts = 0;
628
629  /* Create RTEMS Objects */
630  pcmmio_barrier_create( rtems_build_name( 'a', '2', 'd', '1' ), &wq_a2d_1 );
631  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '1' ), &wq_dac_1 );
632  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '2' ), &wq_dac_2 );
633  pcmmio_din_queue_create( rtems_build_name( 'd', 'i', 'o', ' ' ), &wq_dio );
634
635  if ( base_port )
636    init_io( base_port );
637
638  /* install IRQ handler */
639  if ( base_port && irq ) {
640    int status = 0;
641
642    /*
643     *  Process any pending interrupts
644     */
645
646    common_handler();
647
648    pcmmio_irq.name = irq;
649    #if defined(BSP_SHARED_HANDLER_SUPPORT)
650      printk( "PCMMIO Installing IRQ handler as shared\n" );
651      status = BSP_install_rtems_shared_irq_handler( &pcmmio_irq );
652    #else
653      printk( "PCMMIO Installing IRQ handler as non-shared\n" );
654      status = BSP_install_rtems_irq_handler( &pcmmio_irq );
655    #endif
656    if ( !status ) {
657      printk("Error installing PCMMIO interrupt handler! status=%d\n", status );
658    }
659  }
660}
661
662/*
663 *  From this point down, we should be able to share easily with the Linux
664 *  driver but I haven't gone to the trouble to do surgery on it.  I have
665 *  no way to test it.
666 */
667
668/* real copy is in mio_io.c */
669extern unsigned char adc2_port_image;
670
671/* This is the common interrupt handler. It is called by the
672 * actual hardware ISR.
673 */
674
675void common_handler(void)
676{
677  unsigned char status;
678#if 0
679  unsigned char int_num;
680#endif
681
682  /* Read the interrupt ID register from ADC2 */
683  adc2_port_image = adc2_port_image | 0x20;
684  outb(adc2_port_image,base_port + 0x0f);
685
686  status = inb(base_port + 0x0f);
687#if !defined(PCMMIO_DISABLE_ADC_IRQ)
688  if (status & 1) {
689    /* Clear ADC1 interrupt */
690    inb(base_port+1);      /* Clear interrupt */
691
692    /* Wake up any holding processes */
693    wake_up_interruptible(&wq_a2d_1);
694  }
695
696  if (status & 2) {
697    /* Clear ADC1 interrupt */
698    inb(base_port+5);      /* Clear interrupt */
699
700    /* Wake up anybody waiting for ADC1 */
701    wake_up_interruptible(&wq_a2d_2);
702  }
703
704  if (status & 4) {
705    /* Clear DAC1 interrupt */
706    inb(base_port+9);    /* Clear interrupt */
707
708    /* Wake up if you're waiting on DAC1 */
709    wake_up_interruptible(&wq_dac_1);
710  }
711#endif
712
713  if (status & 8) {
714
715#if 1
716    report_dio_ints();
717#else
718    /* DIO interrupt. Find out which bit */
719    int_num = get_int();
720    if (int_num) {
721      rtems_status_code  rc;
722      din_message_t      din;
723
724      rtems_clock_get_uptime( &din.timestamp );
725      din.pin = int_num;
726
727      rc = rtems_message_queue_send( wq_dio, &din, sizeof(din_message_t) );
728      if ( rc != RTEMS_SUCCESSFUL ) {
729        pcmmio_dio_missed_interrupts++;
730        #ifdef DEBUG
731          printk("<1>Missed DIO interrupt\n" );
732        #endif
733     }
734     #ifdef DEBUG
735       printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
736     #endif
737
738      /* Clear the interrupt */
739      clr_int(int_num);
740    }
741#endif
742  }
743
744  if (status & 0x10) {
745    /* Clear DAC2 Interrupt */
746    inb(base_port+0x0d);    /* Clear interrupt */
747
748    /* Wake up DAC2 holding processes */
749    wake_up_interruptible(&wq_dac_2);
750  }
751
752  /* Reset the access to the interrupt ID register */
753  adc2_port_image = adc2_port_image & 0xdf;
754  outb(adc2_port_image,base_port+0x0f);
755}
756
757
758void clr_int(int bit_number)
759{
760  unsigned short port;
761  unsigned short temp;
762  unsigned short mask;
763  unsigned short dio_port;
764
765  dio_port = base_port + 0x10;
766
767  /* Also adjust bit number */
768  --bit_number;
769
770  /* Calculate the I/O address based upon bit number */
771  port = (bit_number / 8) + dio_port + 8;
772
773  /* Calculate a bit mask based upon the specified bit number */
774  mask = (1 << (bit_number % 8));
775
776  /* Turn on page 2 access */
777  outb(0x80,dio_port+7);
778
779  /* Get the current state of the interrupt enable register */
780  temp = inb(port);
781
782  /* Temporarily clear only our enable. This clears the interrupt */
783  temp = temp & ~mask;    /* Clear the enable for this bit */
784
785  /* Now update the interrupt enable register */
786  outb(temp,port);
787
788  /* Re-enable our interrupt bit */
789  temp = temp | mask;
790  outb(temp,port);
791
792  /* Set access back to page 0 */
793  outb(0x00,dio_port+7);
794}
795
796int get_int(void)
797{
798  int temp;
799  int x;
800  unsigned short dio_port;
801
802  dio_port = base_port + 0x10;
803
804  /* Read the master interrupt pending register,
805           mask off undefined bits */
806  temp = inb(dio_port+6) & 0x07;
807
808  /* If there are no pending interrupts, return 0 */
809  if ((temp & 7) == 0)
810    return 0;
811
812  /* There is something pending, now we need to identify it */
813
814  /* Set access to page 3 for interrupt id register */
815  outb(0xc0, dio_port + 7);
816
817  /* Read the interrupt ID register for port 0 */
818  temp = inb(dio_port+8);
819
820  /* See if any bit set, if so return the bit number */
821  if (temp != 0) {
822    for (x=0; x<=7; x++) {
823      if (temp & (1 << x)) {
824        outb(0,dio_port+7);
825        return(x+1);
826       }
827    }
828  }
829
830  /* None in port 0, read port 1 interrupt ID register */
831  temp = inb(dio_port+9);
832
833  /* See if any bit set, if so return the bit number */
834  if (temp != 0) {
835    for (x=0; x<=7; x++) {
836      if (temp & (1 << x)) {
837        outb(0,dio_port+7);
838        return(x+9);
839      }
840    }
841  }
842
843  /* Lastly, read the status of port 2 interrupt ID register */
844  temp = inb(dio_port+0x0a);
845
846  /* If any pending, return the appropriate bit number */
847  if (temp != 0) {
848    for (x=0; x<=7; x++) {
849      if (temp & (1 << x)) {
850         outb(0,dio_port+7);
851         return(x+17);
852      }
853    }
854  }
855
856  /* We should never get here unless the hardware is seriously
857     misbehaving, but just to be sure, we'll turn the page access
858     back to 0 and return a 0 for no interrupt found
859  */
860  outb(0,dio_port+7);
861  return 0;
862}
863
864void report_dio_interrupt(
865  din_message_t   *din,
866  int              pin
867)
868{
869  rtems_status_code  rc;
870
871  din->pin = pin;
872
873  rc = rtems_message_queue_send( wq_dio, &din, sizeof(din_message_t) );
874  if ( rc != RTEMS_SUCCESSFUL ) {
875    pcmmio_dio_missed_interrupts++;
876    #ifdef DEBUG
877      printk("<1>Missed DIO interrupt\n" );
878    #endif
879 }
880 #ifdef DEBUG
881   printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
882 #endif
883
884  /* Clear the interrupt */
885  clr_int(pin);
886}
887
888int report_dio_ints(void)
889{
890  int                temp;
891  int                x;
892  unsigned short     dio_port;
893  din_message_t      din;
894  bool               found = false;
895
896  rtems_clock_get_uptime( &din.timestamp );
897  /* din.pin set in report_dio_interrupts() */
898
899  dio_port = base_port + 0x10;
900
901  /* Read the master interrupt pending register,
902           mask off undefined bits */
903  temp = inb(dio_port+6) & 0x07;
904
905  /* If there are no pending interrupts, return 0 */
906  if ((temp & 7) == 0)
907    return 0;
908
909  /* There is something pending, now we need to identify it */
910
911  /* Set access to page 3 for interrupt id register */
912  outb(0xc0, dio_port + 7);
913
914  /* Read the interrupt ID register for port 0 */
915  temp = inb(dio_port+8);
916
917  /* See if any bit set, if so return the bit number */
918  for (x=0; temp && x<=7; x++) {
919    if (temp & (1 << x)) {
920      outb(0,dio_port+7);
921      report_dio_interrupt( &din, x+1 );
922      found = true;
923      temp &= ~(1 << x);
924    }
925  }
926
927  /* Now check port 0, read port 1 interrupt ID register */
928  temp = inb(dio_port+9);
929
930  /* See if any bit set, if so return the bit number */
931  for (x=0; temp && x<=7; x++) {
932    if (temp & (1 << x)) {
933      outb(0,dio_port+7);
934      report_dio_interrupt( &din, x+9 );
935      found = true;
936      temp &= ~(1 << x);
937    }
938  }
939
940  /* Now read the status of port 2 interrupt ID register */
941  temp = inb(dio_port+0x0a);
942
943  /* If any pending, return the appropriate bit number */
944  for (x=0; temp && x<=7; x++) {
945    if (temp & (1 << x)) {
946      outb(0,dio_port+7);
947      report_dio_interrupt( &din, x+17 );
948      temp &= ~(1 << x);
949      found = true;
950    }
951  }
952
953  /* We should never get here unless the hardware is seriously
954     misbehaving, but just to be sure, we'll turn the page access
955     back to 0 and return a 0 for no interrupt found
956  */
957  if ( !found )
958    outb(0,dio_port+7);
959  return 0;
960}
961
962void flush_buffered_ints(void)
963{
964  rtems_status_code  rc;
965  size_t             flushed;
966
967  rc = rtems_message_queue_flush( wq_dio, &flushed );
968  if ( rc != RTEMS_SUCCESSFUL ) {
969    printk( "flushed_buffered_int - error %d\n", rc );
970    exit( 0 );
971  }
972}
973
974int get_buffered_int(
975  struct timespec *timestamp
976)
977{
978  rtems_status_code  rc;
979  din_message_t      din;
980  int                line;
981  size_t             received;
982
983  if (irq == 0) {
984    line = get_int();
985    if (line)
986      clr_int(line);
987    return line;
988  }
989
990  rc = rtems_message_queue_receive(
991    wq_dio,
992    &din,
993    &received,
994    RTEMS_NO_WAIT,
995    0
996  );
997  if ( rc == RTEMS_UNSATISFIED ) {
998    mio_error_code = MIO_READ_DATA_FAILURE;
999    return 0;
1000  }
1001
1002  if ( rc != RTEMS_SUCCESSFUL ) {
1003    printk( "get_buffered_int - error %d\n", rc );
1004    exit( 0 );
1005  }
1006
1007  if (timestamp)
1008    *timestamp = din.timestamp;
1009  return din.pin;
1010}
1011
1012int dio_get_missed_interrupts(void)
1013{
1014  int isrs;
1015
1016  isrs = pcmmio_dio_missed_interrupts;
1017
1018  pcmmio_dio_missed_interrupts = 0;
1019
1020  return isrs;
1021}
Note: See TracBrowser for help on using the repository browser.