source: multiio/pcmmio/original/mio_io_rtems.c @ 1b7aa5a

Last change on this file since 1b7aa5a was 1b7aa5a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/12/09 at 20:40:31

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

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