예제 #1
0
/**
 * Send an SCSI INQUIRY command to a device and return selected information.
 * @returns  iprt status code
 * @returns  VERR_TRY_AGAIN if the query failed but might succeed next time
 * @param pcszNode    the full path to the device node
 * @param pu8Type    where to store the SCSI device type on success (optional)
 * @param pchVendor  where to store the vendor id string on success (optional)
 * @param cchVendor  the size of the @a pchVendor buffer
 * @param pchModel   where to store the product id string on success (optional)
 * @param cchModel   the size of the @a pchModel buffer
 * @note check documentation on the SCSI INQUIRY command and the Linux kernel
 *       SCSI headers included above if you want to understand what is going
 *       on in this method.
 */
static int cdromDoInquiry(const char *pcszNode, uint8_t *pu8Type,
                          char *pchVendor, size_t cchVendor, char *pchModel,
                          size_t cchModel)
{
    LogRelFlowFunc(("pcszNode=%s, pu8Type=%p, pchVendor=%p, cchVendor=%llu, pchModel=%p, cchModel=%llu\n",
                    pcszNode, pu8Type, pchVendor, cchVendor, pchModel,
                    cchModel));
    AssertPtrReturn(pcszNode, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pu8Type, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pchVendor, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pchModel, VERR_INVALID_POINTER);

    RTFILE hFile;
    int rc = RTFileOpen(&hFile, pcszNode, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK);
    if (RT_SUCCESS(rc))
    {
        int                             rcIoCtl        = 0;
        unsigned char                   u8Response[96] = { 0 };
        struct cdrom_generic_command    CdromCommandReq;
        RT_ZERO(CdromCommandReq);
        CdromCommandReq.cmd[0]         = INQUIRY;
        CdromCommandReq.cmd[4]         = sizeof(u8Response);
        CdromCommandReq.buffer         = u8Response;
        CdromCommandReq.buflen         = sizeof(u8Response);
        CdromCommandReq.data_direction = CGC_DATA_READ;
        CdromCommandReq.timeout        = 5000;  /* ms */
        rc = RTFileIoCtl(hFile, CDROM_SEND_PACKET, &CdromCommandReq, 0, &rcIoCtl);
        if (RT_SUCCESS(rc) && rcIoCtl < 0)
            rc = RTErrConvertFromErrno(-CdromCommandReq.stat);
        RTFileClose(hFile);

        if (RT_SUCCESS(rc))
        {
            if (pu8Type)
                *pu8Type = u8Response[0] & 0x1f;
            if (pchVendor)
                RTStrPrintf(pchVendor, cchVendor, "%.8s",
                            &u8Response[8] /* vendor id string */);
            if (pchModel)
                RTStrPrintf(pchModel, cchModel, "%.16s",
                            &u8Response[16] /* product id string */);
            LogRelFlowFunc(("returning success: type=%u, vendor=%.8s, product=%.16s\n",
                            u8Response[0] & 0x1f, &u8Response[8], &u8Response[16]));
            return VINF_SUCCESS;
        }
    }
    LogRelFlowFunc(("returning %Rrc\n", rc));
    return rc;
}
예제 #2
0
/**
 * Get the name of a floppy drive according to the Linux floppy driver.
 * @returns true on success, false if the name was not available (i.e. the
 *          device was not readable, or the file name wasn't a PC floppy
 *          device)
 * @param  pcszNode  the path to the device node for the device
 * @param  Number    the Linux floppy driver number for the drive.  Required.
 * @param  pszName   where to store the name retrieved
 */
static bool floppyGetName(const char *pcszNode, unsigned Number,
                          floppy_drive_name pszName)
{
    AssertPtrReturn(pcszNode, false);
    AssertPtrReturn(pszName, false);
    AssertReturn(Number <= 7, false);
    RTFILE File;
    int rc = RTFileOpen(&File, pcszNode, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK);
    if (RT_SUCCESS(rc))
    {
        int rcIoCtl;
        rc = RTFileIoCtl(File, FDGETDRVTYP, pszName, 0, &rcIoCtl);
        RTFileClose(File);
        if (RT_SUCCESS(rc) && rcIoCtl >= 0)
            return true;
    }
    return false;
}
/**
 * The client driver IOCtl Wrapper function.
 *
 * @returns VBox status code.
 * @param   pDevSol         The Solaris device instance.
 * @param   Function        The Function.
 * @param   pvData          Opaque pointer to the data.
 * @param   cbData          Size of the data pointed to by pvData.
 */
static int usbProxySolarisIOCtl(PUSBPROXYDEVSOL pDevSol, unsigned Function, void *pvData, size_t cbData)
{
    if (RT_UNLIKELY(pDevSol->hFile == NIL_RTFILE))
    {
        LogFlow((USBPROXY ":usbProxySolarisIOCtl connection to driver gone!\n"));
        return VERR_VUSB_DEVICE_NOT_ATTACHED;
    }

    VBOXUSBREQ Req;
    Req.u32Magic = VBOXUSB_MAGIC;
    Req.rc = -1;
    Req.cbData = cbData;
    Req.pvDataR3 = pvData;

    int Ret = -1;
    int rc = RTFileIoCtl(pDevSol->hFile, Function, &Req, sizeof(Req), &Ret);
    if (RT_SUCCESS(rc))
    {
        if (RT_FAILURE(Req.rc))
        {
            if (Req.rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
            {
                pDevSol->pProxyDev->fDetached = true;
                usbProxySolarisCloseFile(pDevSol);
                LogRel((USBPROXY ":Command %#x failed, USB Device '%s' disconnected!\n", Function, pDevSol->pProxyDev->pUsbIns->pszName));
            }
            else
                LogRel((USBPROXY ":Command %#x failed. Req.rc=%Rrc\n", Function, Req.rc));
        }

        return Req.rc;
    }

    LogRel((USBPROXY ":Function %#x failed. rc=%Rrc\n", Function, rc));
    return rc;
}
/**
 * Internal wrapper around various OS specific ioctl implementations.
 *
 * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or
 *          an failure returned by the OS specific ioctl APIs.
 *
 * @param   iFunction   The requested function.
 * @param   pvData      The input and output data buffer.
 * @param   cbData      The size of the buffer.
 *
 * @remark  Exactly how the VBoxGuestCommonIOCtl is ferried back
 *          here is OS specific. On BSD and Darwin we can use errno,
 *          while on OS/2 we use the 2nd buffer of the IOCtl.
 */
int vbglR3DoIOCtl(unsigned iFunction, void *pvData, size_t cbData)
{
#if defined(RT_OS_WINDOWS)
    DWORD cbReturned = 0;
    if (!DeviceIoControl(g_hFile, iFunction, pvData, (DWORD)cbData, pvData, (DWORD)cbData, &cbReturned, NULL))
    {
/** @todo The passing of error codes needs to be tested and fixed (as does *all* the other hosts except for
 * OS/2).  The idea is that the VBox status codes in ring-0 should be transferred without loss down to
 * ring-3. However, it's not vitally important right now (obviously, since the other guys has been
 * ignoring it for 1+ years now).  On Linux and Solaris the transfer is done, but it is currently not
 * lossless, so still needs fixing. */
        DWORD LastErr = GetLastError();
        return RTErrConvertFromWin32(LastErr);
    }

    return VINF_SUCCESS;

#elif defined(RT_OS_OS2)
    ULONG cbOS2Parm = cbData;
    int32_t vrc = VERR_INTERNAL_ERROR;
    ULONG cbOS2Data = sizeof(vrc);
    APIRET rc = DosDevIOCtl((uintptr_t)g_File, VBOXGUEST_IOCTL_CATEGORY, iFunction,
                            pvData, cbData, &cbOS2Parm,
                            &vrc, sizeof(vrc), &cbOS2Data);
    if (RT_LIKELY(!rc))
        return vrc;
    return RTErrConvertFromOS2(rc);

#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    VBGLBIGREQ Hdr;
    Hdr.u32Magic = VBGLBIGREQ_MAGIC;
    Hdr.cbData = cbData;
    Hdr.pvDataR3 = pvData;
# if HC_ARCH_BITS == 32
    Hdr.u32Padding = 0;
# endif

/** @todo test status code passing! Check that the kernel doesn't do any
 *        error checks using specific errno values, and just pass an VBox
 *        error instead of an errno.h one. Alternatively, extend/redefine the
 *        header with an error code return field (much better alternative
 *        actually). */
#ifdef VBOX_VBGLR3_XFREE86
    int rc = xf86ioctl(g_File, iFunction, &Hdr);
#else
    int rc = ioctl(RTFileToNative(g_File), iFunction, &Hdr);
#endif
    if (rc == -1)
    {
        rc = errno;
        return RTErrConvertFromErrno(rc);
    }
    return VINF_SUCCESS;

#elif defined(RT_OS_LINUX)
# ifdef VBOX_VBGLR3_XFREE86
    int rc = xf86ioctl((int)g_File, iFunction, pvData);
# else
    if (g_File == NIL_RTFILE)
        return VERR_INVALID_HANDLE;
    int rc = ioctl(RTFileToNative(g_File), iFunction, pvData);
# endif
    if (RT_LIKELY(rc == 0))
        return VINF_SUCCESS;

    /* Positive values are negated VBox error status codes. */
    if (rc > 0)
        rc = -rc;
    else
# ifdef VBOX_VBGLR3_XFREE86
        rc = VERR_FILE_IO_ERROR;
#  else
        rc = RTErrConvertFromErrno(errno);
# endif
    NOREF(cbData);
    return rc;

#elif defined(VBOX_VBGLR3_XFREE86)
    /* PORTME - This is preferred over the RTFileIOCtl variant below, just be careful with the (int). */
/** @todo test status code passing! */
    int rc = xf86ioctl(g_File, iFunction, pvData);
    if (rc == -1)
        return VERR_FILE_IO_ERROR;  /* This is purely legacy stuff, it has to work and no more. */
    return VINF_SUCCESS;

#else
    /* Default implementation - PORTME: Do not use this without testings that passing errors works! */
/** @todo test status code passing! */
    int rc2 = VERR_INTERNAL_ERROR;
    int rc = RTFileIoCtl(g_File, (int)iFunction, pvData, cbData, &rc2);
    if (RT_SUCCESS(rc))
        rc = rc2;
    return rc;
#endif
}
예제 #5
0
int main()
{
#ifdef RT_OS_L4
    __environ = myenv;
#endif
    int         rcRet = 0;
    int ret, err;
    printf("tstIoCtl: TESTING\n");

    RTFILE    File;

    err = RTFileOpen(&File, "/dev/dsp", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK);
    if (RT_FAILURE(err)) {
        printf("Fatal error: failed to open /dev/dsp:\n"
               "VBox error code: %d\n", err);
        return 1;
    }

    int rate = 100;

    if (RT_FAILURE(err = RTFileIoCtl(File, SNDCTL_DSP_SPEED, &rate, sizeof(rate), &ret)) || ret) {
        printf("Failed to set playback speed on /dev/dsp\n"
               "VBox error code: %d, IOCTL return value: %d\n",
               err, ret);
        rcRet++;
    } else printf("Playback speed successfully set to 100, reported speed is %d\n",
        rate);

    rate = 48000;

    if (RT_FAILURE(err = RTFileIoCtl(File, SNDCTL_DSP_SPEED, &rate, sizeof(rate), &ret)) || ret) {
        printf("Failed to set playback speed on /dev/dsp\n"
               "VBox error code: %d, IOCTL return value: %d\n",
               err, ret);
        rcRet++;
    } else printf("Playback speed successfully set to 48000, reported speed is %d\n",
        rate);

    /*
     * Cleanup.
     */
    ret = RTFileClose(File);
    if (RT_FAILURE(ret))
    {
        printf("Failed to close /dev/dsp. ret=%d\n", ret);
        rcRet++;
    }

    /* Under Linux and L4, this involves ioctls internally */
    RTUUID TestUuid;
    if (RT_FAILURE(RTUuidCreate(&TestUuid)))
    {
        printf("Failed to create a UUID. ret=%d\n", ret);
        rcRet++;
    }

    /*
     * Summary
     */
    if (rcRet == 0)
        printf("tstIoCtl: SUCCESS\n");
    else
        printf("tstIoCtl: FAILURE - %d errors\n", rcRet);
    return rcRet;
}
예제 #6
0
/**
 * Search for available CD/DVD drives using the CAM layer.
 *
 * @returns iprt status code
 * @param   pList      the list to append the drives found to
 * @param   pfSuccess  this will be set to true if we found at least one drive
 *                     and to false otherwise.  Optional.
 */
static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess)
{
    int rc = VINF_SUCCESS;
    RTFILE FileXpt;

    rc = RTFileOpen(&FileXpt, "/dev/xpt0", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    if (RT_SUCCESS(rc))
    {
        union ccb DeviceCCB;
        struct dev_match_pattern DeviceMatchPattern;
        struct dev_match_result *paMatches = NULL;

        RT_ZERO(DeviceCCB);
        RT_ZERO(DeviceMatchPattern);

        /* We want to get all devices. */
        DeviceCCB.ccb_h.func_code  = XPT_DEV_MATCH;
        DeviceCCB.ccb_h.path_id    = CAM_XPT_PATH_ID;
        DeviceCCB.ccb_h.target_id  = CAM_TARGET_WILDCARD;
        DeviceCCB.ccb_h.target_lun = CAM_LUN_WILDCARD;

        /* Setup the pattern */
        DeviceMatchPattern.type = DEV_MATCH_DEVICE;
        DeviceMatchPattern.pattern.device_pattern.path_id    = CAM_XPT_PATH_ID;
        DeviceMatchPattern.pattern.device_pattern.target_id  = CAM_TARGET_WILDCARD;
        DeviceMatchPattern.pattern.device_pattern.target_lun = CAM_LUN_WILDCARD;
        DeviceMatchPattern.pattern.device_pattern.flags      = DEV_MATCH_INQUIRY;

#if __FreeBSD_version >= 900000
# define INQ_PAT data.inq_pat
#else
 #define INQ_PAT inq_pat
#endif
        DeviceMatchPattern.pattern.device_pattern.INQ_PAT.type = T_CDROM;
        DeviceMatchPattern.pattern.device_pattern.INQ_PAT.media_type  = SIP_MEDIA_REMOVABLE | SIP_MEDIA_FIXED;
        DeviceMatchPattern.pattern.device_pattern.INQ_PAT.vendor[0]   = '*'; /* Matches anything */
        DeviceMatchPattern.pattern.device_pattern.INQ_PAT.product[0]  = '*'; /* Matches anything */
        DeviceMatchPattern.pattern.device_pattern.INQ_PAT.revision[0] = '*'; /* Matches anything */
#undef INQ_PAT
        DeviceCCB.cdm.num_patterns    = 1;
        DeviceCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
        DeviceCCB.cdm.patterns        = &DeviceMatchPattern;

        /*
         * Allocate the buffer holding the matches.
         * We will allocate for 10 results and call
         * CAM multiple times if we have more results.
         */
        paMatches = (struct dev_match_result *)RTMemAllocZ(10 * sizeof(struct dev_match_result));
        if (paMatches)
        {
            DeviceCCB.cdm.num_matches   = 0;
            DeviceCCB.cdm.match_buf_len = 10 * sizeof(struct dev_match_result);
            DeviceCCB.cdm.matches       = paMatches;

            do
            {
                rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &DeviceCCB, sizeof(union ccb), NULL);
                if (RT_FAILURE(rc))
                {
                    Log(("Error while querying available CD/DVD devices rc=%Rrc\n", rc));
                    break;
                }

                for (unsigned i = 0; i < DeviceCCB.cdm.num_matches; i++)
                {
                    if (paMatches[i].type == DEV_MATCH_DEVICE)
                    {
                        /* We have the drive now but need the appropriate device node */
                        struct device_match_result *pDevResult = &paMatches[i].result.device_result;
                        union ccb PeriphCCB;
                        struct dev_match_pattern PeriphMatchPattern;
                        struct dev_match_result aPeriphMatches[2];
                        struct periph_match_result *pPeriphResult = NULL;
                        unsigned iPeriphMatch = 0;

                        RT_ZERO(PeriphCCB);
                        RT_ZERO(PeriphMatchPattern);
                        RT_ZERO(aPeriphMatches);

                        /* This time we only want the specific nodes for the device. */
                        PeriphCCB.ccb_h.func_code  = XPT_DEV_MATCH;
                        PeriphCCB.ccb_h.path_id    = paMatches[i].result.device_result.path_id;
                        PeriphCCB.ccb_h.target_id  = paMatches[i].result.device_result.target_id;
                        PeriphCCB.ccb_h.target_lun = paMatches[i].result.device_result.target_lun;

                        /* Setup the pattern */
                        PeriphMatchPattern.type = DEV_MATCH_PERIPH;
                        PeriphMatchPattern.pattern.periph_pattern.path_id    = paMatches[i].result.device_result.path_id;
                        PeriphMatchPattern.pattern.periph_pattern.target_id  = paMatches[i].result.device_result.target_id;
                        PeriphMatchPattern.pattern.periph_pattern.target_lun = paMatches[i].result.device_result.target_lun;
                        PeriphMatchPattern.pattern.periph_pattern.flags      = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
                                                                               PERIPH_MATCH_LUN;
                        PeriphCCB.cdm.num_patterns    = 1;
                        PeriphCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
                        PeriphCCB.cdm.patterns        = &PeriphMatchPattern;
                        PeriphCCB.cdm.num_matches   = 0;
                        PeriphCCB.cdm.match_buf_len = sizeof(aPeriphMatches);
                        PeriphCCB.cdm.matches       = aPeriphMatches;

                        do
                        {
                            rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &PeriphCCB, sizeof(union ccb), NULL);
                            if (RT_FAILURE(rc))
                            {
                                Log(("Error while querying available periph devices rc=%Rrc\n", rc));
                                break;
                            }

                            for (iPeriphMatch = 0; iPeriphMatch < PeriphCCB.cdm.num_matches; iPeriphMatch++)
                            {
                                if (   (aPeriphMatches[iPeriphMatch].type == DEV_MATCH_PERIPH)
                                    && (!strcmp(aPeriphMatches[iPeriphMatch].result.periph_result.periph_name, "cd")))
                                {
                                    pPeriphResult = &aPeriphMatches[iPeriphMatch].result.periph_result;
                                    break; /* We found the periph device */
                                }
                            }

                            if (iPeriphMatch < PeriphCCB.cdm.num_matches)
                                break;

                        } while (   (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
                                 && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));

                        if (pPeriphResult)
                        {
                            char szPath[RTPATH_MAX];
                            char szDesc[256];

                            RTStrPrintf(szPath, sizeof(szPath), "/dev/%s%d",
                                        pPeriphResult->periph_name, pPeriphResult->unit_number);

                            /* Remove trailing white space. */
                            strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.vendor,
                                                            sizeof(pDevResult->inq_data.vendor));
                            strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.product,
                                                            sizeof(pDevResult->inq_data.product));

                            dvdCreateDeviceString(pDevResult->inq_data.vendor,
                                                    pDevResult->inq_data.product,
                                                    szDesc, sizeof(szDesc));

                            pList->push_back(DriveInfo(szPath, "", szDesc));
                            if (pfSuccess)
                                *pfSuccess = true;
                        }
                    }
                }
            } while (   (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
                     && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));

            RTMemFree(paMatches);
        }
        else
            rc = VERR_NO_MEMORY;

        RTFileClose(FileXpt);
    }

    return rc;
}