source: multiio/pcmmio/original/mio_io_rtems.c @ 2fc4157

Last change on this file since 2fc4157 was 2fc4157, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 10, 2009 at 6:06:38 PM

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

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