source: multiio/pcmmio/pcmmio.c @ 0ecf946

Last change on this file since 0ecf946 was 13bdbee, checked in by Joel Sherrill <joel.sherrill@…>, on 03/17/11 at 15:04:30

Initial import.

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