VirtualBox

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

Last change on this file since 5999 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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

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