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

Last change on this file since 1cbabbe was 1cbabbe, checked in by Joel Sherrill <joel.sherrill@…>, on 06/17/09 at 20:34:51

2009-06-17 Joel Sherrill <joel.sherrill@…>

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