📄 eppflex.c
字号:
/*
* Thomas Sailer, (C) 2000
*/
#include <basedef.h>
#include <vmm.h>
#include <vmmreg.h>
#include <debug.h>
#include <vwin32.h>
#include <vcomm.h> /* must be included before VXDWRAPS.H */
#include <vxdwraps.h>
#include <winerror.h>
#include <configmg.h>
#include "eppflex.h"
#pragma VxD_LOCKED_CODE_SEG
#pragma VxD_LOCKED_DATA_SEG
#define printk(x) Out_Debug_String(x)
#define MAXPORTS 4
static struct portconfig {
unsigned int addr0, addr0end;
unsigned int addr1, addr1end;
int irq;
int dma;
} portconfig[MAXPORTS];
static DWORD porthandle = 0;
static PFN conthandler = NULL;
static unsigned int portnr;
static DWORD StealNotifyHandler( void *RefData, DWORD dwNotification )
{
/* steal handler: we do not allow anyone to steal our port */
return FALSE;
}
static UCHAR inb(WORD port)
{
_asm {
mov dx,[port]
in al,dx
jmp del1
del1: jmp del2
del2: xor ah,ah
}
}
static void outb(UCHAR data, WORD port)
{
_asm {
mov dx,[port]
mov al,byte ptr data
out dx,al
jmp del1
del1: jmp del2
del2:
}
}
static void releaseport(void)
{
if (!conthandler)
return;
(*conthandler)(RELEASE_RESOURCE, porthandle, StealNotifyHandler);
porthandle = 0;
}
static int acquireport(unsigned int port)
{
char lptname[] = "LPTx";
int ret;
if (porthandle)
releaseport();
porthandle = 0;
if (port >= MAXPORTS)
return ERROR_BAD_DEVICE;
if (!portconfig[port].addr0)
return ERROR_BAD_DEVICE;
portnr = port;
lptname[3] = '1' + port;
conthandler = VCOMM_Get_Contention_Handler(lptname);
if (!conthandler)
return ERROR_BAD_DEVICE;
porthandle = VCOMM_Map_Name_To_Resource(lptname);
if (!porthandle)
return ERROR_BAD_DEVICE;
ret = (*conthandler)(ACQUIRE_RESOURCE, porthandle, StealNotifyHandler, porthandle, TRUE);
if (!ret)
return ERROR_BAD_DEVICE;
return NO_ERROR;
}
/*
* LPT find configuration stuff
*/
static void printknum(DWORD num)
{
char buf[16];
char *cp = &buf[16];
*--cp = 0;
do {
*--cp = '0' + (num % 10);
num /= 10;
} while (num);
printk(cp);
}
static void printkhex(DWORD num, DWORD digits)
{
char buf[9];
char *cp = &buf[9];
*--cp = 0;
if (digits > 8)
digits = 8;
if (!digits)
return;
do {
if ((num & 15) >= 10)
*--cp = 'A' - 10 + (num & 15);
else
*--cp = '0' + (num & 15);
num >>= 4;
digits--;
} while (digits);
printk(cp);
}
static void printdevid(DEVNODE dn)
{
char buf[MAX_DEVICE_ID_LEN];
if (CM_Get_Device_ID(dn, buf, sizeof(buf), 0) != CR_SUCCESS)
return;
printk("Device ID: ");
printk(buf);
printk("\n");
}
static void nodefoundport(DEVNODE dn, unsigned int portnr)
{
LOG_CONF lc;
RES_DES rd;
IO_DES iod;
IRQ_DES irqd;
DMA_DES dmad;
struct portconfig cfg;
if (portnr >= MAXPORTS) {
printk("Port number overflow\n");
return;
}
cfg.addr0 = cfg.addr0end = cfg.addr1 = cfg.addr1end = 0;
cfg.irq = cfg.dma = -1;
if (CM_Get_First_Log_Conf(&lc, dn, ALLOC_LOG_CONF) == CR_SUCCESS) {
rd = (RES_DES)lc;
while (CM_Get_Next_Res_Des(&rd, rd, ResType_IO, NULL, 0) == CR_SUCCESS) {
if (CM_Get_Res_Des_Data(rd, &iod, sizeof(iod), 0) == CR_SUCCESS) {
if (iod.IOD_Alloc_Base >= 0x400) {
cfg.addr1 = iod.IOD_Alloc_Base;
cfg.addr1end = iod.IOD_Alloc_End;
} else {
cfg.addr0 = iod.IOD_Alloc_Base;
cfg.addr0end = iod.IOD_Alloc_End;
}
}
}
rd = (RES_DES)lc;
while (CM_Get_Next_Res_Des(&rd, rd, ResType_IRQ, NULL, 0) == CR_SUCCESS) {
if (CM_Get_Res_Des_Data(rd, &irqd, sizeof(irqd), 0) == CR_SUCCESS) {
cfg.irq = irqd.IRQD_Alloc_Num;
}
}
rd = (RES_DES)lc;
while (CM_Get_Next_Res_Des(&rd, rd, ResType_DMA, NULL, 0) == CR_SUCCESS) {
if (CM_Get_Res_Des_Data(rd, &dmad, sizeof(dmad), 0) == CR_SUCCESS) {
cfg.dma = dmad.DD_Alloc_Chan;
}
}
}
if (cfg.addr0)
portconfig[portnr] = cfg;
printk("LPT");
printknum(portnr+1);
printk(": IO Ranges: ");
printkhex(cfg.addr0, 4);
printk("-");
printkhex(cfg.addr0end, 4);
printk(" ");
printkhex(cfg.addr1, 4);
printk("-");
printkhex(cfg.addr1end, 4);
if (cfg.irq != -1) {
printk(" IRQ ");
printknum(cfg.irq);
}
if (cfg.dma != -1) {
printk(" DMA ");
printknum(cfg.dma);
}
printk("\n");
}
static void nodeconfig(DEVNODE dn)
{
char key[MAX_VMM_REG_KEY_LEN];
char portname[64];
ULONG portsz;
VMMHKEY hkey;
if (CM_Get_DevNode_Key(dn, NULL, &key, sizeof(key), CM_REGISTRY_HARDWARE) == CR_SUCCESS) {
portsz = sizeof(portname);
if (_RegOpenKey(HKEY_LOCAL_MACHINE, key, &hkey) == ERROR_SUCCESS) {
if (_RegQueryValueEx(hkey, "PORTNAME", NULL, NULL, portname, &portsz) == ERROR_SUCCESS) {
printdevid(dn);
printk("Port name: ");
printk(portname);
printk("\n");
if (portname[0] = 'L' && portname[1] == 'P' && portname[2] == 'T' && portname[4] == 0)
nodefoundport(dn, portname[3] - '1');
}
_RegCloseKey(hkey);
}
}
}
static void nodesubtree(DEVNODE dn)
{
DWORD dnch;
do {
nodeconfig(dn);
if (CM_Get_Child(&dnch, dn, 0) == CR_SUCCESS)
nodesubtree(dnch);
} while (CM_Get_Sibling(&dn, dn, 0) == CR_SUCCESS);
}
static void retrieveconfig(void)
{
DEVNODE dn;
CONFIGRET ret;
ret = CM_Locate_DevNode(&dn, NULL, 0);
if (ret != CR_SUCCESS) {
printk("Locate_DevNode error: ");
printknum(ret);
printk("\n");
return;
}
nodesubtree(dn);
}
BOOL OnSysDynamicDeviceInit(void)
{
printk("eppflex: dynamic init\n");
memset(portconfig, 0, sizeof(portconfig));
retrieveconfig();
return TRUE;
}
BOOL OnSysDynamicDeviceExit(void)
{
printk("eppflex: dynamic exit\n");
if (porthandle)
releaseport();
return TRUE;
}
static DWORD read_port(PDIOCPARAMETERS p, WORD port)
{
struct eppflex_rwdata *rwout = (struct eppflex_rwdata *)p->lpvOutBuffer;
if (!porthandle)
return ERROR_INVALID_PARAMETER;
if (p->cbOutBuffer < sizeof(struct eppflex_rwdata))
return ERROR_INVALID_PARAMETER;
if (!port)
return ERROR_INVALID_PARAMETER;
if ((port < portconfig[portnr].addr0 || port > portconfig[portnr].addr0end) &&
(port < portconfig[portnr].addr1 || port > portconfig[portnr].addr1end))
return ERROR_INVALID_PARAMETER;
rwout->data = inb(port);
if (p->lpcbBytesReturned)
*((DWORD *)p->lpcbBytesReturned) = sizeof(struct eppflex_rwdata);
return NO_ERROR;
}
static DWORD write_port(PDIOCPARAMETERS p, WORD port)
{
struct eppflex_rwdata *rwin = (struct eppflex_rwdata *)p->lpvInBuffer;
if (!porthandle)
return ERROR_INVALID_PARAMETER;
if (p->cbInBuffer < sizeof(struct eppflex_rwdata))
return ERROR_INVALID_PARAMETER;
if (!port)
return ERROR_INVALID_PARAMETER;
if ((port < portconfig[portnr].addr0 || port > portconfig[portnr].addr0end) &&
(port < portconfig[portnr].addr1 || port > portconfig[portnr].addr1end))
return ERROR_INVALID_PARAMETER;
outb(rwin->data, port);
if (p->lpcbBytesReturned)
*((DWORD *)p->lpcbBytesReturned) = 0;
return NO_ERROR;
}
static DWORD frob_port(PDIOCPARAMETERS p, WORD port)
{
struct eppflex_rwdata *rwin = (struct eppflex_rwdata *)p->lpvInBuffer;
struct eppflex_rwdata *rwout = (struct eppflex_rwdata *)p->lpvOutBuffer;
unsigned char data;
if (!porthandle)
return ERROR_INVALID_PARAMETER;
if (p->cbInBuffer < sizeof(struct eppflex_rwdata) ||
p->cbOutBuffer < sizeof(struct eppflex_rwdata))
return ERROR_INVALID_PARAMETER;
if (!port)
return ERROR_INVALID_PARAMETER;
if ((port < portconfig[portnr].addr0 || port > portconfig[portnr].addr0end) &&
(port < portconfig[portnr].addr1 || port > portconfig[portnr].addr1end))
return ERROR_INVALID_PARAMETER;
data = inb(port);
data = (data & ~rwin->mask) ^ rwin->data;
outb(data, port);
rwout->data = data;
rwout->mask = rwin->mask;
if (p->lpcbBytesReturned)
*((DWORD *)p->lpcbBytesReturned) = sizeof(struct eppflex_rwdata);
return NO_ERROR;
}
DWORD OnW32DeviceIoControl(PDIOCPARAMETERS p)
{
if (p->lpcbBytesReturned)
*((DWORD *)p->lpcbBytesReturned) = 0;
switch (p->dwIoControlCode) {
case DIOC_OPEN:
return NO_ERROR;
case DIOC_CLOSEHANDLE:
return NO_ERROR;
case IOCTL_EPPFLEX_READ_DATA:
return read_port(p, (WORD)(portconfig[portnr].addr0));
case IOCTL_EPPFLEX_WRITE_DATA:
return write_port(p, (WORD)(portconfig[portnr].addr0));
case IOCTL_EPPFLEX_READ_STATUS:
return read_port(p, (WORD)(portconfig[portnr].addr0 + 1));
case IOCTL_EPPFLEX_WRITE_STATUS:
return write_port(p, (WORD)(portconfig[portnr].addr0 + 1));
case IOCTL_EPPFLEX_READ_CONTROL:
return read_port(p, (WORD)(portconfig[portnr].addr0 + 2));
case IOCTL_EPPFLEX_WRITE_CONTROL:
return write_port(p, (WORD)(portconfig[portnr].addr0 + 2));
case IOCTL_EPPFLEX_FROB_CONTROL:
return frob_port(p, (WORD)(portconfig[portnr].addr0 + 2));
case IOCTL_EPPFLEX_READ_ECONTROL:
return read_port(p, (WORD)(portconfig[portnr].addr1 + 2));
case IOCTL_EPPFLEX_WRITE_ECONTROL:
return write_port(p, (WORD)(portconfig[portnr].addr1 + 2));
case IOCTL_EPPFLEX_FROB_ECONTROL:
return frob_port(p, (WORD)(portconfig[portnr].addr1 + 2));
case IOCTL_EPPFLEX_READ_CONFIGA:
return read_port(p, (WORD)(portconfig[portnr].addr1));
case IOCTL_EPPFLEX_WRITE_CONFIGA:
return write_port(p, (WORD)(portconfig[portnr].addr1));
case IOCTL_EPPFLEX_READ_CONFIGB:
return read_port(p, (WORD)(portconfig[portnr].addr1 + 1));
case IOCTL_EPPFLEX_WRITE_CONFIGB:
return write_port(p, (WORD)(portconfig[portnr].addr1 + 1));
case IOCTL_EPPFLEX_READ_EPPADDR:
return read_port(p, (WORD)(portconfig[portnr].addr0 + 3));
case IOCTL_EPPFLEX_WRITE_EPPADDR:
return write_port(p, (WORD)(portconfig[portnr].addr0 + 3));
case IOCTL_EPPFLEX_READ_EPPDATA:
return read_port(p, (WORD)(portconfig[portnr].addr0 + 4));
case IOCTL_EPPFLEX_WRITE_EPPDATA:
return write_port(p, (WORD)(portconfig[portnr].addr0 + 4));
case IOCTL_EPPFLEX_ACQUIREPORT:
if (p->cbInBuffer < sizeof(unsigned int))
return ERROR_INVALID_PARAMETER;
return acquireport(*((unsigned int *)p->lpvInBuffer));
case IOCTL_EPPFLEX_RELEASEPORT:
releaseport();
return NO_ERROR;
default:
return ERROR_NOT_SUPPORTED;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -