source: multiio/pcmmio/original/mio_io_rtems.c @ 217770e

Last change on this file since 217770e was 217770e, checked in by Joel Sherrill <joel.sherrill@…>, on 12/14/09 at 15:55:14

2009-12-14 Joel Sherrill <joel.sherrill@…>

  • Makefile, README, mio_io_rtems.c, pcmmio_commands.h: Add command to benchmark discrete input including message queue send and receive.
  • main_pcmmio_benchmark.c: New file.
  • Property mode set to 100644
File size: 19.3 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 */
33int get_buffered_int(
34  unsigned long long *timestamp
35);
36void init_io(unsigned short io_address);
37void clr_int(int bit_number);
38int 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    return -1;
429
430  if ( rc == RTEMS_TIMEOUT )
431    return -1;
432
433  if ( rc != RTEMS_SUCCESSFUL ) {
434    printk( "wait_dio_int_with_timestamp - error %d\n", rc );
435    exit( 0 );
436  }
437
438  if (timestamp)
439    *timestamp = din.timestamp;
440  return din.pin;
441}
442
443int wait_dio_int_with_timeout(int milliseconds)
444{
445  return wait_dio_int_with_timestamp(milliseconds, NULL);
446}
447
448int wait_dio_int(void)
449{
450  return wait_dio_int_with_timestamp(0, NULL);
451}
452
453static int handle = 0; /* XXX move to lower */
454
455int check_handle(void)
456{
457  if (handle > 0)  /* If it's already a valid handle */
458    return 0;
459
460  if (handle == -1)  /* If it's already been tried */
461  {
462    mio_error_code = MIO_OPEN_ERROR;
463    sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
464    return -1;
465  }
466
467  /*
468   * 0  ==> not initialized
469   * 1+ ==> valid file handle, thus initialized
470   * -1 ==> already attempted to open
471   */
472  handle = 1;
473  return 0;
474
475  /* if an error happens, go here */
476  mio_error_code = MIO_OPEN_ERROR;
477  sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
478  handle = -1;
479  return -1;
480}
481
482/*
483 *  RTEMS barrier create helper
484 */
485void pcmmio_barrier_create(
486  rtems_name  name,
487  rtems_id   *id
488)
489{
490  rtems_status_code rc;
491
492  rc = rtems_barrier_create( name, RTEMS_BARRIER_MANUAL_RELEASE, 0, id );
493  if ( rc == RTEMS_SUCCESSFUL )
494    return;
495
496 printk( "Unable to create PCMMIO Barrier\n" );
497 exit(1);
498}
499
500/*
501 *  RTEMS barrier create helper
502 */
503void pcmmio_din_queue_create(
504  rtems_name  name,
505  rtems_id   *id
506)
507{
508  rtems_status_code rc;
509
510  rc = rtems_message_queue_create(
511    name,
512    MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS,
513    sizeof(din_message_t),
514    RTEMS_DEFAULT_ATTRIBUTES,
515    id
516  );
517  if ( rc == RTEMS_SUCCESSFUL )
518    return;
519
520  printk( "Unable to create PCMMIO DIN IRQ Message Queue\n" );
521  exit(1);
522}
523
524int interruptible_sleep_on(
525  rtems_id *id,
526  int       milliseconds
527)
528{
529  rtems_status_code rc;
530
531  rc = rtems_barrier_wait(*id, RTEMS_MILLISECONDS_TO_TICKS(milliseconds));
532  if ( rc == RTEMS_SUCCESSFUL )
533    return 0;
534  return -1;
535}
536
537void wake_up_interruptible(
538  rtems_id *id
539)
540{
541  rtems_status_code rc;
542  uint32_t          unblocked;
543
544  rc = rtems_barrier_release(*id, &unblocked);
545}
546
547/*
548 *  RTEMS specific interrupt handler
549 */
550#include <bsp/irq.h>
551
552void common_handler(void);
553
554void pcmmio_irq_handler(
555  rtems_irq_hdl_param param
556)
557{
558  common_handler();
559}
560
561static void pcmmio_irq_disable(const rtems_irq_connect_data *irq)
562{
563  BSP_irq_disable_at_i8259s(irq->name);
564}
565static void pcmmio_irq_enable(const rtems_irq_connect_data *irq)
566{
567  BSP_irq_enable_at_i8259s(irq->name);
568}
569
570static int pcmmio_irq_is_on(const rtems_irq_connect_data *irq)
571{
572  return BSP_irq_enabled_at_i8259s( irq->name );
573}
574
575rtems_irq_connect_data pcmmio_irq = {
576  0,                            // name
577  pcmmio_irq_handler,           // handler
578  NULL,                         // parameter
579  pcmmio_irq_enable,            // enable IRQ
580  pcmmio_irq_disable,           // disable IRQ
581  pcmmio_irq_is_on,             // is IRQ enabled
582};
583
584/* from pcmmio.c - GNU/Linux driver */
585void init_io(unsigned short io_address)
586{
587  int x;
588  unsigned short port;
589
590  /* save the address for later use */
591  port = io_address + 0X10;
592
593  /* Clear all of the I/O ports. This also makes them inputs */
594  for(x=0; x < 7; x++)
595    outb(0,port+x);
596
597  /* Set page 2 access, for interrupt enables */
598  outb(0x80,port+7);
599
600  /* Clear all interrupt enables */
601  outb(0,port+8);
602  outb(0,port+9);
603  outb(0,port+0x0a);
604
605  /* Restore page 0 register access */
606  outb(0,port+7);
607}
608
609/*
610 * RTEMS specific initialization routine
611 */
612void pcmmio_initialize(
613  unsigned short _base_port,
614  unsigned short _irq
615)
616{
617  /* hardware configuration information */
618  base_port                    = _base_port;
619  irq                          = _irq;
620  pcmmio_dio_missed_interrupts = 0;
621
622  /* Create RTEMS Objects */
623  pcmmio_barrier_create( rtems_build_name( 'a', '2', 'd', '1' ), &wq_a2d_1 );
624  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '1' ), &wq_dac_1 );
625  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '2' ), &wq_dac_2 );
626  pcmmio_din_queue_create( rtems_build_name( 'd', 'i', 'o', ' ' ), &wq_dio );
627
628  if ( base_port )
629    init_io( base_port );
630
631  /* install IRQ handler */
632  if ( base_port && irq ) {
633    int status = 0;
634    pcmmio_irq.name = irq;
635    #if defined(BSP_SHARED_HANDLER_SUPPORT)
636      printk( "PCMMIO Installing IRQ handler as shared\n" );
637      status = BSP_install_rtems_shared_irq_handler( &pcmmio_irq );
638    #else
639      printk( "PCMMIO Installing IRQ handler as non-shared\n" );
640      status = BSP_install_rtems_irq_handler( &pcmmio_irq );
641    #endif
642    if ( !status ) {
643      printk("Error installing PCMMIO interrupt handler! status=%d\n", status );
644    }
645  }
646}
647
648#include <libcpu/cpuModel.h> /* for rdtsc */
649
650/*
651 *  From this point down, we should be able to share easily with the Linux
652 *  driver but I haven't gone to the trouble to do surgery on it.  I have
653 *  no way to test it.
654 */
655
656/* real copy is in mio_io.c */
657extern unsigned char adc2_port_image;
658
659/* This is the common interrupt handler. It is called by the
660 * actual hardware ISR.
661 */
662
663void common_handler(void)
664{
665  unsigned char status;
666  unsigned char int_num;
667
668  /* Read the interrupt ID register from ADC2 */
669
670  adc2_port_image = adc2_port_image | 0x20;
671  outb(adc2_port_image,base_port + 0x0f);
672
673  status = inb(base_port + 0x0f);
674  if (status & 1) {
675    /* Clear ADC1 interrupt */
676    inb(base_port+1);      /* Clear interrupt */
677
678    /* Wake up any holding processes */
679    wake_up_interruptible(&wq_a2d_1);
680  }
681
682  if (status & 2) {
683    /* Clear ADC1 interrupt */
684    inb(base_port+5);      /* Clear interrupt */
685
686    /* Wake up anybody waiting for ADC1 */
687    wake_up_interruptible(&wq_a2d_2);
688  }
689
690  if (status & 4) {
691    /* Clear DAC1 interrupt */
692    inb(base_port+9);    /* Clear interrupt */
693
694    /* Wake up if you're waiting on DAC1 */
695    wake_up_interruptible(&wq_dac_1);
696  }
697
698  if (status & 8) {
699
700    /* DIO interrupt. Find out which bit */
701    int_num = get_int();
702    if (int_num) {
703      rtems_status_code  rc;
704      din_message_t      din;
705
706      din.timestamp = rdtsc();
707      din.pin       = int_num;
708
709      rc = rtems_message_queue_send( wq_dio, &din, sizeof(din_message_t) );
710      if ( rc != RTEMS_SUCCESSFUL ) {
711        pcmmio_dio_missed_interrupts++;
712        #ifdef DEBUG
713          printk("<1>Missed DIO interrupt\n" );
714        #endif
715     }
716     #ifdef DEBUG
717       printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
718     #endif
719
720      /* Clear the interrupt */
721      clr_int(int_num);
722    }
723  }
724
725  if (status & 0x10) {
726    /* Clear DAC2 Interrupt */
727    inb(base_port+0x0d);    /* Clear interrupt */
728
729    /* Wake up DAC2 holding processes */
730    wake_up_interruptible(&wq_dac_2);
731  }
732
733  /* Reset the access to the interrupt ID register */
734  adc2_port_image = adc2_port_image & 0xdf;
735  outb(adc2_port_image,base_port+0x0f);
736}
737
738
739void clr_int(int bit_number)
740{
741  unsigned short port;
742  unsigned short temp;
743  unsigned short mask;
744  unsigned short dio_port;
745
746  dio_port = base_port + 0x10;
747
748  /* Also adjust bit number */
749  --bit_number;
750
751  /* Calculate the I/O address based upon bit number */
752  port = (bit_number / 8) + dio_port + 8;
753
754  /* Calculate a bit mask based upon the specified bit number */
755  mask = (1 << (bit_number % 8));
756
757  /* Turn on page 2 access */
758  outb(0x80,dio_port+7);
759
760  /* Get the current state of the interrupt enable register */
761  temp = inb(port);
762
763  /* Temporarily clear only our enable. This clears the interrupt */
764  temp = temp & ~mask;    /* Clear the enable for this bit */
765
766  /* Now update the interrupt enable register */
767  outb(temp,port);
768
769  /* Re-enable our interrupt bit */
770  temp = temp | mask;
771  outb(temp,port);
772
773  /* Set access back to page 0 */
774  outb(0x00,dio_port+7);
775}
776
777int get_int(void)
778{
779  int temp;
780  int x;
781  unsigned short dio_port;
782
783  dio_port = base_port + 0x10;
784
785  /* Read the master interrupt pending register,
786           mask off undefined bits */
787  temp = inb(dio_port+6) & 0x07;
788
789  /* If there are no pending interrupts, return 0 */
790  if ((temp & 7) == 0)
791    return 0;
792
793  /* There is something pending, now we need to identify it */
794
795  /* Set access to page 3 for interrupt id register */
796  outb(0xc0, dio_port + 7);
797
798  /* Read the interrupt ID register for port 0 */
799  temp = inb(dio_port+8);
800
801  /* See if any bit set, if so return the bit number */
802  if (temp != 0) {
803    for (x=0; x<=7; x++) {
804      if (temp & (1 << x)) {
805        outb(0,dio_port+7);
806        return(x+1);
807       }
808    }
809  }
810
811  /* None in port 0, read port 1 interrupt ID register */
812  temp = inb(dio_port+9);
813
814  /* See if any bit set, if so return the bit number */
815  if (temp != 0) {
816    for (x=0; x<=7; x++) {
817      if (temp & (1 << x)) {
818        outb(0,dio_port+7);
819        return(x+9);
820      }
821    }
822  }
823
824  /* Lastly, read the status of port 2 interrupt ID register */
825  temp = inb(dio_port+0x0a);
826
827  /* If any pending, return the appropriate bit number */
828  if (temp != 0) {
829    for (x=0; x<=7; x++) {
830      if (temp & (1 << x)) {
831         outb(0,dio_port+7);
832         return(x+17);
833      }
834    }
835  }
836
837  /* We should never get here unless the hardware is seriously
838     misbehaving, but just to be sure, we'll turn the page access
839     back to 0 and return a 0 for no interrupt found
840  */
841  outb(0,dio_port+7);
842  return 0;
843}
844
845void flush_buffered_ints(void)
846{
847  rtems_status_code  rc;
848  size_t             flushed;
849
850  rc = rtems_message_queue_flush( wq_dio, &flushed );
851  if ( rc != RTEMS_SUCCESSFUL ) {
852    printk( "flushed_buffered_int - error %d\n", rc );
853    exit( 0 );
854  }
855}
856
857int get_buffered_int(
858  unsigned long long *timestamp
859)
860{
861  rtems_status_code  rc;
862  din_message_t      din;
863  int                line;
864  size_t             received;
865
866  if (irq == 0) {
867    line = get_int();
868    if (line)
869      clr_int(line);
870    return line;
871  }
872
873  rc = rtems_message_queue_receive(
874    wq_dio,
875    &din,
876    &received,
877    RTEMS_NO_WAIT,
878    0
879  );
880  if ( rc == RTEMS_UNSATISFIED )
881    return 0;
882
883  if ( rc != RTEMS_SUCCESSFUL ) {
884    printk( "get_buffered_int - error %d\n", rc );
885    exit( 0 );
886  }
887
888  if (timestamp)
889    *timestamp = din.timestamp;
890  return din.pin;
891}
892
893int dio_get_missed_interrupts(void)
894{
895  int isrs;
896
897  isrs = pcmmio_dio_missed_interrupts;
898
899  pcmmio_dio_missed_interrupts = 0;
900
901  return isrs;
902}
Note: See TracBrowser for help on using the repository browser.