source: multiio/pcmmio/mio_io_rtems.c @ 13bdbee

base
Last change on this file since 13bdbee was 13bdbee, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 17, 2011 at 3:04:30 PM

Initial import.

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