If the parport is used as low-level I/O device (like done for simple
logic analyzers or programmer devices for microcontrollers), the host
changes the direction of the parallel port as input and reads the data bits.
Reading has already been implemented, but the direction change was not
forwarded to the ppdev driver on Linux. So what the guest read was not
the state of the hardware but the last value written to the port.
This patch implements changing the direction. The patch has been tested
on Linux host (Arch Linux) with a Linux guest (openSUSE 11.4) with a
simple parport.c file (attached) and with a Windows XP guest (Windows XP
with all patches) with tfla-01.berlios.de and giveio.sys.
Submitted by: Bernhard Walle <[email protected]>
License: MIT License
Index: include/VBox/vmm/pdmifs.h
===================================================================
--- include/VBox/vmm/pdmifs.h (Revision 37161)
+++ include/VBox/vmm/pdmifs.h (Arbeitskopie)
@@ -1800,6 +1800,17 @@
DECLR3CALLBACKMEMBER(int, pfnWriteControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg));
/**
+ * Sets the data direction of the parallel port.
+ *
+ *
+ * @returns VBox status code.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param dir The new direction, 0 -> forward, != 0 -> reverse.
+ * @thread Any thread.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnSetDirection,(PPDMIHOSTPARALLELCONNECTOR pInterface, int direction));
+
+ /**
* Read control register bits.
*
* @returns VBox status code.
Index: src/VBox/Devices/Parallel/DrvHostParallel.cpp
===================================================================
--- src/VBox/Devices/Parallel/DrvHostParallel.cpp (Revision 37161)
+++ src/VBox/Devices/Parallel/DrvHostParallel.cpp (Arbeitskopie)
@@ -155,6 +155,18 @@
return VINF_SUCCESS;
}
+static DECLCALLBACK(int) drvHostParallelSetDirection(PPDMIHOSTPARALLELCONNECTOR pInterface, int dir)
+{
+ PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
+
+ LogFlow(("%s: dir=%d\n", __FUNCTION__, dir));
+
+ /* 0 -> forward, != 0 -> reverse */
+ ioctl(pThis->FileDevice, PPDATADIR, &dir);
+
+ return VINF_SUCCESS;
+}
+
static DECLCALLBACK(int) drvHostParallelReadControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)
{
PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
@@ -313,6 +325,7 @@
pThis->IHostParallelConnector.pfnRead = drvHostParallelRead;
pThis->IHostParallelConnector.pfnSetMode = drvHostParallelSetMode;
pThis->IHostParallelConnector.pfnWriteControl = drvHostParallelWriteControl;
+ pThis->IHostParallelConnector.pfnSetDirection = drvHostParallelSetDirection;
pThis->IHostParallelConnector.pfnReadControl = drvHostParallelReadControl;
pThis->IHostParallelConnector.pfnReadStatus = drvHostParallelReadStatus;
Index: src/VBox/Devices/Parallel/DevParallel.cpp
===================================================================
--- src/VBox/Devices/Parallel/DevParallel.cpp (Revision 37161)
+++ src/VBox/Devices/Parallel/DevParallel.cpp (Arbeitskopie)
@@ -216,7 +216,22 @@
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
#else
- int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
+ int rc;
+
+ /* direction changed? */
+ if (s->pDrvHostParallelConnector->pfnSetDirection)
+ {
+ if ((ch & LPT_CONTROL_ENABLE_BIDIRECT) != (s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
+ {
+ int dir = ch & LPT_CONTROL_ENABLE_BIDIRECT;
+ rc = s->pDrvHostParallelConnector->pfnSetDirection(s->pDrvHostParallelConnector, dir);
+ }
+ }
+
+ /* something else changed? */
+ if ((ch & 0x1f) != (s->reg_control & 0x1f))
+ rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch & 0x1f);
+
AssertRC(rc);
s->reg_control = val;
#endif
/*
* Reads data from the parallel port and prints it on stdout.
*
* Compile with
* $ gcc -W -Wall -o parportread parportread.c -lieee1284
*
* Run with
* $ ./parportread
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <signal.h>
#include <ieee1284.h>
static unsigned int s_usleep_time = 1000000;
static int s_port_number = 0;
static volatile bool s_finish = false;
/* ---------------------------------------------------------------------------------------------- */
void sig_handler(int signal)
{
/* supress warning */
signal = signal;
s_finish = true;
}
/* ---------------------------------------------------------------------------------------------- */
void print_binary(unsigned char byte)
{
char string[9];
int i;
for (i = 0; i < 8; i++)
{
string[7 - i] = byte & (1 << i) ? '1' : '0';
}
string[8] = 0;
printf("%s\n", string);
}
/* ---------------------------------------------------------------------------------------------- */
bool register_signal_handler(void)
{
/* register the interrupt handler */
if (signal(SIGINT, sig_handler) == SIG_ERR)
{
perror("Could not register signal handler for SIGINT");
return false;
}
if (signal(SIGTERM, sig_handler) == SIG_ERR)
{
perror("Could not register signal handler for SIGTERM");
return false;
}
return true;
}
/* ---------------------------------------------------------------------------------------------- */
void print_help(void)
{
fprintf(stderr,
" -h Print this help information\n"
" -p <number> Use parallel port number <number>\n"
" Default is 0\n"
" -i <interval> Measure <interval> times per second\n"
" Default is 1\n" );
}
/* ---------------------------------------------------------------------------------------------- */
bool parse_command_line(int argc, char* argv[])
{
int option;
while ((option = getopt(argc, argv, "hp:i:")) != EOF)
{
switch (option)
{
case 'h':
print_help();
return false;
case 'p':
s_port_number = atoi(optarg);
break;
case 'i':
s_usleep_time = 1000000 / atoi(optarg);
break;
}
}
return true;
}
/* ---------------------------------------------------------------------------------------------- */
int main(int argc, char* argv[])
{
int ret;
struct parport_list pplist;
struct parport* port;
if (!parse_command_line(argc, argv))
{
return EXIT_FAILURE;
}
if (!register_signal_handler())
{
return EXIT_FAILURE;
}
/* find the ports */
if ((ret = ieee1284_find_ports(&pplist, 0)) != E1284_OK)
{
fprintf(stderr, "Failed to run ieee1284_find_ports: %d\n", ret);
return EXIT_FAILURE;
}
/* check if the port number is valid */
if (s_port_number >= pplist.portc)
{
fprintf(stderr, "Invalid port number. Must be less than %d\n", pplist.portc);
return EXIT_FAILURE;
}
/* use the specified port */
port = pplist.portv[s_port_number];
/* open */
if ((ret = ieee1284_open(port, 0, NULL)) != E1284_OK)
{
fprintf(stderr, "Failed to run ieee1284_open: %d\n", ret);
return EXIT_FAILURE;
}
/* claim */
if ((ret = ieee1284_claim(port)) != E1284_OK)
{
fprintf(stderr, "Failed to run ieee1284_claim: %d\n", ret);
return EXIT_FAILURE;
}
/* revert direction */
if ((ret = ieee1284_data_dir(port, true)) != E1284_OK)
{
fprintf(stderr, "Failed to run ieee1284_data_dir: %d\n", ret);
return EXIT_FAILURE;
}
/* measure loop */
while (!s_finish)
{
unsigned char data = ieee1284_read_data(port);
print_binary(data);
usleep(s_usleep_time);
}
return EXIT_SUCCESS;
}
_______________________________________________
vbox-dev mailing list
[email protected]
http://vbox.innotek.de/mailman/listinfo/vbox-dev