VirtualBox

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

Last change on this file since 45710 was 45061, checked in by vboxsync, 12 years ago

Review of PDM driver destructors making sure that variables they use are correctly initialized in the constructor. Found several RTFileClose(0) cases.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 36.2 KB
Line 
1/* $Id: DrvHostParallel.cpp 45061 2013-03-18 14:09:03Z vboxsync $ */
2/** @file
3 * VirtualBox Host Parallel Port Driver.
4 *
5 * Initial Linux-only code contributed by: Alexander Eichner
6 */
7
8/*
9 * Copyright (C) 2006-2012 Oracle Corporation
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/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmthread.h>
26#include <iprt/asm.h>
27#include <iprt/assert.h>
28#include <iprt/file.h>
29#include <iprt/pipe.h>
30#include <iprt/semaphore.h>
31#include <iprt/stream.h>
32#include <iprt/uuid.h>
33#include <iprt/cdefs.h>
34#include <iprt/ctype.h>
35
36#ifdef RT_OS_LINUX
37# include <sys/ioctl.h>
38# include <sys/types.h>
39# include <sys/stat.h>
40# include <sys/poll.h>
41# include <fcntl.h>
42# include <unistd.h>
43# include <linux/ppdev.h>
44# include <linux/parport.h>
45# include <errno.h>
46#endif
47
48/** @def VBOX_WITH_WIN_PARPORT_SUP *
49 * Indicates whether to use the generic direct hardware access or host specific
50 * code to access the parallel port.
51 */
52#if defined(RT_OS_LINUX)
53# undef VBOX_WITH_WIN_PARPORT_SUP
54#elif defined(RT_OS_WINDOWS)
55#else
56# error "Not ported"
57#endif
58
59#if defined(VBOX_WITH_WIN_PARPORT_SUP) && defined(IN_RING0)
60# include <iprt/asm-amd64-x86.h>
61#endif
62
63#if defined(VBOX_WITH_WIN_PARPORT_SUP) && defined(IN_RING3)
64# include <Windows.h>
65# include <setupapi.h>
66# include <cfgmgr32.h>
67# include <iprt/mem.h>
68# include <iprt/string.h>
69#endif
70
71#include "VBoxDD.h"
72
73
74/*******************************************************************************
75* Structures and Typedefs *
76*******************************************************************************/
77/**
78 * Host parallel port driver instance data.
79 * @implements PDMIHOSTPARALLELCONNECTOR
80 */
81typedef struct DRVHOSTPARALLEL
82{
83 /** Pointer to the driver instance structure. */
84 PPDMDRVINS pDrvIns;
85 /** Pointer to the driver instance. */
86 PPDMDRVINSR3 pDrvInsR3;
87 PPDMDRVINSR0 pDrvInsR0;
88 /** Pointer to the char port interface of the driver/device above us. */
89 PPDMIHOSTPARALLELPORT pDrvHostParallelPort;
90 /** Our host device interface. */
91 PDMIHOSTPARALLELCONNECTOR IHostParallelConnector;
92 /** Our host device interface. */
93 PDMIHOSTPARALLELCONNECTOR IHostParallelConnectorR3;
94 /** Device Path */
95 char *pszDevicePath;
96 /** Device Handle */
97 RTFILE hFileDevice;
98#ifndef VBOX_WITH_WIN_PARPORT_SUP
99 /** Thread waiting for interrupts. */
100 PPDMTHREAD pMonitorThread;
101 /** Wakeup pipe read end. */
102 RTPIPE hWakeupPipeR;
103 /** Wakeup pipe write end. */
104 RTPIPE hWakeupPipeW;
105 /** Current mode the parallel port is in. */
106 PDMPARALLELPORTMODE enmModeCur;
107#endif
108
109#ifdef VBOX_WITH_WIN_PARPORT_SUP
110 /** Data register. */
111 uint32_t u32LptAddr;
112 /** Status register. */
113 uint32_t u32LptAddrStatus;
114 /** Control register. */
115 uint32_t u32LptAddrControl;
116 /** Data read buffer. */
117 uint8_t u8ReadIn;
118 /** Control read buffer. */
119 uint8_t u8ReadInControl;
120 /** Status read buffer. */
121 uint8_t u8ReadInStatus;
122 /** Parallel port name */
123 char szParportName[6];
124 /** Whether the parallel port is available or not. */
125 bool fParportAvail;
126 /** Device Handle */
127 RTFILE hWinFileDevice;
128#endif /* VBOX_WITH_WIN_PARPORT_SUP */
129} DRVHOSTPARALLEL, *PDRVHOSTPARALLEL;
130
131
132/**
133 * Ring-0 operations.
134 */
135typedef enum DRVHOSTPARALLELR0OP
136{
137 /** Invalid zero value. */
138 DRVHOSTPARALLELR0OP_INVALID = 0,
139 /** Perform R0 initialization. */
140 DRVHOSTPARALLELR0OP_INITR0STUFF,
141 /** Read data. */
142 DRVHOSTPARALLELR0OP_READ,
143 /** Read status register. */
144 DRVHOSTPARALLELR0OP_READSTATUS,
145 /** Read control register. */
146 DRVHOSTPARALLELR0OP_READCONTROL,
147 /** Write data. */
148 DRVHOSTPARALLELR0OP_WRITE,
149 /** Write control register. */
150 DRVHOSTPARALLELR0OP_WRITECONTROL,
151 /** Set port direction. */
152 DRVHOSTPARALLELR0OP_SETPORTDIRECTION
153} DRVHOSTPARALLELR0OP;
154
155/** Converts a pointer to DRVHOSTPARALLEL::IHostDeviceConnector to a PDRHOSTPARALLEL. */
156#define PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface) ( (PDRVHOSTPARALLEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector))) )
157
158
159/*******************************************************************************
160* Defined Constants And Macros *
161*******************************************************************************/
162#define CTRL_REG_OFFSET 2
163#define STATUS_REG_OFFSET 1
164#define LPT_CONTROL_ENABLE_BIDIRECT 0x20
165
166
167
168#ifdef VBOX_WITH_WIN_PARPORT_SUP
169# ifdef IN_RING0
170
171/**
172 * R0 mode function to write byte value to data port.
173 * @returns VBox status code.
174 * @param pDrvIns Driver instance.
175 * @param u64Arg Data to be written to data register.
176 *
177 */
178static int drvR0HostParallelReqWrite(PPDMDRVINS pDrvIns, uint64_t u64Arg)
179{
180 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
181 LogFlowFunc(("write to data port=%#x val=%#x\n", pThis->u32LptAddr, u64Arg));
182 ASMOutU8(pThis->u32LptAddr, (uint8_t)(u64Arg));
183 return VINF_SUCCESS;
184}
185
186/**
187 * R0 mode function to write byte value to parallel port control
188 * register.
189 * @returns VBox status code.
190 * @param pDrvIns Driver instance.
191 * @param u64Arg Data to be written to control register.
192 */
193static int drvR0HostParallelReqWriteControl(PPDMDRVINS pDrvIns, uint64_t u64Arg)
194{
195 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
196 LogFlowFunc(("write to ctrl port=%#x val=%#x\n", pThis->u32LptAddrControl, u64Arg));
197 ASMOutU8(pThis->u32LptAddrControl, (uint8_t)(u64Arg));
198 return VINF_SUCCESS;
199}
200
201/**
202 * R0 mode function to ready byte value from the parallel port
203 * data register
204 * @returns VBox status code.
205 * @param pDrvIns Driver instance.
206 * @param u64Arg Not used.
207 */
208static int drvR0HostParallelReqRead(PPDMDRVINS pDrvIns, uint64_t u64Arg)
209{
210 uint8_t u8Data;
211 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
212 u8Data = ASMInU8(pThis->u32LptAddr);
213 LogFlowFunc(("read from data port=%#x val=%#x\n", pThis->u32LptAddr, u8Data));
214 pThis->u8ReadIn = u8Data;
215 return VINF_SUCCESS;
216}
217
218/**
219 * R0 mode function to ready byte value from the parallel port
220 * control register.
221 * @returns VBox status code.
222 * @param pDrvIns Driver instance.
223 * @param u64Arg Not used.
224 */
225static int drvR0HostParallelReqReadControl(PPDMDRVINS pDrvIns, uint64_t u64Arg)
226{
227 uint8_t u8Data;
228 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
229 u8Data = ASMInU8(pThis->u32LptAddrControl);
230 LogFlowFunc(("read from ctrl port=%#x val=%#x\n", pThis->u32LptAddr, u8Data));
231 pThis->u8ReadInControl = u8Data;
232 return VINF_SUCCESS;
233}
234
235/**
236 * R0 mode function to ready byte value from the parallel port
237 * status register.
238 * @returns VBox status code.
239 * @param pDrvIns Driver instance.
240 * @param u64Arg Not used.
241 */
242static int drvR0HostParallelReqReadStatus(PPDMDRVINS pDrvIns, uint64_t u64Arg)
243{
244 uint8_t u8Data;
245 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
246 u8Data = ASMInU8(pThis->u32LptAddrStatus);
247 LogFlowFunc(("read from status port=%#x val=%#x\n", pThis->u32LptAddr, u8Data));
248 pThis->u8ReadInStatus = u8Data;
249 return VINF_SUCCESS;
250}
251
252/**
253 * R0 mode function to set the direction of parallel port -
254 * operate in bidirectional mode or single direction.
255 * @returns VBox status code.
256 * @param pDrvIns Driver instance.
257 * @param u64Arg Mode.
258 */
259static int drvR0HostParallelReqSetPortDir(PPDMDRVINS pDrvIns, uint64_t u64Arg)
260{
261 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
262 uint8_t u8ReadControlVal;
263 uint8_t u8WriteControlVal;
264
265 if (u64Arg)
266 {
267 u8ReadControlVal = ASMInU8(pThis->u32LptAddrControl);
268 u8WriteControlVal = u8ReadControlVal | LPT_CONTROL_ENABLE_BIDIRECT; /* enable input direction */
269 ASMOutU8(pThis->u32LptAddrControl, u8WriteControlVal);
270 }
271 else
272 {
273 u8ReadControlVal = ASMInU8(pThis->u32LptAddrControl);
274 u8WriteControlVal = u8ReadControlVal & ~LPT_CONTROL_ENABLE_BIDIRECT; /* disable input direction */
275 ASMOutU8(pThis->u32LptAddrControl, u8WriteControlVal);
276 }
277 return VINF_SUCCESS;
278}
279
280/**
281 * @interface_method_impl{FNPDMDRVREQHANDLERR0}
282 */
283PDMBOTHCBDECL(int) drvR0HostParallelReqHandler(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
284{
285 int rc;
286
287 LogFlowFuncEnter();
288 /* I have included break after each case. Need to work on this. */
289 switch ((DRVHOSTPARALLELR0OP)uOperation)
290 {
291 case DRVHOSTPARALLELR0OP_READ:
292 rc = drvR0HostParallelReqRead(pDrvIns, u64Arg);
293 break;
294 case DRVHOSTPARALLELR0OP_READSTATUS:
295 rc = drvR0HostParallelReqReadStatus(pDrvIns, u64Arg);
296 break;
297 case DRVHOSTPARALLELR0OP_READCONTROL:
298 rc = drvR0HostParallelReqReadControl(pDrvIns, u64Arg);
299 break;
300 case DRVHOSTPARALLELR0OP_WRITE:
301 rc = drvR0HostParallelReqWrite(pDrvIns, u64Arg);
302 break;
303 case DRVHOSTPARALLELR0OP_WRITECONTROL:
304 rc = drvR0HostParallelReqWriteControl(pDrvIns, u64Arg);
305 break;
306 case DRVHOSTPARALLELR0OP_SETPORTDIRECTION:
307 rc = drvR0HostParallelReqSetPortDir(pDrvIns, u64Arg);
308 break;
309 default: /* not supported */
310 rc = VERR_NOT_SUPPORTED;
311 }
312 LogFlowFuncLeave();
313 return rc;
314}
315
316# endif /* IN_RING0 */
317#endif /* VBOX_WITH_WIN_PARPORT_SUP */
318
319#ifdef IN_RING3
320# ifdef VBOX_WITH_WIN_PARPORT_SUP
321
322/**
323 * Find IO port range for the parallel port and return the lower address.
324 *
325 * @returns parallel port IO address.
326 * @param DevInst Device Instance for parallel port.
327 */
328static uint32_t drvHostWinFindIORangeResource(const DEVINST DevInst)
329{
330 uint8_t *pBuf = NULL;
331 short wHeaderSize;
332 uint32_t u32Size;
333 CONFIGRET cmRet;
334 LOG_CONF firstLogConf;
335 LOG_CONF nextLogConf;
336 RES_DES rdPrevResDes;
337 uint32_t u32ParportAddr = 0;
338
339 wHeaderSize = sizeof(IO_DES);
340 cmRet = CM_Get_First_Log_Conf(&firstLogConf, DevInst, ALLOC_LOG_CONF);
341 if (cmRet != CR_SUCCESS)
342 {
343 cmRet = CM_Get_First_Log_Conf(&firstLogConf, DevInst, BOOT_LOG_CONF);
344 if (cmRet != CR_SUCCESS)
345 return 0;
346 }
347 cmRet = CM_Get_Next_Res_Des(&nextLogConf, firstLogConf, 2, 0L, 0L);
348 if (cmRet != CR_SUCCESS)
349 {
350 CM_Free_Res_Des_Handle(firstLogConf);
351 return 0;
352 }
353 /* This loop is based on the fact that only one resourece is assigned to
354 * the LPT port. If multiple resources (address range) are assigned to
355 * to LPT port, it will pick and return the last one
356 */
357 for (;;)
358 {
359 u32Size = 0;
360 cmRet = CM_Get_Res_Des_Data_Size((PULONG)(&u32Size), nextLogConf, 0L);
361 if (cmRet != CR_SUCCESS)
362 {
363 LogFlowFunc(("Failed to get Size \n"));
364 CM_Free_Res_Des_Handle(nextLogConf);
365 break;
366 }
367
368 pBuf = (uint8_t *)RTMemAlloc(u32Size + 1);
369 if (!pBuf)
370 {
371 LogFlowFunc(("Failed to get Buf %d\n", u32Size));
372 CM_Free_Res_Des_Handle(nextLogConf);
373 break;
374 }
375 cmRet = CM_Get_Res_Des_Data(nextLogConf, pBuf, u32Size, 0L);
376 if (cmRet != CR_SUCCESS)
377 {
378 LogFlowFunc(("Failed to get Des Data \n"));
379 CM_Free_Res_Des_Handle(nextLogConf);
380 if (pBuf)
381 RTMemFree(pBuf);
382 break;
383 }
384
385 LogFlowFunc(("call GetIOResource\n"));
386 if (pBuf)
387 u32ParportAddr = ((IO_DES *)pBuf)->IOD_Alloc_Base;
388 LogFlowFunc(("called GetIOResource, ret=%#x\n", u32ParportAddr));
389 rdPrevResDes = 0;
390 cmRet = CM_Get_Next_Res_Des(&rdPrevResDes,
391 nextLogConf,
392 2,
393 0L,
394 0L);
395 if (pBuf)
396 RTMemFree(pBuf);
397 if (cmRet != CR_SUCCESS)
398 break;
399
400 CM_Free_Res_Des_Handle(nextLogConf);
401 nextLogConf = rdPrevResDes;
402 }
403 CM_Free_Res_Des_Handle(nextLogConf);
404 LogFlowFunc(("return u32ParportAddr=%#x", u32ParportAddr));
405 return u32ParportAddr;
406}
407
408/**
409 * Get Parallel port address and update the shared data
410 * structure.
411 * @returns VBox status code.
412 * @param pThis The host parallel port instance data.
413 */
414static int drvWinHostGetparportAddr(PDRVHOSTPARALLEL pThis)
415{
416 HDEVINFO hDevInfo;
417 SP_DEVINFO_DATA DeviceInfoData;
418 uint32_t u32Idx;
419 uint32_t u32ParportAddr;
420 int rc = VINF_SUCCESS;
421
422 hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES);
423 if (hDevInfo == INVALID_HANDLE_VALUE)
424 return VERR_INVALID_HANDLE;
425
426 /* Enumerate through all devices in Set. */
427 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
428 for (u32Idx = 0; SetupDiEnumDeviceInfo(hDevInfo, u32Idx, &DeviceInfoData); u32Idx++)
429 {
430 DWORD dwDataType;
431 uint8_t *pBuf = NULL;
432 DWORD dwBufSize = 0;
433
434 while (!SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME,
435 (PDWORD)&dwDataType, (uint8_t *)pBuf,
436 dwBufSize, (PDWORD)&dwBufSize))
437 {
438 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
439 {
440 LogFlow(("ERROR_INSUFF_BUFF = %d. dwBufSz = %d\n", GetLastError(), dwBufSize));
441 if (pBuf)
442 RTMemFree(pBuf);
443 pBuf = (uint8_t *)RTMemAlloc(dwBufSize * 2);
444 }
445 else
446 {
447 /* No need to bother about this error (in most cases its errno=13,
448 * INVALID_DATA . Just break from here and proceed to next device
449 * enumerated item
450 */
451 LogFlow(("GetDevProp Error = %d & dwBufSz = %d\n", GetLastError(), dwBufSize));
452 break;
453 }
454 }
455
456 if (RTStrStr((char*)pBuf, "LPT"))
457 {
458 u32ParportAddr = drvHostWinFindIORangeResource(DeviceInfoData.DevInst);
459 if (u32ParportAddr)
460 {
461 /* Find parallel port name and update the shared data struncture */
462 char *pCh = RTStrStr((char*)pBuf, "(");
463 char *pTmpCh = RTStrStr((char *)pBuf, ")");
464 /* check for the confirmation for the availability of parallel port */
465 if (!(pCh && pTmpCh))
466 {
467 LogFlowFunc(("Parallel port Not Found. \n"));
468 return VERR_NOT_FOUND;
469
470 }
471 if (((pTmpCh - (char *)pBuf) - (pCh - (char *)pBuf)) < 0) {
472 LogFlowFunc(("Parallel port string not properly formatted.\n"));
473 return VERR_NOT_FOUND;
474 }
475 /* check for the confirmation for the availability of parallel port */
476 if (RTStrCopyEx((char *)(pThis->szParportName), sizeof(pThis->szParportName),
477 pCh+1, ((pTmpCh - (char *)pBuf) - (pCh - (char *)pBuf)) - 1))
478 {
479 LogFlowFunc(("Parallel Port Not Found.\n"));
480 return VERR_NOT_FOUND;
481 }
482 *((char *)pThis->szParportName + (pTmpCh - (char *)pBuf) - (pCh - (char *)pBuf) + 1 ) = '\0';
483
484 /* checking again to make sure that we have got a valid name and in valid format too. */
485 if (RTStrNCmp((char *)pThis->szParportName, "LPT", 3)) {
486 LogFlowFunc(("Parallel Port name \"LPT\" Not Found.\n"));
487 return VERR_NOT_FOUND;
488 }
489 if (!RTStrStr((char *)pThis->szParportName, "LPT")
490 || !(pThis->szParportName[3] >= '0'
491 && pThis->szParportName[3] <= '9'))
492 {
493 RT_BZERO(pThis->szParportName, sizeof(pThis->szParportName));
494 LogFlowFunc(("Printer Port Name Not Found.\n"));
495 return VERR_NOT_FOUND;
496 }
497 pThis->fParportAvail = true;
498 pThis->u32LptAddr = u32ParportAddr;
499 pThis->u32LptAddrControl = pThis->u32LptAddr + CTRL_REG_OFFSET;
500 pThis->u32LptAddrStatus = pThis->u32LptAddr + STATUS_REG_OFFSET;
501 }
502 else
503 LogFlowFunc(("u32Parport Addr No Available \n"));
504 if (pThis->fParportAvail)
505 break;
506 }
507 if (pBuf)
508 RTMemFree(pBuf);
509 if (pThis->fParportAvail)
510 {
511 /* Parallel port address has been found. No need to iterate further. */
512 break;
513 }
514 }
515
516 if (GetLastError() != NO_ERROR && GetLastError() != ERROR_NO_MORE_ITEMS)
517 rc = VERR_GENERAL_FAILURE;
518
519 SetupDiDestroyDeviceInfoList(hDevInfo);
520 return rc;
521
522}
523# endif /* VBOX_WITH_WIN_PARPORT_SUP */
524
525/**
526 * Changes the current mode of the host parallel port.
527 *
528 * @returns VBox status code.
529 * @param pThis The host parallel port instance data.
530 * @param enmMode The mode to change the port to.
531 */
532static int drvHostParallelSetMode(PDRVHOSTPARALLEL pThis, PDMPARALLELPORTMODE enmMode)
533{
534 int iMode = 0;
535 int rc = VINF_SUCCESS;
536 LogFlowFunc(("mode=%d\n", enmMode));
537
538# ifndef VBOX_WITH_WIN_PARPORT_SUP
539 int rcLnx;
540 if (pThis->enmModeCur != enmMode)
541 {
542 switch (enmMode)
543 {
544 case PDM_PARALLEL_PORT_MODE_SPP:
545 iMode = IEEE1284_MODE_COMPAT;
546 break;
547 case PDM_PARALLEL_PORT_MODE_EPP_DATA:
548 iMode = IEEE1284_MODE_EPP | IEEE1284_DATA;
549 break;
550 case PDM_PARALLEL_PORT_MODE_EPP_ADDR:
551 iMode = IEEE1284_MODE_EPP | IEEE1284_ADDR;
552 break;
553 case PDM_PARALLEL_PORT_MODE_ECP:
554 case PDM_PARALLEL_PORT_MODE_INVALID:
555 default:
556 return VERR_NOT_SUPPORTED;
557 }
558
559 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPSETMODE, &iMode);
560 if (RT_UNLIKELY(rcLnx < 0))
561 rc = RTErrConvertFromErrno(errno);
562 else
563 pThis->enmModeCur = enmMode;
564 }
565
566 return rc;
567# else /* VBOX_WITH_WIN_PARPORT_SUP */
568 return VINF_SUCCESS;
569# endif /* VBOX_WITH_WIN_PARPORT_SUP */
570}
571
572/* -=-=-=-=- IBase -=-=-=-=- */
573
574/**
575 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
576 */
577static DECLCALLBACK(void *) drvHostParallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
578{
579 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
580 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
581
582 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
583 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELCONNECTOR, &pThis->CTX_SUFF(IHostParallelConnector));
584 return NULL;
585}
586
587
588/* -=-=-=-=- IHostDeviceConnector -=-=-=-=- */
589
590/** @copydoc PDMICHARCONNECTOR::pfnWrite */
591static DECLCALLBACK(int) drvHostParallelWrite(PPDMIHOSTPARALLELCONNECTOR pInterface, const void *pvBuf, size_t cbWrite, PDMPARALLELPORTMODE enmMode)
592{
593 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
594 //PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
595 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
596 int rc = VINF_SUCCESS;
597 int rcLnx = 0;
598
599 LogFlowFunc(("pvBuf=%#p cbWrite=%d\n", pvBuf, cbWrite));
600
601 rc = drvHostParallelSetMode(pThis, enmMode);
602 if (RT_FAILURE(rc))
603 return rc;
604# ifndef VBOX_WITH_WIN_PARPORT_SUP
605 if (enmMode == PDM_PARALLEL_PORT_MODE_SPP)
606 {
607 /* Set the data lines directly. */
608 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPWDATA, pvBuf);
609 }
610 else
611 {
612 /* Use write interface. */
613 rcLnx = write(RTFileToNative(pThis->hFileDevice), pvBuf, cbWrite);
614 }
615 if (RT_UNLIKELY(rcLnx < 0))
616 rc = RTErrConvertFromErrno(errno);
617# else /* VBOX_WITH_WIN_PARPORT_SUP */
618 if (pThis->fParportAvail)
619 {
620 for (size_t i = 0; i < cbWrite; i++)
621 {
622 uint64_t u64Data = (uint8_t) *((uint8_t *)(pvBuf) + i);
623 LogFlowFunc(("calling R0 to write to parallel port, data=%#x\n", u64Data));
624 rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_WRITE, u64Data);
625 AssertRC(rc);
626 }
627 }
628# endif /* VBOX_WITH_WIN_PARPORT_SUP */
629 return rc;
630}
631
632/**
633 * @interface_method_impl{PDMIBASE,pfnRead}
634 */
635static DECLCALLBACK(int) drvHostParallelRead(PPDMIHOSTPARALLELCONNECTOR pInterface, void *pvBuf, size_t cbRead, PDMPARALLELPORTMODE enmMode)
636{
637 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
638 int rc = VINF_SUCCESS;
639
640# ifndef VBOX_WITH_WIN_PARPORT_SUP
641 int rcLnx = 0;
642 LogFlowFunc(("pvBuf=%#p cbRead=%d\n", pvBuf, cbRead));
643
644 rc = drvHostParallelSetMode(pThis, enmMode);
645 if (RT_FAILURE(rc))
646 return rc;
647
648 if (enmMode == PDM_PARALLEL_PORT_MODE_SPP)
649 {
650 /* Set the data lines directly. */
651 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPWDATA, pvBuf);
652 }
653 else
654 {
655 /* Use write interface. */
656 rcLnx = read(RTFileToNative(pThis->hFileDevice), pvBuf, cbRead);
657 }
658 if (RT_UNLIKELY(rcLnx < 0))
659 rc = RTErrConvertFromErrno(errno);
660# else /* VBOX_WITH_WIN_PARPORT_SUP */
661 if (pThis->fParportAvail)
662 {
663 *((uint8_t*)(pvBuf)) = 0; /* Initialize the buffer. */
664 for (size_t i = 0; i < cbRead; i++)
665 {
666 LogFlowFunc(("calling R0 to read from parallel port\n"));
667 int rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_READ, 0);
668 AssertRC(rc);
669 *((uint8_t *)pvBuf + i) = (uint8_t)pThis->u8ReadIn;
670 }
671 }
672# endif /* VBOX_WITH_WIN_PARPORT_SUP */
673 return rc;
674}
675
676static DECLCALLBACK(int) drvHostParallelSetPortDirection(PPDMIHOSTPARALLELCONNECTOR pInterface, bool fForward)
677{
678 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
679 int rc = VINF_SUCCESS;
680 int iMode = 0;
681 if (!fForward)
682 iMode = 1;
683# ifndef VBOX_WITH_WIN_PARPORT_SUP
684 int rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPDATADIR, &iMode);
685 if (RT_UNLIKELY(rcLnx < 0))
686 rc = RTErrConvertFromErrno(errno);
687
688# else /* VBOX_WITH_WIN_PARPORT_SUP */
689 uint64_t u64Data;
690 u64Data = (uint8_t)iMode;
691 if (pThis->fParportAvail)
692 {
693 LogFlowFunc(("calling R0 to write CTRL, data=%#x\n", u64Data));
694 rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_SETPORTDIRECTION, u64Data);
695 AssertRC(rc);
696 }
697# endif /* VBOX_WITH_WIN_PARPORT_SUP */
698 return rc;
699}
700
701/**
702 * @interface_method_impl{PDMIBASE,pfnWriteControl}
703 */
704static DECLCALLBACK(int) drvHostParallelWriteControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg)
705{
706 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
707 int rc = VINF_SUCCESS;
708 int rcLnx = 0;
709
710 LogFlowFunc(("fReg=%#x\n", fReg));
711# ifndef VBOX_WITH_WIN_PARPORT_SUP
712 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPWCONTROL, &fReg);
713 if (RT_UNLIKELY(rcLnx < 0))
714 rc = RTErrConvertFromErrno(errno);
715# else /* VBOX_WITH_WIN_PARPORT_SUP */
716 uint64_t u64Data;
717 u64Data = (uint8_t)fReg;
718 if (pThis->fParportAvail)
719 {
720 LogFlowFunc(("calling R0 to write CTRL, data=%#x\n", u64Data));
721 rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_WRITECONTROL, u64Data);
722 AssertRC(rc);
723 }
724# endif /* VBOX_WITH_WIN_PARPORT_SUP */
725 return rc;
726}
727
728
729/**
730 * @interface_method_impl{PDMIBASE,pfnReadControl}
731 */
732static DECLCALLBACK(int) drvHostParallelReadControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)
733{
734 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
735 int rc = VINF_SUCCESS;
736 int rcLnx = 0;
737 uint8_t fReg = 0;
738
739# ifndef VBOX_WITH_WIN_PARPORT_SUP
740 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPRCONTROL, &fReg);
741 if (RT_UNLIKELY(rcLnx < 0))
742 rc = RTErrConvertFromErrno(errno);
743 else
744 {
745 LogFlowFunc(("fReg=%#x\n", fReg));
746 *pfReg = fReg;
747 }
748# else /* VBOX_WITH_WIN_PARPORT_SUP */
749 *pfReg = 0; /* Initialize the buffer*/
750 if (pThis->fParportAvail)
751 {
752 LogFlowFunc(("calling R0 to read control from parallel port\n"));
753 rc = PDMDrvHlpCallR0(pThis-> CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_READCONTROL, 0);
754 AssertRC(rc);
755 *pfReg = pThis->u8ReadInControl;
756 }
757# endif /* VBOX_WITH_WIN_PARPORT_SUP */
758 return rc;
759}
760
761/**
762 * @interface_method_impl{PDMIBASE,pfnReadStatus}
763 */
764static DECLCALLBACK(int) drvHostParallelReadStatus(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)
765{
766 PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector));
767 int rc = VINF_SUCCESS;
768 int rcLnx = 0;
769 uint8_t fReg = 0;
770# ifndef VBOX_WITH_WIN_PARPORT_SUP
771 rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPRSTATUS, &fReg);
772 if (RT_UNLIKELY(rcLnx < 0))
773 rc = RTErrConvertFromErrno(errno);
774 else
775 {
776 LogFlowFunc(("fReg=%#x\n", fReg));
777 *pfReg = fReg;
778 }
779# else /* VBOX_WITH_WIN_PARPORT_SUP */
780 *pfReg = 0; /* Intialize the buffer. */
781 if (pThis->fParportAvail)
782 {
783 LogFlowFunc(("calling R0 to read status from parallel port\n"));
784 rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_READSTATUS, 0);
785 AssertRC(rc);
786 *pfReg = pThis->u8ReadInStatus;
787 }
788# endif /* VBOX_WITH_WIN_PARPORT_SUP */
789 return rc;
790}
791
792# ifndef VBOX_WITH_WIN_PARPORT_SUP
793
794static DECLCALLBACK(int) drvHostParallelMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
795{
796 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
797 struct pollfd aFDs[2];
798
799 /*
800 * We can wait for interrupts using poll on linux hosts.
801 */
802 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
803 {
804 int rc;
805
806 aFDs[0].fd = RTFileToNative(pThis->hFileDevice);
807 aFDs[0].events = POLLIN;
808 aFDs[0].revents = 0;
809 aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR);
810 aFDs[1].events = POLLIN | POLLERR | POLLHUP;
811 aFDs[1].revents = 0;
812 rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
813 if (rc < 0)
814 {
815 AssertMsgFailed(("poll failed with rc=%d\n", RTErrConvertFromErrno(errno)));
816 return RTErrConvertFromErrno(errno);
817 }
818
819 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
820 break;
821 if (rc > 0 && aFDs[1].revents)
822 {
823 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
824 break;
825 /* notification to terminate -- drain the pipe */
826 char ch;
827 size_t cbRead;
828 RTPipeRead(pThis->hWakeupPipeR, &ch, 1, &cbRead);
829 continue;
830 }
831
832 /* Interrupt occurred. */
833 rc = pThis->pDrvHostParallelPort->pfnNotifyInterrupt(pThis->pDrvHostParallelPort);
834 AssertRC(rc);
835 }
836
837 return VINF_SUCCESS;
838}
839
840/**
841 * Unblock the monitor thread so it can respond to a state change.
842 *
843 * @returns a VBox status code.
844 * @param pDrvIns The driver instance.
845 * @param pThread The send thread.
846 */
847static DECLCALLBACK(int) drvHostParallelWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
848{
849 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
850 size_t cbIgnored;
851 return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored);
852}
853
854# endif /* VBOX_WITH_WIN_PARPORT_SUP */
855
856/**
857 * Destruct a host parallel driver instance.
858 *
859 * Most VM resources are freed by the VM. This callback is provided so that
860 * any non-VM resources can be freed correctly.
861 *
862 * @param pDrvIns The driver instance data.
863 */
864static DECLCALLBACK(void) drvHostParallelDestruct(PPDMDRVINS pDrvIns)
865{
866 int rc;
867 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
868 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
869 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
870
871#ifndef VBOX_WITH_WIN_PARPORT_SUP
872 if (pThis->hFileDevice != NIL_RTFILE)
873 ioctl(RTFileToNative(pThis->hFileDevice), PPRELEASE);
874
875 if (pThis->hWakeupPipeW != NIL_RTPIPE)
876 {
877 rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc);
878 pThis->hWakeupPipeW = NIL_RTPIPE;
879 }
880
881 if (pThis->hWakeupPipeR != NIL_RTPIPE)
882 {
883 rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc);
884 pThis->hWakeupPipeR = NIL_RTPIPE;
885 }
886
887 if (pThis->hFileDevice != NIL_RTFILE)
888 {
889 rc = RTFileClose(pThis->hFileDevice); AssertRC(rc);
890 pThis->hFileDevice = NIL_RTFILE;
891 }
892
893 if (pThis->pszDevicePath)
894 {
895 MMR3HeapFree(pThis->pszDevicePath);
896 pThis->pszDevicePath = NULL;
897 }
898#else /* VBOX_WITH_WIN_PARPORT_SUP */
899 if (pThis->hWinFileDevice != NIL_RTFILE)
900 {
901 rc = RTFileClose(pThis->hWinFileDevice); AssertRC(rc);
902 pThis->hWinFileDevice = NIL_RTFILE;
903 }
904#endif /* VBOX_WITH_WIN_PARPORT_SUP */
905}
906
907/**
908 * Construct a host parallel driver instance.
909 *
910 * @copydoc FNPDMDRVCONSTRUCT
911 */
912static DECLCALLBACK(int) drvHostParallelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
913{
914 PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
915 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
916
917 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
918
919 /*
920 * Init basic data members and interfaces.
921 *
922 * Must be done before returning any failure because we've got a destructor.
923 */
924 pThis->hFileDevice = NIL_RTFILE;
925#ifndef VBOX_WITH_WIN_PARPORT_SUP
926 pThis->hWakeupPipeR = NIL_RTPIPE;
927 pThis->hWakeupPipeW = NIL_RTPIPE;
928#else
929 pThis->hWinFileDevice = NIL_RTFILE;
930#endif
931
932 pThis->pDrvInsR3 = pDrvIns;
933#ifdef VBOX_WITH_DRVINTNET_IN_R0
934 pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
935#endif
936
937 /* IBase. */
938 pDrvIns->IBase.pfnQueryInterface = drvHostParallelQueryInterface;
939 /* IHostParallelConnector. */
940 pThis->IHostParallelConnectorR3.pfnWrite = drvHostParallelWrite;
941 pThis->IHostParallelConnectorR3.pfnRead = drvHostParallelRead;
942 pThis->IHostParallelConnectorR3.pfnSetPortDirection = drvHostParallelSetPortDirection;
943 pThis->IHostParallelConnectorR3.pfnWriteControl = drvHostParallelWriteControl;
944 pThis->IHostParallelConnectorR3.pfnReadControl = drvHostParallelReadControl;
945 pThis->IHostParallelConnectorR3.pfnReadStatus = drvHostParallelReadStatus;
946
947 /*
948 * Validate the config.
949 */
950 if (!CFGMR3AreValuesValid(pCfg, "DevicePath\0"))
951 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
952 N_("Unknown host parallel configuration option, only supports DevicePath"));
953
954 /*
955 * Query configuration.
956 */
957 /* Device */
958 int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
959 if (RT_FAILURE(rc))
960 {
961 AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
962 return rc;
963 }
964
965 /*
966 * Open the device
967 */
968 rc = RTFileOpen(&pThis->hFileDevice, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
969 if (RT_FAILURE(rc))
970 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Parallel#%d could not open '%s'"),
971 pDrvIns->iInstance, pThis->pszDevicePath);
972
973#ifndef VBOX_WITH_WIN_PARPORT_SUP
974 /*
975 * Try to get exclusive access to parallel port
976 */
977 rc = ioctl(RTFileToNative(pThis->hFileDevice), PPEXCL);
978 if (rc < 0)
979 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
980 N_("Parallel#%d could not get exclusive access for parallel port '%s'"
981 "Be sure that no other process or driver accesses this port"),
982 pDrvIns->iInstance, pThis->pszDevicePath);
983
984 /*
985 * Claim the parallel port
986 */
987 rc = ioctl(RTFileToNative(pThis->hFileDevice), PPCLAIM);
988 if (rc < 0)
989 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
990 N_("Parallel#%d could not claim parallel port '%s'"
991 "Be sure that no other process or driver accesses this port"),
992 pDrvIns->iInstance, pThis->pszDevicePath);
993
994 /*
995 * Get the IHostParallelPort interface of the above driver/device.
996 */
997 pThis->pDrvHostParallelPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTPARALLELPORT);
998 if (!pThis->pDrvHostParallelPort)
999 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Parallel#%d has no parallel port interface above"),
1000 pDrvIns->iInstance);
1001
1002 /*
1003 * Create wakeup pipe.
1004 */
1005 rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);
1006 AssertRCReturn(rc, rc);
1007
1008 /*
1009 * Start in SPP mode.
1010 */
1011 pThis->enmModeCur = PDM_PARALLEL_PORT_MODE_INVALID;
1012 rc = drvHostParallelSetMode(pThis, PDM_PARALLEL_PORT_MODE_SPP);
1013 if (RT_FAILURE(rc))
1014 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot change mode of parallel mode to SPP"), pDrvIns->iInstance);
1015
1016 /*
1017 * Start waiting for interrupts.
1018 */
1019 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostParallelMonitorThread, drvHostParallelWakeupMonitorThread, 0,
1020 RTTHREADTYPE_IO, "ParMon");
1021 if (RT_FAILURE(rc))
1022 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot create monitor thread"), pDrvIns->iInstance);
1023
1024#else /* VBOX_WITH_WIN_PARPORT_SUP */
1025 HANDLE hPort;
1026 pThis->fParportAvail = false;
1027 pThis->u32LptAddr = 0;
1028 pThis->u32LptAddrControl = 0;
1029 pThis->u32LptAddrStatus = 0;
1030 rc = drvWinHostGetparportAddr(pThis);
1031
1032 /* If we have the char port availabe use it , else I am not getting exclusive access to parallel port.
1033 Read and write will be done only if addresses are available
1034 */
1035 if (pThis->szParportName)
1036 {
1037 rc = RTFileOpen(&pThis->hWinFileDevice, (char *)pThis->szParportName,
1038 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1039 }
1040#endif
1041 return VINF_SUCCESS;
1042}
1043
1044
1045/**
1046 * Char driver registration record.
1047 */
1048const PDMDRVREG g_DrvHostParallel =
1049{
1050 /* u32Version */
1051 PDM_DRVREG_VERSION,
1052 /* szName */
1053 "HostParallel",
1054 /* szRCMod */
1055 "",
1056 /* szR0Mod */
1057 "VBoxDDR0.r0",
1058 /* pszDescription */
1059 "Parallel host driver.",
1060 /* fFlags */
1061# if defined(VBOX_WITH_WIN_PARPORT_SUP)
1062 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
1063# else
1064 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1065# endif
1066 /* fClass. */
1067 PDM_DRVREG_CLASS_CHAR,
1068 /* cMaxInstances */
1069 ~0U,
1070 /* cbInstance */
1071 sizeof(DRVHOSTPARALLEL),
1072 /* pfnConstruct */
1073 drvHostParallelConstruct,
1074 /* pfnDestruct */
1075 drvHostParallelDestruct,
1076 /* pfnRelocate */
1077 NULL,
1078 /* pfnIOCtl */
1079 NULL,
1080 /* pfnPowerOn */
1081 NULL,
1082 /* pfnReset */
1083 NULL,
1084 /* pfnSuspend */
1085 NULL,
1086 /* pfnResume */
1087 NULL,
1088 /* pfnAttach */
1089 NULL,
1090 /* pfnDetach */
1091 NULL,
1092 /* pfnPowerOff */
1093 NULL,
1094 /* pfnSoftReset */
1095 NULL,
1096 /* u32EndVersion */
1097 PDM_DRVREG_VERSION
1098};
1099#endif /*IN_RING3*/
1100
1101
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