source: multiio/pcmmio/mio_io_rtems.c @ d810c06

Last change on this file since d810c06 was d810c06, checked in by Joel Sherrill <joel.sherrill@…>, on 03/18/11 at 13:19:31

2011-03-18 Joel Sherrill <joel.sherrill@…>

  • Makefile, mio_io.h, mio_io_rtems.c, pcmmio_shell.c, rtems_config.c: Initial implementation.
  • .cvsignore, multiio_pcmmio.c: New files.
  • Property mode set to 100644
File size: 19.4 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
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  struct timespec 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  struct timespec *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  struct timespec *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/*
654 *  From this point down, we should be able to share easily with the Linux
655 *  driver but I haven't gone to the trouble to do surgery on it.  I have
656 *  no way to test it.
657 */
658
659/* real copy is in mio_io.c */
660extern unsigned char adc2_port_image;
661
662/* This is the common interrupt handler. It is called by the
663 * actual hardware ISR.
664 */
665
666void common_handler(void)
667{
668  unsigned char status;
669  unsigned char int_num;
670
671  /* Read the interrupt ID register from ADC2 */
672
673  adc2_port_image = adc2_port_image | 0x20;
674  outb(adc2_port_image,base_port + 0x0f);
675
676  status = inb(base_port + 0x0f);
677  if (status & 1) {
678    /* Clear ADC1 interrupt */
679    inb(base_port+1);      /* Clear interrupt */
680
681    /* Wake up any holding processes */
682    wake_up_interruptible(&wq_a2d_1);
683  }
684
685  if (status & 2) {
686    /* Clear ADC1 interrupt */
687    inb(base_port+5);      /* Clear interrupt */
688
689    /* Wake up anybody waiting for ADC1 */
690    wake_up_interruptible(&wq_a2d_2);
691  }
692
693  if (status & 4) {
694    /* Clear DAC1 interrupt */
695    inb(base_port+9);    /* Clear interrupt */
696
697    /* Wake up if you're waiting on DAC1 */
698    wake_up_interruptible(&wq_dac_1);
699  }
700
701  if (status & 8) {
702
703    /* DIO interrupt. Find out which bit */
704    int_num = get_int();
705    if (int_num) {
706      rtems_status_code  rc;
707      din_message_t      din;
708
709      rtems_clock_get_uptime( &din.timestamp );
710      din.pin = int_num;
711
712      rc = rtems_message_queue_send( wq_dio, &din, sizeof(din_message_t) );
713      if ( rc != RTEMS_SUCCESSFUL ) {
714        pcmmio_dio_missed_interrupts++;
715        #ifdef DEBUG
716          printk("<1>Missed DIO interrupt\n" );
717        #endif
718     }
719     #ifdef DEBUG
720       printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
721     #endif
722
723      /* Clear the interrupt */
724      clr_int(int_num);
725    }
726  }
727
728  if (status & 0x10) {
729    /* Clear DAC2 Interrupt */
730    inb(base_port+0x0d);    /* Clear interrupt */
731
732    /* Wake up DAC2 holding processes */
733    wake_up_interruptible(&wq_dac_2);
734  }
735
736  /* Reset the access to the interrupt ID register */
737  adc2_port_image = adc2_port_image & 0xdf;
738  outb(adc2_port_image,base_port+0x0f);
739}
740
741
742void clr_int(int bit_number)
743{
744  unsigned short port;
745  unsigned short temp;
746  unsigned short mask;
747  unsigned short dio_port;
748
749  dio_port = base_port + 0x10;
750
751  /* Also adjust bit number */
752  --bit_number;
753
754  /* Calculate the I/O address based upon bit number */
755  port = (bit_number / 8) + dio_port + 8;
756
757  /* Calculate a bit mask based upon the specified bit number */
758  mask = (1 << (bit_number % 8));
759
760  /* Turn on page 2 access */
761  outb(0x80,dio_port+7);
762
763  /* Get the current state of the interrupt enable register */
764  temp = inb(port);
765
766  /* Temporarily clear only our enable. This clears the interrupt */
767  temp = temp & ~mask;    /* Clear the enable for this bit */
768
769  /* Now update the interrupt enable register */
770  outb(temp,port);
771
772  /* Re-enable our interrupt bit */
773  temp = temp | mask;
774  outb(temp,port);
775
776  /* Set access back to page 0 */
777  outb(0x00,dio_port+7);
778}
779
780int get_int(void)
781{
782  int temp;
783  int x;
784  unsigned short dio_port;
785
786  dio_port = base_port + 0x10;
787
788  /* Read the master interrupt pending register,
789           mask off undefined bits */
790  temp = inb(dio_port+6) & 0x07;
791
792  /* If there are no pending interrupts, return 0 */
793  if ((temp & 7) == 0)
794    return 0;
795
796  /* There is something pending, now we need to identify it */
797
798  /* Set access to page 3 for interrupt id register */
799  outb(0xc0, dio_port + 7);
800
801  /* Read the interrupt ID register for port 0 */
802  temp = inb(dio_port+8);
803
804  /* See if any bit set, if so return the bit number */
805  if (temp != 0) {
806    for (x=0; x<=7; x++) {
807      if (temp & (1 << x)) {
808        outb(0,dio_port+7);
809        return(x+1);
810       }
811    }
812  }
813
814  /* None in port 0, read port 1 interrupt ID register */
815  temp = inb(dio_port+9);
816
817  /* See if any bit set, if so return the bit number */
818  if (temp != 0) {
819    for (x=0; x<=7; x++) {
820      if (temp & (1 << x)) {
821        outb(0,dio_port+7);
822        return(x+9);
823      }
824    }
825  }
826
827  /* Lastly, read the status of port 2 interrupt ID register */
828  temp = inb(dio_port+0x0a);
829
830  /* If any pending, return the appropriate bit number */
831  if (temp != 0) {
832    for (x=0; x<=7; x++) {
833      if (temp & (1 << x)) {
834         outb(0,dio_port+7);
835         return(x+17);
836      }
837    }
838  }
839
840  /* We should never get here unless the hardware is seriously
841     misbehaving, but just to be sure, we'll turn the page access
842     back to 0 and return a 0 for no interrupt found
843  */
844  outb(0,dio_port+7);
845  return 0;
846}
847
848void flush_buffered_ints(void)
849{
850  rtems_status_code  rc;
851  size_t             flushed;
852
853  rc = rtems_message_queue_flush( wq_dio, &flushed );
854  if ( rc != RTEMS_SUCCESSFUL ) {
855    printk( "flushed_buffered_int - error %d\n", rc );
856    exit( 0 );
857  }
858}
859
860int get_buffered_int(
861  struct timespec *timestamp
862)
863{
864  rtems_status_code  rc;
865  din_message_t      din;
866  int                line;
867  size_t             received;
868
869  if (irq == 0) {
870    line = get_int();
871    if (line)
872      clr_int(line);
873    return line;
874  }
875
876  rc = rtems_message_queue_receive(
877    wq_dio,
878    &din,
879    &received,
880    RTEMS_NO_WAIT,
881    0
882  );
883  if ( rc == RTEMS_UNSATISFIED ) {
884    mio_error_code = MIO_READ_DATA_FAILURE;
885    return 0;
886  }
887
888  if ( rc != RTEMS_SUCCESSFUL ) {
889    printk( "get_buffered_int - error %d\n", rc );
890    exit( 0 );
891  }
892
893  if (timestamp)
894    *timestamp = din.timestamp;
895  return din.pin;
896}
897
898int dio_get_missed_interrupts(void)
899{
900  int isrs;
901
902  isrs = pcmmio_dio_missed_interrupts;
903
904  pcmmio_dio_missed_interrupts = 0;
905
906  return isrs;
907}
Note: See TracBrowser for help on using the repository browser.