source: multiio/pcmmio/original/pcmmio.c @ da59d43

Last change on this file since da59d43 was 2bae2aa, checked in by Joel Sherrill <joel.sherrill@…>, on 06/08/09 at 14:52:43

Initial import.

  • Property mode set to 100644
File size: 18.2 KB
Line 
1/* PCMMIO.C    WinSystems PCM-MIO Linux Driver */
2
3/*
4 * $Header$
5 * $Id$
6 *
7 * Filename : $RCSfile$
8 *
9 * $Log$
10 *
11 *
12 * WinSystems PCM-MIO Linux Device Driver
13 */
14
15 static char *RCSInfo = "$Id$";
16
17/* Portions of original code Copyright (C) 1998-99 by Ori Pomerantz */
18
19
20/* #define DEBUG 1 */
21
22#ifndef __KERNEL__
23#  define __KERNEL__
24#endif
25
26#ifndef MODULE
27#  define MODULE
28#endif
29
30#include <linux/config.h>
31#include <linux/module.h>
32
33#include <linux/sched.h>
34#include <linux/kernel.h>
35#include <linux/fs.h>
36#include <linux/errno.h>
37#include <linux/delay.h>
38#include <linux/mm.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
41
42#include <asm/io.h>
43#include <asm/uaccess.h>
44
45
46MODULE_LICENSE("GPL");
47
48/* Our own ioctl numbers */
49
50#include "mio_io.h"
51
52#define SUCCESS 0
53
54#define MAX_INTS 1024
55
56/* Function prototypes for local functions */
57
58int get_buffered_int(void);
59void init_io(unsigned short io_address);
60void clr_int(int bit_number);
61int get_int(void);
62
63
64/* Interrupt handler */
65
66irqreturn_t mio_handler(int, void *, struct pt_regs *);
67
68void common_handler(void);
69
70
71/* This holds the base addresses of the board */
72
73unsigned short base_port = 0;
74
75/* The name for our device, as it will appear in
76 * /proc/devices */
77
78#define MAJOR_NUM 115
79#define DEVICE_NAME "pcmmio"
80
81/* The maximum length of the message for the device */
82
83#define BUF_LEN 40
84
85/* The message the device will give when asked */
86
87static char Message[BUF_LEN];
88
89/* A message pointer for the device */
90
91int Message_Ptr = 0;
92
93/* Our insmod command line arguments */
94
95MODULE_PARM(io,"1-6i");
96MODULE_PARM(irq,"1-6i");
97
98static unsigned short io = 0;
99static unsigned short irq = 0;
100
101
102/* We will buffer up the transition interrupts and will pass them on
103   to waiting applications
104*/
105
106unsigned char int_buffer[MAX_INTS];
107int inptr = 0;
108int outptr = 0;
109
110
111/* These declarations create the wait queues. One for each supported
112   device.
113*/
114
115DECLARE_WAIT_QUEUE_HEAD(wq_a2d_1);
116DECLARE_WAIT_QUEUE_HEAD(wq_a2d_2);
117DECLARE_WAIT_QUEUE_HEAD(wq_dac_1);
118DECLARE_WAIT_QUEUE_HEAD(wq_dac_2);
119DECLARE_WAIT_QUEUE_HEAD(wq_dio);
120
121unsigned char adc2_port_image = 0;
122
123/* This is the common interrupt handler. It is called by the hctual hardware ISR.
124*/
125
126void common_handler()
127{
128unsigned char status;
129unsigned char int_num;
130
131
132                        /* Read the interrupt ID register from ADC2 */
133
134                        adc2_port_image = adc2_port_image | 0x20;
135                        outb(adc2_port_image,base_port + 0x0f);
136
137                        status = inb(base_port + 0x0f);
138
139                        if(status & 1)
140                        {
141                                /* Clear ADC1 interrupt */
142                                inb(base_port+1);                       /* Clear interrupt */
143
144                                /* Wake up any holding processes */
145
146                                wake_up_interruptible(&wq_a2d_1);
147                        }
148
149                        if(status & 2)
150                        {                       
151                                /* Clear ADC1 interrupt */
152
153                                inb(base_port+5);                       /* Clear interrupt */
154
155                                /* Wake up anybody waiting for ADC1 */
156
157                                wake_up_interruptible(&wq_a2d_2);
158                        }
159
160                        if(status & 4)
161                        {
162                                /* Clear DAC1 interrupt */
163
164                                inb(base_port+9);               /* Clear interrupt */
165
166                                /* Wake up if you're waiting on DAC1 */
167
168                                wake_up_interruptible(&wq_dac_1);
169                        }
170
171                        if(status & 8)
172                        {
173
174                                /* DIO interrupt. Find out which bit */
175
176                                int_num = get_int();
177                                if(int_num)
178                                {
179#ifdef DEBUG
180                                        printk("<1>Buffering DIO interrupt on bit %d\n",int_num);
181#endif
182
183                                        /* Buffer the interrupt */
184
185                                        int_buffer[inptr++] = int_num;
186                                        if(inptr == MAX_INTS)
187                                                inptr = 0;
188                               
189                                        /* Clear the interrupt */
190
191                                        clr_int(int_num);
192                                }
193
194                                /* Wake up anybody waiting for a DIO interrupt */
195
196                                wake_up_interruptible(&wq_dio);
197                        }
198
199                        if(status & 0x10)
200                        {
201                                /* Clear DAC2 Interrupt */
202
203                                inb(base_port+0x0d);            /* Clear interrupt */
204
205                                /* Wake up DAC2 holding processes */
206
207                                wake_up_interruptible(&wq_dac_2);
208                        }
209
210
211                        /* Reset the access to the interrupt ID register */
212
213                        adc2_port_image = adc2_port_image & 0xdf;
214                        outb(adc2_port_image,base_port+0x0f);   
215
216}
217
218
219
220/* This is the actual hadrware interrupt handler. It defers to another
221   functon for handling.
222*/
223
224irqreturn_t mio_handler(int pirq, void *dev_id, struct pt_regs *regs)
225{
226
227#ifdef DEBUG
228        printk("<1>MIO Interrupt received\n");
229#endif
230
231        common_handler();
232        return IRQ_HANDLED;
233}
234
235
236
237/***********************************************************************
238*
239*
240*                       DEVICE OPEN
241*
242*
243************************************************************************
244*/
245
246
247/* This function is called whenever a process attempts
248 * to open the device file */
249
250static int device_open(struct inode *inode, struct file *file)
251{
252
253  if(base_port == 0)
254  {
255        printk("<1>**** OPEN ATTEMPT on uninitialized port *****\n");
256        return -1;
257  }
258
259#ifdef DEBUG
260  printk ("device_open(%p)\n", file);
261#endif
262
263  /* Rewind the message pointer for this device on a new open.
264
265     This could cause problems for applications that use file I/O
266     for talking to the device as we do not limit the number of
267     applications that can open the device. The solution is to use
268     IOCTL functions to control the device rather than file I/O
269     calls.
270  */
271
272  Message_Ptr = 0;
273
274
275  return SUCCESS;
276}
277
278
279/*************************************************************************
280*
281*
282*                       DEVICE CLOSE
283*
284*
285**************************************************************************
286*/
287
288
289int device_release(struct inode *inode, struct file *file)
290{
291
292#ifdef DEBUG
293  printk ("device_release(%p,%p)\n", inode, file);
294#endif
295
296
297  return 0;
298
299}
300
301
302/****************************************************************************
303*
304*                       DEVICE READ
305*
306*
307*
308*****************************************************************************
309*/
310
311ssize_t device_read(struct file *file,char *buffer,size_t length,loff_t *offset)
312{
313unsigned short port;
314int bytes_read;
315int x;
316
317   /* We only allow reading of the 32 valid ports in the device. Beyond
318      that we return EOF.
319   */
320
321   if(Message_Ptr == 32)
322        return 0;       /* EOF Condition */
323
324   port = base_port;
325
326   // Do a fresh read of the ports */
327
328   for(x=0; x<32; x++)
329       Message[x] = inb(port+x);
330
331
332  /* Number of bytes actually written to the buffer */
333
334   bytes_read = 0;
335
336#ifdef DEBUG
337  printk("device_read(%p,%p,%d)\n",file, buffer, length);
338#endif
339
340
341  /* Actually put the data into the buffer */
342
343  while (length && (Message_Ptr < 32))
344  {
345    /* Because the buffer is in the user data segment,
346     * not the kernel data segment, assignment wouldn't
347     * work. Instead, we have to use put_user which
348     * copies data from the kernel data segment to the
349     * user data segment. */
350
351    put_user((Message[Message_Ptr++]), buffer++);
352    length --;
353    bytes_read ++;
354  }
355
356#ifdef DEBUG
357   printk ("Read %d bytes, %d left\n",bytes_read, length);
358#endif
359
360   /* Read functions are supposed to return the number
361    * of bytes actually inserted into the buffer */
362
363
364  /* By updating file->f_pos we can allow seeking of our Messge_Ptr
365     which will allow random access to the ports using file I/O
366  */
367
368  file->f_pos = (loff_t)Message_Ptr;
369
370  return bytes_read;
371}
372
373
374/****************************************************************************
375*
376*
377*                               DEVICE WRITE
378*
379*****************************************************************************
380*/
381
382ssize_t device_write(struct file *file,const char *buffer,size_t length,loff_t *offset)
383{
384int i;
385unsigned short port;
386
387    port = base_port;
388
389#ifdef DEBUG
390  printk ("device_write(%p,%s,%d)",file, buffer, length);
391#endif
392
393  /* Read in the bytes to write, one at a time */
394
395  for(i=0; i<length && i<BUF_LEN; i++)
396  {
397    get_user(Message[i], buffer+i);
398
399    /* We output each byte to it's appropriate port as it comes in */
400
401        if(Message_Ptr == 32)
402        {
403         file->f_pos = (loff_t) Message_Ptr;
404             return i;
405        }
406
407
408    outb(Message[i],port + Message_Ptr++);
409
410  }
411
412  /* As with device_read if we update the file position. Seeking will
413     work as expected.
414  */
415
416  file->f_pos = (loff_t) Message_Ptr;
417
418
419  /* Again, return the number of input characters used */
420
421    return i;
422}
423
424
425/****************************************************************************
426*
427*
428*
429*                       DEVICE IOCTL
430*
431*
432*****************************************************************************
433*/
434
435
436int device_ioctl(struct inode *inode,struct file *file,
437     unsigned int ioctl_num, unsigned long ioctl_param)
438{
439int i;
440unsigned short word_val;
441unsigned char byte_val;
442unsigned char offset_val;
443unsigned char *arguments;
444
445#ifdef DEBUG
446//  printk("PCMMIO - IOCTL call IOCTL CODE %04X\n",ioctl_num);
447#endif
448
449
450  /* Switch according to the ioctl called */
451
452  switch (ioctl_num)
453        {
454
455        case WRITE_DAC_DATA:
456
457                arguments = (char *) ioctl_param;
458
459                if(!access_ok(VERIFY_WRITE,arguments,3))
460                {
461                    printk("<1>pcmmio : Unable to access IOCTL argument memory\n");
462                    return -EFAULT;
463                }
464
465                byte_val = arguments[0];
466
467                word_val = arguments[2];
468                word_val = word_val << 8;
469                word_val = word_val | arguments[1];
470
471                if(byte_val)            /* DAC 1 */
472                        outw(word_val,base_port+0x0c);
473                else
474                        outw(word_val,base_port+8);
475
476                break;
477
478
479        case    READ_DAC_STATUS:
480
481                byte_val = ioctl_param & 0xff;          /* This is the dac number */
482
483                if(byte_val)
484                        i = inb(base_port + 0x0f);
485                else
486                        i = inb(base_port + 0x0b);
487
488                return i;
489
490                break;
491
492
493        case    WRITE_DAC_COMMAND:
494
495                byte_val = ioctl_param & 0xff;          /* This is the DAC number */
496                offset_val = ioctl_param >> 8;          /* This is the data value */
497
498                if(byte_val)
499                        outb(offset_val,base_port + 0x0e);
500                else
501                        outb(offset_val,base_port + 0x0a);
502
503                break;
504
505
506        case    WRITE_ADC_COMMAND:
507
508                byte_val = ioctl_param & 0xff;          /* This is the ADC number */
509                offset_val = ioctl_param >> 8;          /* This is the data value */
510
511                if(byte_val)
512                        outb(offset_val,base_port + 0x06);
513                else
514                        outb(offset_val,base_port + 0x02);
515
516                break;
517
518
519
520        case    READ_ADC_DATA:
521
522                byte_val = ioctl_param & 0xff;  /* This is the ADC number */
523
524                if(byte_val)
525                        word_val = inw(base_port + 4);
526                else
527                        word_val = inw(base_port);
528
529                return word_val;
530
531                break;
532
533
534        case    READ_ADC_STATUS:
535
536                byte_val = ioctl_param & 0xff;          /* This is the ADC number */
537       
538                if(byte_val)
539                        i = inb(base_port + 7);
540                else
541                        i = inb(base_port + 3);
542
543                return i;
544
545                break;
546
547
548        case    WRITE_DIO_BYTE:
549
550                offset_val = ioctl_param & 0xff;
551                byte_val = ioctl_param >> 8;
552                outb(byte_val, base_port + 0x10 + offset_val);
553
554                break;
555
556
557        case    READ_DIO_BYTE:
558
559                offset_val = ioctl_param & 0xff;
560                byte_val = inb(base_port + 0x10 + offset_val);
561                return (byte_val & 0xff);
562
563                break;
564
565
566        case    MIO_WRITE_REG:
567
568                offset_val = ioctl_param & 0xff;
569                byte_val = ioctl_param >> 8;
570                outb(byte_val, base_port + offset_val);
571
572                break;
573
574
575        case    MIO_READ_REG:
576
577                offset_val = ioctl_param & 0xff;
578                byte_val = inb(base_port + offset_val);
579                return (byte_val & 0xff);
580
581                break;
582
583
584        case    WAIT_A2D_INT_1:
585
586#ifdef DEBUG
587                printk("<1>PCMMIO - IOCTL wait_ad1_int \n");
588                printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
589                current->pid,current->comm);
590#endif
591
592                interruptible_sleep_on(&wq_a2d_1);
593                break;
594
595        case    WAIT_A2D_INT_2:
596
597
598#ifdef DEBUG
599                printk("<1>PCMMIO - IOCTL wait_ad2_int \n");
600                printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
601                current->pid,current->comm);
602#endif
603
604                interruptible_sleep_on(&wq_a2d_2);
605                break;
606
607        case    WAIT_DAC_INT_1:
608
609#ifdef DEBUG
610                printk("<1>PCMMIO - IOCTL wait_dac1_int \n");
611                printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
612                current->pid,current->comm);
613#endif
614                interruptible_sleep_on(&wq_dac_1);
615                break;
616
617        case    WAIT_DAC_INT_2:
618
619#ifdef DEBUG
620                printk("<1>PCMMIO - IOCTL wait_dac2_int \n");
621                printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
622                current->pid,current->comm);
623#endif
624                interruptible_sleep_on(&wq_dac_2);
625                break;
626
627        case    WAIT_DIO_INT:
628
629                if((i = get_buffered_int()))
630                        return i;
631
632#ifdef DEBUG
633                printk("<1>PCMMIO - IOCTL wait_dio_int \n");
634                printk("<1>PCMMIO : current process %i (%s) going to sleep\n",
635                current->pid,current->comm);
636#endif
637                interruptible_sleep_on(&wq_dio);
638
639                i = get_buffered_int();
640
641                return i;
642                break;
643
644        case READ_IRQ_ASSIGNED:
645
646                return(irq & 0xff);
647                break;
648
649        case DIO_GET_INT:
650
651                i = get_buffered_int();
652                return(i & 0xff);
653                break;
654
655
656         }
657
658  return SUCCESS;
659}
660
661/***************************** DEVICE_LSEEK ***************************/
662
663loff_t device_lseek(struct file *filp, loff_t off, int whence)
664{
665unsigned short offset;
666
667    /* Convert the offset value to a more familiar size. After all
668       our device is a fixed size of 10 bytes.
669    */
670
671    offset = (unsigned short)off;
672
673#ifdef DEBUG
674    printk("<1>PCMMIO:lseek - offset %d mode %d\n",offset,whence);
675#endif
676
677    switch(whence)
678    {
679        case 0:   /* Seek set */
680            Message_Ptr = offset;
681                if(Message_Ptr > 32)
682                        Message_Ptr = 32;
683                break;
684
685        case 1:   /* Seek from Current */
686            Message_Ptr += offset;
687                if(Message_Ptr > 32)
688                        Message_Ptr = 32;
689
690                break;
691       
692        default:          /* Seek from End */
693            return -EINVAL;
694            break;
695    }
696
697        if(Message_Ptr < 0)
698        {
699            Message_Ptr = 0;
700            filp->f_pos = (loff_t)Message_Ptr;
701            return -EINVAL;
702        }
703
704        if(Message_Ptr > 32)
705        {
706            Message_Ptr = 32;
707            filp->f_pos = (loff_t)Message_Ptr;
708            return -EINVAL;
709        }
710
711        filp->f_pos = (loff_t)Message_Ptr;
712        return (loff_t)Message_Ptr;
713}
714
715/* ******************* Module Declarations *************************** */
716
717
718/* This structure will hold the functions to be called
719 * when a process does something to the our device
720*/
721
722struct file_operations Fops = {
723
724  owner:        THIS_MODULE,
725  llseek:       device_lseek,
726  read:         device_read,
727  write:        device_write,
728  ioctl:        device_ioctl,
729  open:         device_open,
730  release:      device_release,
731};
732
733/****************************************************************************
734*
735*                       INIT_MODULE
736*
737*
738*****************************************************************************
739*/
740
741/* Initialize the module - Register the character device */
742
743int init_module()
744{
745int ret_val;
746
747  /* Sign-on */
748
749   printk("<1>\nWinSystems PCM-MIO Driver. Copyright 2006. All rights reserved\n");
750   printk("<1>%s\n",RCSInfo);
751
752
753  /* Check and Map our I/O region requests */
754
755        if(io != 0)
756    {
757                if(request_region(io,0x20,"PCMMIO") == NULL)
758                {
759                        printk("<1>PCMMIO - Unable to use I/O Address %04X\n",io);
760                io = 0;
761                }
762        /* Register the character device */
763
764                ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
765
766                /* Negative values signify an error */
767 
768                if (ret_val < 0)
769                {
770                printk (" %s failed with %d\n",",registering the character device PCMMIO ", ret_val);
771                return ret_val;
772                }
773       
774                printk ("\nPCMMIO : The Base I/O Address = %04X\n",io);
775                base_port = io;
776                init_io(io);
777        }
778
779      if((io != 0) && (irq != 0))
780      {
781                        if(request_irq(irq,mio_handler,SA_SHIRQ,"PCMMIO",RCSInfo))
782                        printk("<1>PCMMIO - Unable to register IRQ %d\n",irq);
783                else
784                        printk("<1>PCMMIO - IRQ %d registered ok Chip 1\n",irq);
785
786          }
787 
788        return 0;
789}
790
791/***************************************************************************
792*
793*                       CLEANUP_MODULE
794*
795****************************************************************************
796*/
797
798/* Cleanup - unregister the appropriate file from /proc */
799
800void cleanup_module()
801{
802  /* Unregister I/O Port usage */
803
804        if(irq)
805                free_irq(irq,RCSInfo);
806     
807        if(io)
808        release_region(io,0x20);
809
810  /* Unregister the device */
811
812        unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
813 
814
815
816
817/* start of device subroutines */
818
819
820
821/* This array holds the image values of the last write to each I/O
822   port. This allows bit manipulation routines to work without having to actually do
823   a read-modify-write to the I/O port.
824*/
825
826unsigned char port_images[6];
827
828
829void init_io(unsigned short io_address)
830{
831int x;
832unsigned short port;
833
834        /* save the address for later use */
835
836        port = io_address + 0X10;
837
838        /* Clear all of the I/O ports. This also makes them inputs */
839
840        for(x=0; x < 7; x++)
841                outb(0,port+x);
842
843        /* Clear the image values as well */
844
845        for(x=0; x < 6; x++)
846                port_images[x] = 0;
847
848        /* Set page 2 access, for interrupt enables */
849
850        outb(0x80,port+7);
851
852        /* Clear all interrupt enables */
853
854        outb(0,port+8);
855        outb(0,port+9);
856        outb(0,port+0x0a);
857
858        /* Restore page 0 register access */
859
860        outb(0,port+7);
861}
862
863
864
865
866void clr_int(int bit_number)
867{
868unsigned short port;
869unsigned short temp;
870unsigned short mask;
871unsigned short dio_port;
872
873
874        dio_port = base_port + 0x10;
875
876        /* Also adjust bit number */
877
878        --bit_number;
879
880        /* Calculate the I/O address based upon bit number */
881
882        port = (bit_number / 8) + dio_port + 8;
883
884        /* Calculate a bit mask based upon the specified bit number */
885
886        mask = (1 << (bit_number % 8));
887
888        /* Turn on page 2 access */
889
890        outb(0x80,dio_port+7);
891
892        /* Get the current state of the interrupt enable register */
893
894        temp = inb(port);
895
896        /* Temporarily clear only our enable. This clears the interrupt */
897
898        temp = temp & ~mask;    /* Clear the enable for this bit */
899
900        /* Now update the interrupt enable register */
901
902        outb(temp,port);
903
904        /* Re-enable our interrupt bit */
905
906        temp = temp | mask;
907
908        outb(temp,port);
909
910        /* Set access back to page 0 */
911
912        outb(0x00,dio_port+7);
913}
914
915
916int get_int(void)
917{
918int temp;
919int x;
920unsigned short dio_port;
921
922        dio_port = base_port + 0x10;
923
924        /* Read the master interrupt pending register,
925           mask off undefined bits */
926
927        temp = inb(dio_port+6) & 0x07;
928
929        /* If there are no pending interrupts, return 0 */
930
931        if((temp & 7) == 0)
932            return 0;
933
934        /* There is something pending, now we need to identify it */
935
936        /* Set access to page 3 for interrupt id register */
937
938        outb(0xc0, dio_port + 7);
939
940        /* Read the interrupt ID register for port 0 */
941
942        temp = inb(dio_port+8);
943
944        /* See if any bit set, if so return the bit number */
945
946        if(temp != 0)
947        {
948            for(x=0; x<=7; x++)
949            {
950            if(temp & (1 << x))
951                {
952                    outb(0,dio_port+7);
953                    return(x+1);
954            }
955         }
956     }
957
958        /* None in port 0, read port 1 interrupt ID register */
959
960        temp = inb(dio_port+9);
961
962        /* See if any bit set, if so return the bit number */
963
964        if(temp != 0)
965        {
966            for(x=0; x<=7; x++)
967            {
968                if(temp & (1 << x))
969                {
970                    outb(0,dio_port+7);
971                    return(x+9);
972                }
973            }
974        }
975
976        /* Lastly, read the statur of port 2 interrupt ID register */
977
978        temp = inb(dio_port+0x0a);
979
980        /* If any pending, return the appropriate bit number */
981
982        if(temp != 0)
983        {
984            for(x=0; x<=7; x++)
985            {
986                        if(temp & (1 << x))
987                        {
988                           outb(0,dio_port+7);
989                           return(x+17);
990                        }
991            }
992        }
993
994        /* We should never get here unless the hardware is seriously
995           misbehaving, but just to be sure, we'll turn the page access
996           back to 0 and return a 0 for no interrupt found
997        */
998
999        outb(0,dio_port+7);
1000        return 0;
1001}
1002
1003
1004int get_buffered_int(void)
1005{
1006int temp;
1007
1008        if(irq == 0)
1009        {
1010            temp = get_int();
1011            if(temp)
1012                        clr_int(temp);
1013            return temp;
1014        }
1015
1016        if(outptr != inptr)
1017        {
1018            temp = int_buffer[outptr++];
1019            if(outptr == MAX_INTS)
1020                        outptr = 0;
1021            return temp;
1022        }
1023
1024        return 0;
1025}
1026
1027       
Note: See TracBrowser for help on using the repository browser.