Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

338 lines
8.7 KiB

/*
* vidcio.c
*
* 32-bit Video Capture driver
*
* chip register access functions for Bravado card
*
* Geraint Davies, Feb 93
*/
#include <vckernel.h>
#include <bravado.h>
#include "hardware.h"
#include "vidcio.h"
/*
* the vckernel library does not synchronise calls to the
* InterruptAcknowledge or CaptureService functions with calls to the
* other h/w callbacks (all the other callback functions are synchronised
* with each other).
*
* The interrupt ack function does not do much, but it does access the
* PCVideo chip, and thus could change the index register between a write to
* the index reg and a write to the data.
* Thus we need to sync calls to functions in this module with
* the interrupt. We do this using the vckernel wrapper function
* VC_SynchronizeExecution - on NT this will be a call to KeSynchronizeExecution,
* and on Win-16 this would be a disable-interrupt.
*
* Calls to HW_SetPCVideoReg, HW_Set9051Reg, HW_Set4680Reg and HW_GetPCVideoReg
* thus package up their arguments and call this function: this function
* will disable the interrupts as appropriate and call back to
* the relevant HW_Set*Reg_Sync function to do the operation.
*
*/
/* -- forward declarations -------------------------------------------------*/
BOOLEAN HW_Set9051Reg_Sync(PSYNC_REG_ARG);
BOOLEAN HW_Set4680Reg_Sync(PSYNC_REG_ARG);
BOOLEAN HW_SetPCVideoReg_Sync(PSYNC_REG_ARG);
BOOLEAN HW_GetPCVideoReg_Sync(PSYNC_REG_ARG);
/* -- external functions --------------------------------------------------*/
VOID
HW_Set9051Reg(PDEVICE_INFO pDevInfo, BYTE bRegister, BYTE bData)
{
SYNC_REG_ARG SyncArg;
if (bRegister > NR_REG_9051) {
dprintf(("bad register nr for 9051"));
return;
}
SyncArg.pDevInfo = pDevInfo;
SyncArg.bRegister = bRegister;
SyncArg.bData = bData;
VC_SynchronizeExecution(pDevInfo, (PSYNC_ROUTINE) HW_Set9051Reg_Sync, &SyncArg);
}
VOID
HW_Set4680Reg(PDEVICE_INFO pDevInfo, BYTE bRegister, BYTE bData)
{
SYNC_REG_ARG SyncArg;
if (bRegister > NR_REG_4680) {
dprintf(("bad register nr for 4680"));
return;
}
SyncArg.pDevInfo = pDevInfo;
SyncArg.bRegister = bRegister;
SyncArg.bData = bData;
VC_SynchronizeExecution(pDevInfo, (PSYNC_ROUTINE) HW_Set4680Reg_Sync, &SyncArg);
}
/*
* set a register on the main PCVideo chip
*/
VOID HW_SetPCVideoReg(PDEVICE_INFO pDevInfo, BYTE bRegister, BYTE bData)
{
SYNC_REG_ARG SyncArg;
SyncArg.pDevInfo = pDevInfo;
SyncArg.bRegister = bRegister;
SyncArg.bData = bData;
VC_SynchronizeExecution(pDevInfo, (PSYNC_ROUTINE) HW_SetPCVideoReg_Sync, &SyncArg);
}
/* get back the value of a PCVideo register */
BYTE
HW_GetPCVideoReg(PDEVICE_INFO pDevInfo, BYTE bRegister)
{
SYNC_REG_ARG SyncArg;
SyncArg.pDevInfo = pDevInfo;
SyncArg.bRegister = bRegister;
VC_SynchronizeExecution(pDevInfo, (PSYNC_ROUTINE) HW_GetPCVideoReg_Sync, &SyncArg);
return(SyncArg.bData);
}
/*--- internal device-access functions ------------------------------*/
/*
* all the devices on the board with the exception of the PCVideo chip
* are accessed via the I2C bus. This is a 1-bit serial bus, so for
* each output we need to individually clock out onto the bus one
* bit at a time a master(device) address, a sub address (the device reg) and
* the data
*
* We put the data onto the data bit with the clock low, and then set the
* clock high. The data must be stable during clock-high, except for start bits
* and stop bits. A data high-to-low transition during clock-high is a
* start bit, and a data low-to-high transition during clock-high is a stop bit.
*
* An output sequence consists of a start bit, three bytes (chip address,
* register address and data) and then a stop bit. Each of the three bytes
* is sent msb first, and is followed by an immediate ack bit before the
* next byte starts.
*
* For efficiency, we set the PCV_INDEX register to point to the
* I2C control register once at the start of the sequence.
*/
typedef enum _i2c_types {ClockBit, DataBit} i2c_types;
/*
* this function writes one clock or data bit onto the I2C bus
*/
VOID
HW_WriteI2C(PDEVICE_INFO pDevInfo, i2c_types type, BOOL bData)
{
/* assume I2C control register selected on PCV */
if (type == ClockBit) {
VC_Out(pDevInfo, PCV_DATA,
(BYTE) ((VC_In(pDevInfo, PCV_DATA) & 0xfe) | (bData ? 1 : 0)));
} else {
VC_Out(pDevInfo, PCV_DATA,
(BYTE) ((VC_In(pDevInfo, PCV_DATA) & 0xfd) | (bData ? 0x2 : 0)));
}
}
/*
* read back the value of the clock or data bit
*/
UINT HW_ReadI2C(PDEVICE_INFO pDevInfo, i2c_types type)
{
UINT uVal;
/* assume I2C control regiseter selected on PCV */
uVal = VC_In(pDevInfo, PCV_DATA);
if (type == ClockBit) {
return(uVal & 0x1);
} else {
return((uVal >> 1) & 0x1);
}
}
/*
* clock one whole byte onto the I2C bus not including start or stop
* bits (since these are sent round a whole transmission, not each byte)
*
*/
void HW_ByteToI2C(PDEVICE_INFO pDevInfo, BYTE bData)
{
int i;
/* write each bit, MSB first.
* fortunately HW_WriteI2C takes a BOOL to save us the trouble
* of reversing the bits
*/
for (i = 0; i < 8; i++, bData <<= 1) {
/* write data bit */
HW_WriteI2C(pDevInfo, DataBit, bData & 0x80);
/* turn clock on and off */
HW_WriteI2C(pDevInfo, ClockBit, TRUE);
KeStallExecutionProcessor(5);
HW_WriteI2C(pDevInfo, ClockBit, FALSE);
KeStallExecutionProcessor(4);
}
/* ack sequence */
HW_WriteI2C(pDevInfo, DataBit, TRUE);
HW_WriteI2C(pDevInfo, ClockBit, TRUE);
KeStallExecutionProcessor(1);
HW_ReadI2C(pDevInfo, ClockBit);
HW_WriteI2C(pDevInfo, ClockBit, FALSE);
}
/* write data to a given register on a given device on the I2C bus */
VOID
HW_SetI2CReg(PDEVICE_INFO pDevInfo, BYTE bAddress, BYTE bSubAddress, BYTE bData)
{
/* the HW_WriteI2C and HW_ByteToI2C functions assume that
* the PCV_INDEX register is already set up to point to the
* I2C control register.
*/
VC_Out(pDevInfo, PCV_INDEX, REG_I2C);
/* start bit */
HW_WriteI2C(pDevInfo, DataBit, TRUE);
HW_WriteI2C(pDevInfo, ClockBit, TRUE);
KeStallExecutionProcessor(5);
HW_WriteI2C(pDevInfo, DataBit, FALSE);
KeStallExecutionProcessor(5);
HW_WriteI2C(pDevInfo, ClockBit, FALSE);
HW_ByteToI2C(pDevInfo, bAddress);
HW_ByteToI2C(pDevInfo, bSubAddress);
HW_ByteToI2C(pDevInfo, bData);
/* stop bit */
HW_WriteI2C(pDevInfo, DataBit, FALSE);
HW_WriteI2C(pDevInfo, ClockBit, TRUE);
KeStallExecutionProcessor(5);
HW_WriteI2C(pDevInfo, DataBit, TRUE);
KeStallExecutionProcessor(5);
}
/*
* set a register on the 9051 signal digitiser chip that controls signal
* capture - this is done via the I2C bus and so we also keep a copy
* of the data in the HWInfo since its easier than struggling to get bytes
* back over the I2C bus.
*/
BOOLEAN
HW_Set9051Reg_Sync(PSYNC_REG_ARG pSync)
{
if (pSync->bRegister > NR_REG_9051) {
dprintf(("bad register nr for 9051"));
return FALSE;
}
HW_SetI2CReg(pSync->pDevInfo, ADDR_9051, pSync->bRegister, pSync->bData);
((PHWINFO) VC_GetHWInfo(pSync->pDevInfo))->bReg9051[pSync->bRegister]
= pSync->bData;
return(TRUE);
}
/* get back the value of a 9051 register -
* use the copy in the HWInfo struct.
*/
BYTE
HW_Get9051Reg(PDEVICE_INFO pDevInfo, BYTE bRegister)
{
if (bRegister > NR_REG_9051) {
dprintf(("bad register nr for 9051"));
return(0);
}
return( ((PHWINFO)VC_GetHWInfo(pDevInfo))->bReg9051[bRegister]);
}
/*
* set a register on the 4680 chip that controls overlay display
*/
BOOLEAN
HW_Set4680Reg_Sync(PSYNC_REG_ARG pSync)
{
if (pSync->bRegister > NR_REG_4680) {
dprintf(("bad register nr for 4680"));
return FALSE;
}
HW_SetI2CReg(pSync->pDevInfo, ADDR_4680, pSync->bRegister, pSync->bData);
((PHWINFO) VC_GetHWInfo(pSync->pDevInfo))->bReg4680[pSync->bRegister]
= pSync->bData;
return(TRUE);
}
/* get back the value of a 4680 register */
BYTE
HW_Get4680Reg(PDEVICE_INFO pDevInfo, BYTE bRegister)
{
if (bRegister > NR_REG_4680) {
dprintf(("bad register nr for 4680"));
return(0);
}
return( ((PHWINFO)VC_GetHWInfo(pDevInfo))->bReg4680[bRegister] );
}
/*
* set a register on the main PCVideo chip
*/
BOOLEAN
HW_SetPCVideoReg_Sync(PSYNC_REG_ARG pSync)
{
VC_Out(pSync->pDevInfo, PCV_INDEX, pSync->bRegister);
VC_Out(pSync->pDevInfo, PCV_DATA, pSync->bData);
if (pSync->bRegister < NR_REG_PCVIDEO) {
((PHWINFO)VC_GetHWInfo(pSync->pDevInfo))->bRegPCVideo[pSync->bRegister]
= pSync->bData;
}
return(TRUE);
}
/* get back the value of a PCVideo register */
BOOLEAN
HW_GetPCVideoReg_Sync(PSYNC_REG_ARG pSync)
{
VC_Out(pSync->pDevInfo, PCV_INDEX, pSync->bRegister);
pSync->bData = VC_In(pSync->pDevInfo, PCV_DATA);
return(TRUE);
}