VirtualBox

source: vbox/trunk/src/VBox/Devices/Parallel/DrvHostParallel.cpp@ 4071

Last change on this file since 4071 was 4071, checked in by vboxsync, 18 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.6 KB
Line 
1/* $Id: DrvHostParallel.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
2/** @file
3 * VirtualBox Host Parallel Port Driver.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DRV_HOST_PARALLEL
22#include <VBox/pdmdrv.h>
23#include <iprt/asm.h>
24#include <iprt/assert.h>
25#include <iprt/stream.h>
26#include <iprt/semaphore.h>
27
28#ifdef RT_OS_LINUX
29# include <sys/ioctl.h>
30# include <sys/types.h>
31# include <sys/stat.h>
32# include <fcntl.h>
33# include <unistd.h>
34# include <linux/ppdev.h>
35# include <linux/parport.h>
36#endif
37
38#include "Builtins.h"
39#include "ParallelIOCtlCmd.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * Host parallel port driver instance data.
47 */
48typedef struct DRVHOSTPARALLEL
49{
50 /** Pointer to the driver instance structure. */
51 PPDMDRVINS pDrvIns;
52 /** Pointer to the char port interface of the driver/device above us. */
53 PPDMIHOSTDEVICEPORT pDrvHostDevicePort;
54 /** Our host device interface. */
55 PDMIHOSTDEVICECONNECTOR IHostDeviceConnector;
56 /** Our host device port interface. */
57 PDMIHOSTDEVICEPORT IHostDevicePort;
58 /** Device Path */
59 char *pszDevicePath;
60 /** Device Handle */
61 RTFILE FileDevice;
62 /** Flag to notify the receive thread it should terminate. */
63 volatile bool fShutdown;
64 /** Receive thread ID. */
65 RTTHREAD ReceiveThread;
66 /** Send thread ID. */
67 RTTHREAD SendThread;
68 /** Send event semephore */
69 RTSEMEVENT SendSem;
70
71} DRVHOSTPARALLEL, *PDRVHOSTPARALLEL;
72
73/** Converts a pointer to DRVHOSTPARALLEL::IHostDeviceConnector to a PDRHOSTPARALLEL. */
74#define PDMIHOSTDEVICECONNECTOR_2_DRVHOSTPARALLEL(pInterface) ( (PDRVHOSTPARALLEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPARALLEL, IHostDeviceConnector)) )
75/** Converts a pointer to DRVHOSTPARALLEL::IHostDevicePort to a PDRHOSTPARALLEL. */
76#define PDMIHOSTDEVICEPORT_2_DRVHOSTPARALLEL(pInterface) ( (PDRVHOSTPARALLEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPARALLEL, IHostDevicePort)) )
77
78/* -=-=-=-=- IBase -=-=-=-=- */
79
80/**
81 * Queries an interface to the driver.
82 *
83 * @returns Pointer to interface.
84 * @returns NULL if the interface was not supported by the driver.
85 * @param pInterface Pointer to this interface structure.
86 * @param enmInterface The requested interface identification.
87 */
88static DECLCALLBACK(void *) drvHostParallelQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
89{
90 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
91 PDRVHOSTPARALLEL pData = PDMINS2DATA(pDrvIns, PDRVHOSTPARALLEL);
92 switch (enmInterface)
93 {
94 case PDMINTERFACE_BASE:
95 return &pDrvIns->IBase;
96 case PDMINTERFACE_HOST_DEVICE_CONNECTOR:
97 return &pData->IHostDeviceConnector;
98 default:
99 return NULL;
100 }
101}
102
103/* -=-=-=-=- IHostDeviceConnector -=-=-=-=- */
104
105/** @copydoc PDMICHAR::pfnWrite */
106static DECLCALLBACK(int) drvHostParallelWrite(PPDMIHOSTDEVICECONNECTOR pInterface, const void *pvBuf, size_t *cbWrite)
107{
108 PDRVHOSTPARALLEL pData = PDMIHOSTDEVICECONNECTOR_2_DRVHOSTPARALLEL(pInterface);
109 const unsigned char *pBuffer = (const unsigned char *)pvBuf;
110
111 LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, *cbWrite));
112
113 ioctl(pData->FileDevice, PPWDATA, pBuffer);
114
115 RTSemEventSignal(pData->SendSem);
116 return VINF_SUCCESS;
117}
118
119static DECLCALLBACK(int) drvHostParallelRead(PPDMIHOSTDEVICECONNECTOR pInterface, void *pvBuf, size_t *cbRead)
120{
121 PDRVHOSTPARALLEL pData = PDMIHOSTDEVICECONNECTOR_2_DRVHOSTPARALLEL(pInterface);
122 unsigned char *pBuffer = (unsigned char *)pvBuf;
123
124 LogFlow(("%s: pvBuf=%#p cbRead=%d\n", __FUNCTION__, pvBuf, cbRead));
125
126 ioctl(pData->FileDevice, PPRDATA, pBuffer);
127 *cbRead = 1;
128
129 return VINF_SUCCESS;
130}
131
132static DECLCALLBACK(int) drvHostParallelIOCtl(PPDMIHOSTDEVICECONNECTOR pInterface, RTUINT uCommand,
133 void *pvData)
134{
135 PDRVHOSTPARALLEL pData = PDMIHOSTDEVICECONNECTOR_2_DRVHOSTPARALLEL(pInterface);
136 unsigned long ioctlCommand;
137
138 LogFlow(("%s: uCommand=%d pvData=%#p\n", __FUNCTION__, uCommand, pvData));
139
140 switch (uCommand) {
141 case LPT_IOCTL_COMMAND_SET_CONTROL:
142 ioctlCommand = PPWCONTROL;
143 break;
144 case LPT_IOCTL_COMMAND_GET_CONTROL:
145 ioctlCommand = PPRCONTROL;
146 break;
147 }
148
149 ioctl(pData->FileDevice, ioctlCommand, pvData);
150
151 return VINF_SUCCESS;
152}
153
154/**
155 * Construct a host parallel driver instance.
156 *
157 * @returns VBox status.
158 * @param pDrvIns The driver instance data.
159 * If the registration structure is needed,
160 * pDrvIns->pDrvReg points to it.
161 * @param pCfgHandle Configuration node handle for the driver. Use this to
162 * obtain the configuration of the driver instance. It's
163 * also found in pDrvIns->pCfgHandle as it's expected to
164 * be used frequently in this function.
165 */
166static DECLCALLBACK(int) drvHostParallelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
167{
168 PDRVHOSTPARALLEL pData = PDMINS2DATA(pDrvIns, PDRVHOSTPARALLEL);
169 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
170
171 /*
172 * Init basic data members and interfaces.
173 */
174 pData->ReceiveThread = NIL_RTTHREAD;
175 pData->fShutdown = false;
176 /* IBase. */
177 pDrvIns->IBase.pfnQueryInterface = drvHostParallelQueryInterface;
178 /* IChar. */
179 pData->IHostDeviceConnector.pfnWrite = drvHostParallelWrite;
180 pData->IHostDeviceConnector.pfnIOCtl = drvHostParallelIOCtl;
181 pData->IHostDeviceConnector.pfnRead = drvHostParallelRead;
182
183 /*
184 * Query configuration.
185 */
186 /* Device */
187 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "DevicePath", &pData->pszDevicePath);
188 if (VBOX_FAILURE(rc))
189 {
190 AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Vra.\n", rc));
191 return rc;
192 }
193
194 /*
195 * Open the device
196 */
197 pData->FileDevice = open(pData->pszDevicePath, O_RDWR | O_NONBLOCK);
198 if (pData->FileDevice < 0) {
199
200 }
201
202 /*
203 * Try to get exclusive access to parallel port
204 */
205 if (ioctl(pData->FileDevice, PPEXCL) < 0) {
206 }
207
208 /*
209 * Claim the parallel port
210 */
211 if (ioctl(pData->FileDevice, PPCLAIM) < 0) {
212 }
213
214 /*
215 * Get the IHostDevicePort interface of the above driver/device.
216 */
217 pData->pDrvHostDevicePort = (PPDMIHOSTDEVICEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_HOST_DEVICE_PORT);
218 if (!pData->pDrvHostDevicePort)
219 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Parallel#%d has no parallel port interface above"), pDrvIns->iInstance);
220
221 rc = RTSemEventCreate(&pData->SendSem);
222 AssertRC(rc);
223
224 return VINF_SUCCESS;
225}
226
227
228/**
229 * Destruct a host parallel driver instance.
230 *
231 * Most VM resources are freed by the VM. This callback is provided so that
232 * any non-VM resources can be freed correctly.
233 *
234 * @param pDrvIns The driver instance data.
235 */
236static DECLCALLBACK(void) drvHostParallelDestruct(PPDMDRVINS pDrvIns)
237{
238 PDRVHOSTPARALLEL pData = PDMINS2DATA(pDrvIns, PDRVHOSTPARALLEL);
239
240 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
241
242 pData->fShutdown = true;
243 if (pData->ReceiveThread)
244 {
245 RTThreadWait(pData->ReceiveThread, 1000, NULL);
246 if (pData->ReceiveThread != NIL_RTTHREAD)
247 LogRel(("Parallel%d: receive thread did not terminate\n", pDrvIns->iInstance));
248 }
249
250 RTSemEventSignal(pData->SendSem);
251 RTSemEventDestroy(pData->SendSem);
252 pData->SendSem = NIL_RTSEMEVENT;
253
254 if (pData->SendThread)
255 {
256 RTThreadWait(pData->SendThread, 1000, NULL);
257 if (pData->SendThread != NIL_RTTHREAD)
258 LogRel(("Parallel%d: send thread did not terminate\n", pDrvIns->iInstance));
259 }
260
261 ioctl(pData->FileDevice, PPRELEASE);
262 close(pData->FileDevice);
263}
264
265/**
266 * Char driver registration record.
267 */
268const PDMDRVREG g_DrvHostParallel =
269{
270 /* u32Version */
271 PDM_DRVREG_VERSION,
272 /* szDriverName */
273 "HostParallel",
274 /* pszDescription */
275 "Parallel host driver.",
276 /* fFlags */
277 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
278 /* fClass. */
279 PDM_DRVREG_CLASS_CHAR,
280 /* cMaxInstances */
281 ~0,
282 /* cbInstance */
283 sizeof(DRVHOSTPARALLEL),
284 /* pfnConstruct */
285 drvHostParallelConstruct,
286 /* pfnDestruct */
287 drvHostParallelDestruct,
288 /* pfnIOCtl */
289 NULL,
290 /* pfnPowerOn */
291 NULL,
292 /* pfnReset */
293 NULL,
294 /* pfnSuspend */
295 NULL,
296 /* pfnResume */
297 NULL,
298 /* pfnDetach */
299 NULL,
300 /** pfnPowerOff */
301 NULL
302};
303
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette