source: multiio/pcmmio/original/mio_io_rtems.c @ b1481d8

Last change on this file since b1481d8 was b1481d8, checked in by Joel Sherrill <joel.sherrill@…>, on 08/13/09 at 20:49:38

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

  • main_pcmmio_irq.c, mio_io.h, mio_io_rtems.c: Add ADCs confirmed to work using the dac command. Both single voltages and a pattern were written.
  • Property mode set to 100644
File size: 18.1 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_timestamp(
386  int                 milliseconds,
387  unsigned long long *timestamp
388)
389{
390  int i;
391  int sc;
392
393  if (check_handle())   /* Check for chip available */
394    return -1;
395
396  if((i = get_buffered_int(NULL)))
397    return i;
398
399  sc = interruptible_sleep_on(&wq_dio, milliseconds);
400  if ( sc != 0 )
401    return sc;
402
403  i = get_buffered_int(timestamp);
404
405  return i;
406}
407
408int wait_dio_int_with_timeout(int milliseconds)
409{
410  return wait_dio_int_with_timestamp(milliseconds, NULL);
411}
412
413int wait_dio_int(void)
414{
415  return wait_dio_int_with_timestamp(0, NULL);
416}
417
418static int handle = 0; /* XXX move to lower */
419
420int check_handle(void)
421{
422  if (handle > 0)  /* If it's already a valid handle */
423    return 0;
424
425  if (handle == -1)  /* If it's already been tried */
426  {
427    mio_error_code = MIO_OPEN_ERROR;
428    sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
429    return -1;
430  }
431
432  /*
433   * 0  ==> not initialized
434   * 1+ ==> valid file handle, thus initialized
435   * -1 ==> already attempted to open
436   */
437  handle = 1;
438  return 0;
439
440  /* if an error happens, go here */
441  mio_error_code = MIO_OPEN_ERROR;
442  sprintf(mio_error_string,"MIO - Unable to open device PCMMIO");
443  handle = -1;
444  return -1;
445}
446
447/*
448 *  RTEMS barrier create helper
449 */
450void pcmmio_barrier_create(
451  rtems_name  name,
452  rtems_id   *id
453)
454{
455  rtems_status_code rc;
456
457  rc = rtems_barrier_create( name, RTEMS_BARRIER_MANUAL_RELEASE, 0, id );
458  if ( rc == RTEMS_SUCCESSFUL )
459    return;
460
461 printk( "Unable to create PCMMIO Barrier\n" );
462 exit(1);
463}
464
465int interruptible_sleep_on(
466  rtems_id *id,
467  int       milliseconds
468)
469{
470  rtems_status_code rc;
471
472  rc = rtems_barrier_wait(*id, RTEMS_MILLISECONDS_TO_TICKS(milliseconds));
473  if ( rc == RTEMS_SUCCESSFUL )
474    return 0;
475  return -1;
476}
477
478void wake_up_interruptible(
479  rtems_id *id
480)
481{
482  rtems_status_code rc;
483  uint32_t          unblocked;
484
485  rc = rtems_barrier_release(*id, &unblocked);
486}
487
488/*
489 *  RTEMS specific interrupt handler
490 */
491#include <bsp/irq.h>
492
493void common_handler(void);
494
495void pcmmio_irq_handler(
496  rtems_irq_hdl_param param
497)
498{
499  common_handler();
500}
501
502static void pcmmio_irq_disable(const rtems_irq_connect_data *irq)
503{
504  BSP_irq_disable_at_i8259s(irq->name);
505}
506static void pcmmio_irq_enable(const rtems_irq_connect_data *irq)
507{
508  BSP_irq_enable_at_i8259s(irq->name);
509}
510
511static int pcmmio_irq_is_on(const rtems_irq_connect_data *irq)
512{
513  return BSP_irq_enabled_at_i8259s( irq->name );
514}
515
516rtems_irq_connect_data pcmmio_irq = {
517  0,                            // name
518  pcmmio_irq_handler,           // handler
519  NULL,                         // parameter
520  pcmmio_irq_enable,            // enable IRQ
521  pcmmio_irq_disable,           // disable IRQ
522  pcmmio_irq_is_on,             // is IRQ enabled
523};
524
525/* from pcmmio.c - GNU/Linux driver */
526void init_io(unsigned short io_address)
527{
528  int x;
529  unsigned short port;
530
531  /* save the address for later use */
532  port = io_address + 0X10;
533
534  /* Clear all of the I/O ports. This also makes them inputs */
535  for(x=0; x < 7; x++)
536    outb(0,port+x);
537
538  /* Set page 2 access, for interrupt enables */
539  outb(0x80,port+7);
540
541  /* Clear all interrupt enables */
542  outb(0,port+8);
543  outb(0,port+9);
544  outb(0,port+0x0a);
545
546  /* Restore page 0 register access */
547  outb(0,port+7);
548}
549
550/*
551 * RTEMS specific initialization routine
552 */
553void pcmmio_initialize(
554  unsigned short _base_port,
555  unsigned short _irq
556)
557{
558  /* reset discrete interrupt input counters */
559  flush_buffered_ints();
560
561  /* hardware configuration information */
562  base_port = _base_port;
563  irq       = _irq;
564
565  /* Create RTEMS Objects */
566  pcmmio_barrier_create( rtems_build_name( 'a', '2', 'd', '1' ), &wq_a2d_1 );
567  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '1' ), &wq_dac_1 );
568  pcmmio_barrier_create( rtems_build_name( 'd', 'a', 'c', '2' ), &wq_dac_2 );
569  pcmmio_barrier_create( rtems_build_name( 'd', 'i', 'o', ' ' ), &wq_dio );
570
571  if ( base_port )
572    init_io( base_port );
573
574  /* install IRQ handler */
575  if ( base_port && irq ) {
576    int status = 0;
577    pcmmio_irq.name = irq;
578    #if defined(BSP_SHARED_HANDLER_SUPPORT)
579      printk( "PCMMIO Installing IRQ handler as shared\n" );
580      status = BSP_install_rtems_shared_irq_handler( &pcmmio_irq );
581    #else
582      printk( "PCMMIO Installing IRQ handler as non-shared\n" );
583      status = BSP_install_rtems_irq_handler( &pcmmio_irq );
584    #endif
585    if ( !status ) {
586      printk("Error installing PCMMIO interrupt handler! status=%d\n", status );
587    }
588  }
589}
590
591#include <libcpu/cpuModel.h> /* for rdtsc */
592
593/*
594 *  From this point down, we should be able to share easily with the Linux
595 *  driver but I haven't gone to the trouble to do surgery on it.  I have
596 *  no way to test it.
597 */
598
599/* We will buffer up the transition interrupts and will pass them on
600   to waiting applications
601*/
602
603#define MAX_INTS 1024
604
605typedef struct {
606  unsigned char      line;
607  unsigned long long timestamp;
608} DIO_Int_t;
609
610static DIO_Int_t int_buffer[MAX_INTS];
611static int       inptr = 0;
612static int       outptr = 0;
613
614/* real copy is in mio_io.c */
615extern unsigned char adc2_port_image;
616
617/* This is the common interrupt handler. It is called by the
618 * actual hardware ISR.
619 */
620
621void common_handler(void)
622{
623  unsigned char status;
624  unsigned char int_num;
625
626  /* Read the interrupt ID register from ADC2 */
627
628  adc2_port_image = adc2_port_image | 0x20;
629  outb(adc2_port_image,base_port + 0x0f);
630
631  status = inb(base_port + 0x0f);
632  if (status & 1) {
633    /* Clear ADC1 interrupt */
634    inb(base_port+1);      /* Clear interrupt */
635
636    /* Wake up any holding processes */
637    wake_up_interruptible(&wq_a2d_1);
638  }
639
640  if (status & 2) {
641    /* Clear ADC1 interrupt */
642    inb(base_port+5);      /* Clear interrupt */
643
644    /* Wake up anybody waiting for ADC1 */
645    wake_up_interruptible(&wq_a2d_2);
646  }
647
648  if (status & 4) {
649    /* Clear DAC1 interrupt */
650    inb(base_port+9);    /* Clear interrupt */
651
652    /* Wake up if you're waiting on DAC1 */
653    wake_up_interruptible(&wq_dac_1);
654  }
655
656  if (status & 8) {
657
658    /* DIO interrupt. Find out which bit */
659    int_num = get_int();
660    if (int_num) {
661      #ifdef DEBUG
662        printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
663      #endif
664
665      /*
666       * Buffer the interrupt
667       *
668       * NOTE: No need to worry about disabling interrupts,
669       *       we are in interrupts.
670       */
671
672      int_buffer[inptr].timestamp = rdtsc();
673      int_buffer[inptr].line = int_num;
674      inptr++;
675      if (inptr == MAX_INTS)
676        inptr = 0;
677
678      /* Clear the interrupt */
679      clr_int(int_num);
680    }
681
682    /* Wake up anybody waiting for a DIO interrupt */
683    wake_up_interruptible(&wq_dio);
684  }
685
686  if (status & 0x10) {
687    /* Clear DAC2 Interrupt */
688    inb(base_port+0x0d);    /* Clear interrupt */
689
690    /* Wake up DAC2 holding processes */
691    wake_up_interruptible(&wq_dac_2);
692  }
693
694  /* Reset the access to the interrupt ID register */
695  adc2_port_image = adc2_port_image & 0xdf;
696  outb(adc2_port_image,base_port+0x0f);
697}
698
699
700void clr_int(int bit_number)
701{
702  unsigned short port;
703  unsigned short temp;
704  unsigned short mask;
705  unsigned short dio_port;
706
707  dio_port = base_port + 0x10;
708
709  /* Also adjust bit number */
710  --bit_number;
711
712  /* Calculate the I/O address based upon bit number */
713  port = (bit_number / 8) + dio_port + 8;
714
715  /* Calculate a bit mask based upon the specified bit number */
716  mask = (1 << (bit_number % 8));
717
718  /* Turn on page 2 access */
719  outb(0x80,dio_port+7);
720
721  /* Get the current state of the interrupt enable register */
722  temp = inb(port);
723
724  /* Temporarily clear only our enable. This clears the interrupt */
725  temp = temp & ~mask;    /* Clear the enable for this bit */
726
727  /* Now update the interrupt enable register */
728  outb(temp,port);
729
730  /* Re-enable our interrupt bit */
731  temp = temp | mask;
732  outb(temp,port);
733
734  /* Set access back to page 0 */
735  outb(0x00,dio_port+7);
736}
737
738int get_int(void)
739{
740  int temp;
741  int x;
742  unsigned short dio_port;
743
744  dio_port = base_port + 0x10;
745
746  /* Read the master interrupt pending register,
747           mask off undefined bits */
748  temp = inb(dio_port+6) & 0x07;
749
750  /* If there are no pending interrupts, return 0 */
751  if ((temp & 7) == 0)
752    return 0;
753
754  /* There is something pending, now we need to identify it */
755
756  /* Set access to page 3 for interrupt id register */
757  outb(0xc0, dio_port + 7);
758
759  /* Read the interrupt ID register for port 0 */
760  temp = inb(dio_port+8);
761
762  /* See if any bit set, if so return the bit number */
763  if (temp != 0) {
764    for (x=0; x<=7; x++) {
765      if (temp & (1 << x)) {
766        outb(0,dio_port+7);
767        return(x+1);
768       }
769    }
770  }
771
772  /* None in port 0, read port 1 interrupt ID register */
773  temp = inb(dio_port+9);
774
775  /* See if any bit set, if so return the bit number */
776  if (temp != 0) {
777    for (x=0; x<=7; x++) {
778      if (temp & (1 << x)) {
779        outb(0,dio_port+7);
780        return(x+9);
781      }
782    }
783  }
784
785  /* Lastly, read the status of port 2 interrupt ID register */
786  temp = inb(dio_port+0x0a);
787
788  /* If any pending, return the appropriate bit number */
789  if (temp != 0) {
790    for (x=0; x<=7; x++) {
791      if (temp & (1 << x)) {
792         outb(0,dio_port+7);
793         return(x+17);
794      }
795    }
796  }
797
798  /* We should never get here unless the hardware is seriously
799     misbehaving, but just to be sure, we'll turn the page access
800     back to 0 and return a 0 for no interrupt found
801  */
802  outb(0,dio_port+7);
803  return 0;
804}
805
806void flush_buffered_ints(void)
807{
808  inptr = 0;
809  outptr = 0;
810}
811
812int get_buffered_int(
813  unsigned long long *timestamp
814)
815{
816  rtems_interrupt_level level;
817  int                   line;
818
819  if (irq == 0) {
820    line = get_int();
821    if (line)
822      clr_int(line);
823    return line;
824  }
825
826  line = 0;
827
828  rtems_interrupt_disable( level );
829    if (outptr != inptr) {
830      if ( timestamp )
831        *timestamp = int_buffer[outptr].timestamp;
832      line = int_buffer[outptr].line;
833      outptr++;
834      if (outptr == MAX_INTS)
835        outptr = 0;
836    }
837  rtems_interrupt_enable( level );
838 
839  return line;
840}
Note: See TracBrowser for help on using the repository browser.