/************************************************************************ * Author : Vlad Korolev * * First Version: Apr , 1999 * * BUGS * * ************************************************************************/ #define __KERNEL__ #define MODULE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /************************************************* * Data Types * ************************************************/ typedef struct /* Each dev file corresponds to Channel */ { int Busy; /* Open Status */ int Delay; /* Delay in usecs */ int Gain; /* Output Gain */ int Faults; /* Number of Faults */ int Sent; /* Bytes sent */ } Channel; typedef struct { int Good; int Clock; /* 1 - 32 Mhz 0 - 8Mhz */ int Sent; int Faults; int Cntl0; Channel Chan [8]; } IPack; typedef struct { unsigned long * plx9600; unsigned char * altera; int irq; int major; int AutoInt; int BusErr; int CurPack; IPack IP [4]; } Board; /* Minor decoding */ #define ChanFromN(n) ( n & 0xf ) #define IPFromN(n) ( n >> 4 ) /* Hardware access */ /* Altera Registers */ #define CNTL0 *(Dev.altera+0x500) #define CNTL1 *(Dev.altera+0x600) #define CNTL2 *(Dev.altera+0x700) /* PLX9060 registers */ #define ICSR *(Dev.plx9600+0x68/4) /* Int. Control Stat Register*/ #define PCUI *(Dev.plx9600+0x6c/4) /* Prom Command User Init */ /* Industry Pack registers */ #define SETPACK(n) (Dev.CurPack = n ) #define IOSPACE(n) *(Dev.altera+0x1000+(Dev.CurPack*0x1000)+n) #define IDSPACE(n) *(Dev.altera+(0x1000+(Dev.CurPack*0x1000)+0x100+n)) #define INTSPACE(n) *(Dev.altera+0x1000+Dev.CurPack*0x1000+0x200+n) #define IOSPACEW(n) *(unsigned short*)(Dev.altera+0x1000+(Dev.CurPack*0x1000)+n) #define MAXIP 4 #define MAXCHAN 8 static Board Dev = { NULL, /* PLX9600 */ NULL, /* Altera */ 0, /* IRQ */ 0, /* Major */ 0, /* AutoInt flag */ 0, /* BusErr flag */ 0, /* Current Pack for Accounting */ { {0,0,0,0,0, { {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, } }, {0,0,0,0,0, { {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} } }, {0,0,0,0,0, { {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} } }, {0,0,0,0,0, { {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} } } } }; static void Sleep ( int ticks ); static int Memset ( char * ptr , int c , int size ); /* Implement Open / Close ioctl () read / write */ static int pci40_open ( struct inode * inode , struct file * filp ) { int minor = inode->i_rdev & 0xff; if ( !Dev.IP[IPFromN(minor)].Good ) return -ENODEV; /* Clear the text of mode is WR_ONLY */ if ( Dev.IP[IPFromN(minor)].Chan[ChanFromN(minor)].Busy ) return -EBUSY; Dev.IP[IPFromN(minor)].Chan[ChanFromN(minor)].Busy = 1; filp->private_data = (void*)((IPFromN (minor) << 4 ) | (ChanFromN(minor) & 0xf )); MOD_INC_USE_COUNT; return 0; } static int pci40_release ( struct inode * inode , struct file * filp ) { int minor = inode->i_rdev & 0xff; Dev.IP[IPFromN(minor)].Chan[ChanFromN(minor)].Busy = 0; MOD_DEC_USE_COUNT; return 0; } /* Write operation (Unipolar,Raw, ) */ static ssize_t pci40_write ( struct file * filp , const char * buf , size_t count, loff_t *ppos ) { int i,p; static int j = 0x1000; static short data; int offSet = 0x1000; offSet += 0x1000*(((int)filp->private_data)/0x10); offSet += 0x0002*((int)filp->private_data)&0x0f; if ( count < 2 ) return -EINVAL; get_user ( data , (int*)buf ); { writew ( data & 0x1fff , Dev.altera + offSet ); writew ( 0x000f , Dev.altera + 0x4000 + 0x22 ); } return count; } static struct file_operations greensp_ops = { NULL, /* seek */ NULL, /* read */ pci40_write, /* write */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ pci40_open, /* open */ NULL, /* flush */ pci40_release, /* release */ NULL, NULL, NULL, NULL }; #define NR_DEVICE 2 /*************** * Interrupt Handler * * In the present configuration the only possible cause of interrupt * is BUS timeout, so the only thing we can do is to increase * the fault count, and set the fault flag * ******************/ static void int_handler ( int xw , void * xx , struct pt_regs * xy ) { int i; int x; unsigned long flags; save_flags(flags); /* Save flags */ cli(); if ( CNTL2 & 0x40 ) { Dev.BusErr = 1; } if ( CNTL0 & 0x80 ) Dev.AutoInt = 1; /* Reset the cpu Line */ CNTL0 = 0; ICSR = 0x0031b00 ; CNTL0 |= 0x70; restore_flags(flags); /* Restore CPU flags */ } int init_module ( void ) { /* Look up PCI Bios */ struct pci_dev *pcidev = NULL; int index = 0 ; printk ("<1>PCI40 + FastDAC16 Driver \n" ); if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; if ( pcidev = pci_find_device( 0x124b, 0x0040, pcidev)) { unsigned long a; int i, GoodPacks; Dev.altera = (char*) ioremap(pcidev->base_address[2], 0x14000 ); Dev.plx9600 = (long*) ioremap(pcidev->base_address[0], 0x01000 ); Dev.irq = pcidev->irq; request_irq ( Dev.irq , int_handler , SA_INTERRUPT , "pci40" , NULL ); /* Reset the board */ // PCUI |= 0x40000000 ; Sleep ( 1 ); PCUI &= ~ 0x40000000; Sleep ( 1 ); // PCUI |= 0x20000000 ; Sleep ( 1 ); PCUI &= ~ 0x20000000; Sleep ( 1 ); /* Set interrupt handling */ ICSR = 0x0031b00 ; CNTL0 |= 0x70; /* Test the interrupts */ printk ( " Testing Interrupts....." ); CNTL0 |= 0xF0; udelay ( 100 ); if ( Dev.AutoInt == 1 ) { Dev.AutoInt = 0; printk ( "Passed\n" ); } else { Dev.AutoInt = 0; printk ( "Failed\n" ); } GoodPacks = 0; for ( i = 0 ; i < 4 ; i++ ) { int x; SETPACK(i); Dev.BusErr = 0; x = IDSPACE(0); Sleep ( x ); if ( Dev.BusErr != 0 ) { Dev.BusErr = 0; } else { Dev.IP[i].Good = 1; Dev.BusErr = 0; GoodPacks++; } } if ( GoodPacks != 0 ) { printk ( "Packs with Good ID ......." ); for ( i = 0 ; i < 4 ; i ++ ) if ( Dev.IP[i].Good ) printk ( "%c" , 'A'+i ); printk ( "\n" ); } GoodPacks = 0; for ( i = 0 ; i < 4 ; i++ ) { int x; SETPACK(i); Dev.BusErr = 0; IOSPACEW(0x20) = 0x0100; Sleep ( x ); if ( Dev.BusErr != 0 ) { Dev.BusErr = 0; } else { Dev.BusErr = 0; Dev.IP[i].Good = 1; GoodPacks++; } } if ( GoodPacks != 0 ) { printk ( "Packs with Good IO ......." ); for ( i = 0 ; i < 4 ; i ++ ) if ( Dev.IP[i].Good ) printk ( "%c" , 'A'+i ); printk ( "\n" ); } } printk ( "Altera %p \n" , Dev.altera ); writew ( 0xf01 , Dev.altera + 0x4000 + 0x20 ); udelay ( 20 ); Dev.major = register_chrdev ( 0 , "pci40" , &greensp_ops ); return 0; } void cleanup_module ( void ) { if ( Dev.major != 0 ) unregister_chrdev ( Dev.major , "pci40" ); iounmap ( Dev.plx9600 ); iounmap ( Dev.altera ); free_irq ( Dev.irq , NULL ); } static int Memset ( char * ptr , int c , int size ) { int i; for ( i = 0 ; i < size ; i++ ) ptr[i] = c; } static void Sleep ( int ticks ) { int i; for ( i = 0 ; i < 100 ; i++ ) udelay( 500 ); }