⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 par4chkd.c

📁 基于PC104的24位数据采集器的完整源码
💻 C
📖 第 1 页 / 共 5 页
字号:
        // Verify that writing (or reading + writing) is ok
        
        if ( WriteCopy )
                Err = access_ok( VERIFY_WRITE,
                                 (void*)Irp->OutBuffer,
                                 _IOC_SIZE(Command) );

        // Verify that reading is ok
        
        else if ( ReadCopy )
                Err = access_ok( VERIFY_READ,
                                 (void*)Irp->InBuffer,
                                  _IOC_SIZE(Command) );

        // Neither reading nor writing required
        
        else
                Err = 1;

        if (!Err)
                return( STATUS_INVALID_USER_BUFFER );



        // Fill Ioctl buffer from user space
        
        if (ReadCopy)
                OsCopyFromUser( *InBuffer, Irp->InBuffer, _IOC_SIZE(Command) );

        

        return( STATUS_SUCCESS );
}

SRLOCAL void OsReturnIoctlBuffer( IRP *Irp,
                                  unsigned long Command,
                                  int *OutBuffer ) {

        // Check if driver must write to user space (by READing from kernel)
        
        if ( _IOC_DIR(Command) & _IOC_READ )

                OsCopyToUser( Irp->OutBuffer, OutBuffer, _IOC_SIZE(Command) );
}

#define OsModuleUseCountInc  MOD_INC_USE_COUNT
#define OsModuleUseCountDec  MOD_DEC_USE_COUNT

// Atomic operation functions

#define OsAtomicSet( pAtom, Value )  atomic_set( (pAtom), (Value) )
#define OsAtomicInc( pAtom )         atomic_inc( (pAtom) )
#define OsAtomicDec( pAtom )         atomic_dec( (pAtom) )
#define OsAtomicAdd( pAtom, Amount ) atomic_add( (Amount), (pAtom) )
#define OsAtomicSub( pAtom, Amount ) atomic_sub( (Amount), (pAtom) )
#define OsAtomicRead( pAtom )        atomic_read( (pAtom) )



#endif // SROS_xxxxx  End of OS dependent helper functions section








/* PC PARALLEL PORT REGISTERS AND FUNCTIONS:

The parallel port has been standard PC hardware since the earliest
days of the PC.  Almost all PCs have at least one, while some have
two or even more.  A single parallel port is comprised of several
byte wide registers mapped into IO space that can be manipulated with
in and out instructions for data IO.

At power on the PC scans for parallel ports in the following address
order.  The first parallel port found is commonly referred to as
LPT1, the second as LPT2, and so on.  The base address 0x378 is by
far the most common base address for systems with a single port.

 PC power on parallel port base addresses scan order

    0x3BC
    0x378 <<< LPT1 on most machines
    0x278 <<< LPT2 on most machines
    0x268
    0x26C
    0x27C


In the days of good old DOS LPT assigments are stored at 0:408.  Even
though Windows machines are virtualized, those locations can still be
examined by running debug in a DOS window to see what the LPT
addresses are.  The 0x3BC address was the parallel port on the old
Monochrome graphics card.

Early ports were designed primarily for data output only.  Later
modifications added data input and several other features.  IEEE has
now standardized the various operating modes into the IEEE 1284 spec.
The PAR4CH board will operate with either the 1284 BPP (bidirectional
parallel port byte wide mode), or 1284 EPP (enhanced parallel port
mode).  EPP transfers are faster, relieving the x86 cpu of some of
the signaling chores.  Almost all PCs support BPP mode.  And, almost
all recent vintage PCs also support EPP.  Use EPP if it is available.


The basic PC parallel port has three byte wide registers.  These
registers and their layouts are the same across all IEEE 1284
operating modes.  They are:

 Basic parallel port registers

    Data register = PortBaseAddress + 0
    Stat register = PortBaseAddress + 1
    Ctrl register = PortBaseAddress + 2

The parallel port may have additional registers beyond these three
basic ones in the IEEE 1284 enhanced modes.  See the functions listed
further on down for the additional drivers that are required for BPP
or EPP by the PAR4CH.  The following paragraphs describe the layout
and signal mapping for each of the basic registers.



>>> DATA REGISTER / BYTE WIDE / PORTBASEADDRESS + 0 / READ & WRITE:

This register was primarily intended on the original PC parallel port
to be write only.  The output was latched and could be read back with
the same data being read back that had just been latched.  The BPP
mode (aka PS2) enhanced this so that depending on the setting of the
direction bit in the control register, independent data could be read
back rather than the latched output.


>>> STATUS REGISTER / BYTE WIDE / PORTBASEADDRESS + 1 / READ ONLY:

This is a read only register designed to return status information
from a device attached to the parallel port.  Register bit to DB25 pin
to PAR4CH signal mapping is:

Stat reg bit 0    NA             NA                      NA
Stat reg bit 1    NA             NA                      NA
Stat reg bit 2    NA             NA                      NA
Stat reg bit 3    DB25 pin 15    Parallel Error          PAR4CH PERROR
Stat reg bit 4    DB25 pin 13    Parallel Select         PAR4CH PS1
Stat reg bit 5    DB25 pin 12    Parallel Paper Empty    PAR4CH PS0
Stat reg bit 6    DB25 pin 10    Parallel Acknowledge    PAR4CH PIRQ
Stat reg bit 7    DB25 pin 11    Parallel Busy           PAR4CH PWAIT

DB25 pin 10, Parallel Acknowledge, is also connected to IRQ7 on the
ISA bus via a tri state buffer that can be enabled in the parallel
port control register.

These bits may be variously inverted or not inverted from the DB25
pin senses.  The relationships are:

PAR4CH PERROR high    DB25 pin 15 high      Stat reg bit 3 high
PAR4CH PS1 high       DB25 pin 13 high      Stat reg bit 4 high
PAR4CH PS0 high       DB25 pin 12 high      Stat reg bit 5 high
PAR4CH PIRQ high      DB25 pin 10 high      Stat reg bit 6 high
PAR4CH PWAIT high     DB25 pin 11 high      Stat reg bit 7 low



>>> CONTROL REGISTER, BYTE WIDE / PORTBASEADDRESS + 2 / READ & WRITE:

This register is primarily a write only register designed to send
control signals to a device attached to the parallel port.  The
signal values are latched and can be read back, where the read back
values are the same as the ones last programmed.  Register bit to
DB25 pin to PAR4CH signal mapping is:

Ctrl reg bit 0    DB25 pin 1     Parallel Strobe         PAR4CH PWRITE
Ctrl reg bit 1    DB25 pin 14    Parallel Auto LF        PAR4CH PDS
Ctrl reg bit 2    DB25 pin 16    Parallel Initialize     PAR4CH PINIT
Ctrl reg bit 3    DB25 pin 17    Parallel Select In      PAR4CH PAS
Ctrl reg bit 4    NA             Parallel Irq enable     NA
Ctrl reg bit 5    NA             Parallel Direction      NA
Ctrl reg bit 6    NA             NA                      NA
Ctrl reg bit 7    NA             NA                      NA

These bits may be variously inverted or not inverted from the DB25
pin senses.  The relationships are:

Ctrl reg bit 0 high    DB25 pin 1 low     PAR4CH PWRITE low
Ctrl reg bit 1 high    DB25 pin 14 low    PAR4CH PDS low
Ctrl reg bit 2 high    DB25 pin 16 high   PAR4CH PINIT high
Ctrl reg bit 3 high    DB25 pin 17 low    PAR4CH PAS low
Ctrl reg bit 4 high    NA                 Parallel port irq 7 is ENABLED
Ctrl reg bit 5 high    NA                 Parallel data dir is INPUT TO PC
Ctrl reg bit 6 high    NA
Ctrl reg bit 7 high    NA

Ctrl reg bits are not inverted on read back from their programmed
values.

*/


// Status register bit assignments: (with PAR4CH signal names)

#define PERROR                  (1 << 3)    // DB25 pin 15
#define PS1                     (1 << 4)    // DB25 pin 13
#define PS0                     (1 << 5)    // DB25 pin 12
#define PIRQ                    (1 << 6)    // DB25 pin 10
#define PWAIT                   (1 << 7)    // DB25 pin 11

#define PAR4CH_FIFO_EF_MASK          PS0      //// NOT USED
#define PAR4CH_FIFO_FF_MASK          PS1      //// NOT USED
#define PAR4CH_VOLTAGE_GOOD_MASK     PERROR   //// NOT USED



// Control register bit assignments and values: (with PAR4CH signal names)

#define PWR                     (1 << 0)    // DB25 pin 1    << PWRITE
#define PDS                     (1 << 1)    // DB25 pin 14
#define PINIT                   (1 << 2)    // DB25 pin 16
#define PAS                     (1 << 3)    // DB25 pin 17
#define PIRQEN                  (1 << 4)    // not on DB25
#define PDIR                    (1 << 5)    // not on DB25

#define PWR_READ                (0 << 0)
#define PWR_WRITE               (1 << 0)

#define PDS_NEGATE              (0 << 1)
#define PDS_ASSERT              (1 << 1)

#define PAS_NEGATE              (0 << 3)
#define PAS_ASSERT              (1 << 3)

#define PINIT_POWERDOWN         (0 << 2)
#define PINIT_POWERUP           (1 << 2)

#define PIRQ_DISABLE            (0 << 4)
#define PIRQ_ENABLE             (1 << 4)

#define PDIR_WRITE              (0 << 5)
#define PDIR_READ               (1 << 5)




SRLOCAL void Par4ch_ParPortInit( DEVINFO *Dev ) {

        dbg4_printk( "Par4ch_ParPortInit\n" );


        // Set up port addresses.

        Dev->ParPortData  = (Dev->ParPortBase + 0);
        Dev->ParPortStat  = (Dev->ParPortBase + 1);
        Dev->ParPortCtrl  = (Dev->ParPortBase + 2);
        Dev->EppPortAddr  = (Dev->ParPortBase + 3);
        Dev->EppPortData  = (Dev->ParPortBase + 4);


        // Point to EPP/BPP read/write functions according to the mode.

        if (Dev->ParPortMode == PAR4CH_PORT_MODE_EPP) {

                Dev->ParPortAsRd = Par4ch_EppAsRd;
                Dev->ParPortAsWr = Par4ch_EppAsWr;
                Dev->ParPortDsRd = Par4ch_EppDsRd;
                Dev->ParPortDsWr = Par4ch_EppDsWr;
                }
        
       else { // (Dev->ParPortMode == PAR4CH_PORT_MODE_BPP)
                
                Dev->ParPortAsRd = Par4ch_BppAsRd;
                Dev->ParPortAsWr = Par4ch_BppAsWr;
                Dev->ParPortDsRd = Par4ch_BppDsRd;
                Dev->ParPortDsWr = Par4ch_BppDsWr;
                }
        
}
SRLOCAL void Par4ch_ParPortDataRd( DEVINFO *Dev, unsigned char *Value ) {

        dbg5_printk( "Par4ch_ParPortDataRd\n" );


        // Read from the parallel port data register.

        OsPortIn( Dev->ParPortData, Value );


}
SRLOCAL void Par4ch_ParPortDataWr( DEVINFO *Dev, unsigned char Value ) {

        dbg5_printk( "Par4ch_ParPortDataWr\n" );


        // Write to the parallel port data register.

        OsPortOut( Dev->ParPortData, Value );

}
SRLOCAL void Par4ch_ParPortStatRd( DEVINFO *Dev, unsigned char *Value ) {

        dbg5_printk( "Par4ch_ParPortStatRd\n" );


        // Read from the parallel port status register.

        OsPortIn( Dev->ParPortStat, Value );

}
SRLOCAL void Par4ch_ParPortCtrlWr( DEVINFO *Dev, unsigned char Value ) {

        dbg5_printk( "Par4ch_ParPortCtrlWr\n" );


        // Write to the parallel port control register.

        Dev->ParPortCtrlValue = Value;

        OsPortOut( Dev->ParPortCtrl, Value );

}
SRLOCAL void Par4ch_ParPortCtrlRw( DEVINFO *Dev, unsigned char Value ) {

        dbg5_printk( "Par4ch_ParPortCtrlRw\n" );


        // Set the parallel port control register read/write/as/ds bits.

        Dev->ParPortCtrlValue &= ~(PWR | PDS | PAS | PDIR);
        Dev->ParPortCtrlValue |= (Value & (PWR | PDS | PAS | PDIR));

        OsPortOut( Dev->ParPortCtrl, Dev->ParPortCtrlValue );

}
SRLOCAL void Par4ch_ParPortCtrlIrqen( DEVINFO *Dev, unsigned char Value ) {

        dbg5_printk( "Par4ch_ParPortCtrlPdir\n" );


        // Set the parallel port control register PIRQEN bit.

        Dev->ParPortCtrlValue &= ~PIRQEN;
        Dev->ParPortCtrlValue |= (Value & PIRQEN);
 
        OsPortOut( Dev->ParPortCtrl, Dev->ParPortCtrlValue );

}
SRLOCAL void Par4ch_ParPortCtrlPdir( DEVINFO *Dev, unsigned char Value ) {
 
        dbg5_printk( "Par4ch_ParPortCtrlPdir\n" );


        // Set the parallel port control register PDIR bit.

        Dev->ParPortCtrlValue &= ~PDIR;
        Dev->ParPortCtrlValue |= (Value & PDIR);
 
        OsPortOut( Dev->ParPortCtrl, Dev->ParPortCtrlValue );

}





/* WAIT FOR A SPECIFIED AMOUNT OF TIME:

Operations like PowerDown and PowerUp require waiting for a period of
milliseconds.  Their wait periods go through the Par4ch_Wait function.

The wait is done by simply executing x86 in instructions.  An in
instruction from the ISA bus takes approximately 1us.  The wait
periods for power up and down are not super critical.  Another
mechanism like calling sleep could be used if preferred.

*/

SRLOCAL void Par4ch_Wait( DEVINFO *Dev, unsigned milliseconds ) {

        long microseconds;
        unsigned char value;

        dbg3_printk( "Par4ch_Wait\n" );


        // Wait for the specified number of milliseconds:

        while ( milliseconds-- ) {

                microseconds = 1000; // 1000 us = 1 ms

                while ( microseconds-- )

                        Par4ch_ParPortStatRd( Dev, &value); // ~1 us
                }

        return;
}




/* POWER GOOD:

Whether the PAR4CH on board power supply voltage is good or too low
is indicated by the PERROR bit on the parallel port status register.
This signal is active low and, if good, the on board voltage is with
within 1% of 4.75 volts.

This bit is pulled up by a resistor on the PC side of the port.

*/

SRLOCAL int Par4ch_VoltageGood( DEVINFO *Dev ) {

        unsigned char Status;

        dbg4_printk( "Par4ch_VoltageGood\n" );



        // Get the voltage good bit from the status register.

        Par4ch_ParPortStatRd( Dev, &Status );


        if ( (Status & PERROR) == 0 )   // flag low -> voltage good

                return( 1 );

        else                            // flag high -> voltage bad
                return( 0 );



}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -