Subversion Repositories pentevo

Rev

Rev 883 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "init.h"
  6. #include "hddio.h"
  7.  
  8. #include "util.h"
  9.  
  10. typedef int (__cdecl *GetASPI32SupportInfo_t)();
  11. typedef int (__cdecl *SendASPI32Command_t)(void *SRB);
  12. const int ATAPI_CDB_SIZE = 12; // sizeof(CDB) == 16
  13. //const int MAX_INFO_LEN = 48;
  14.  
  15. static GetASPI32SupportInfo_t _GetASPI32SupportInfo = nullptr;
  16. static SendASPI32Command_t _SendASPI32Command = nullptr;
  17. static HMODULE hAspiDll = nullptr;
  18. static HANDLE hASPICompletionEvent;
  19.  
  20.  
  21. DWORD ATA_PASSER::open(PHYS_DEVICE *dev)
  22. {
  23.    close();
  24.    this->dev = dev;
  25.  
  26.    hDevice = CreateFile(dev->filename,
  27.                 GENERIC_READ | GENERIC_WRITE, // R/W required!
  28.                 (temp.win9x?0:FILE_SHARE_DELETE) /*Dexus*/ | FILE_SHARE_READ | FILE_SHARE_WRITE,
  29.                 nullptr, OPEN_EXISTING, 0, nullptr);
  30.  
  31.    if (hDevice == INVALID_HANDLE_VALUE)
  32.    {
  33.        ULONG Le = GetLastError();
  34.        printf("can't open: `%s', %lu\n", dev->filename, Le);
  35.        return Le;
  36.    }
  37.  
  38.    if(dev->type == ATA_NTHDD && dev->usage == ATA_OP_USE)
  39.    {
  40.        memset(Vols, 0, sizeof(Vols));
  41.  
  42.        // lock & dismount all volumes on disk
  43.        char VolName[256];
  44.        HANDLE VolEnum = FindFirstVolume(VolName, _countof(VolName));
  45.        if(VolEnum == INVALID_HANDLE_VALUE)
  46.        {
  47.            ULONG Le = GetLastError();
  48.            printf("can't enumerate volumes: %lu\n", Le);
  49.            return Le;
  50.        }
  51.  
  52.        BOOL NextVol = TRUE;
  53.        unsigned VolIdx = 0;
  54.        unsigned i;
  55.        for(; NextVol; NextVol = FindNextVolume(VolEnum, VolName, _countof(VolName)))
  56.        {
  57.            size_t l = strlen(VolName);
  58.            if(VolName[l-1] == '\\')
  59.                VolName[l-1] = 0;
  60.  
  61.            HANDLE Vol = CreateFile(VolName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
  62.            if(Vol == INVALID_HANDLE_VALUE)
  63.            {
  64.                printf("can't open volume `%s'\n", VolName);
  65.                continue;
  66.            }
  67.  
  68.            UCHAR Buf[sizeof(VOLUME_DISK_EXTENTS) + 100 * sizeof(DISK_EXTENT)];
  69.            PVOLUME_DISK_EXTENTS DiskExt = PVOLUME_DISK_EXTENTS(Buf);
  70.  
  71.            ULONG Junk;
  72.            if(!DeviceIoControl(Vol, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, nullptr, 0, Buf, sizeof(Buf), &Junk, nullptr))
  73.            {
  74.                Junk = GetLastError();
  75.                CloseHandle(Vol);
  76.                printf("can't get volume extents: `%s', %lu\n", VolName, Junk);
  77.                continue;
  78.            }
  79.  
  80.            if(DiskExt->NumberOfDiskExtents == 0)
  81.            {
  82.                // bad volume
  83.                CloseHandle(Vol);
  84.                return ERROR_ACCESS_DENIED;
  85.            }
  86.  
  87.            if(DiskExt->NumberOfDiskExtents > 1)
  88.            {
  89.                for(i = 0; i < DiskExt->NumberOfDiskExtents; i++)
  90.                {
  91.                    if(DiskExt->Extents[i].DiskNumber == dev->spti_id)
  92.                    {
  93.                        // complex volume (volume split over several disks)
  94.                        CloseHandle(Vol);
  95.                        return ERROR_ACCESS_DENIED;
  96.                    }
  97.                }
  98.            }
  99.  
  100.            if(DiskExt->Extents[0].DiskNumber != dev->spti_id)
  101.            {
  102.                CloseHandle(Vol);
  103.                continue;
  104.            }
  105.  
  106.            Vols[VolIdx++] = Vol;
  107.        }
  108.        FindVolumeClose(VolEnum);
  109.  
  110.        for(i = 0; i < VolIdx; i++)
  111.        {
  112.            ULONG Junk;
  113.            if(!DeviceIoControl(Vols[i], FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &Junk, nullptr))
  114.            {
  115.                Junk = GetLastError();
  116.                printf("can't lock volume: %lu\n", Junk);
  117.                return Junk;
  118.            }
  119.            if(!DeviceIoControl(Vols[i], FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &Junk, nullptr))
  120.            {
  121.                Junk = GetLastError();
  122.                printf("can't dismount volume: %lu\n", Junk);
  123.                return Junk;
  124.            }
  125.        }
  126.    }
  127.    return NO_ERROR;
  128. }
  129.  
  130. void ATA_PASSER::close()
  131. {
  132.    if (hDevice != INVALID_HANDLE_VALUE)
  133.    {
  134.        if(dev->type == ATA_NTHDD && dev->usage == ATA_OP_USE)
  135.        {
  136.            // unlock all volumes on disk
  137.            for(unsigned i = 0; i < _countof(Vols) && Vols[i]; i++)
  138.            {
  139.                ULONG Junk;
  140.                DeviceIoControl(Vols[i], FSCTL_UNLOCK_VOLUME, nullptr, 0, nullptr, 0, &Junk, nullptr);
  141.                CloseHandle(Vols[i]);
  142.                Vols[i] = nullptr;
  143.            }
  144.        }
  145.  
  146.        CloseHandle(hDevice);
  147.    }
  148.    hDevice = INVALID_HANDLE_VALUE;
  149.    dev = nullptr;
  150. }
  151.  
  152. unsigned ATA_PASSER::identify(PHYS_DEVICE *outlist, unsigned max)
  153. {
  154.    unsigned res = 0;
  155.    ATA_PASSER ata;
  156.  
  157.    unsigned HddCount = get_hdd_count();
  158.  
  159.    for (unsigned drive = 0; drive < MAX_PHYS_HD_DRIVES && res < max; drive++)
  160.    {
  161.  
  162.       PHYS_DEVICE *dev = outlist + res;
  163.       dev->type = ATA_NTHDD;
  164.       dev->spti_id = drive;
  165.       dev->usage = ATA_OP_ENUM_ONLY;
  166.       sprintf(dev->filename, "\\\\.\\PhysicalDrive%u", dev->spti_id);
  167.  
  168.       if(drive >= HddCount)
  169.           continue;
  170.  
  171.       DWORD errcode = ata.open(dev);
  172.       if (errcode == ERROR_FILE_NOT_FOUND)
  173.           continue;
  174.  
  175.       color(CONSCLR_HARDITEM);
  176.       printf("hd%u: ", drive);
  177.  
  178.       if (errcode != NO_ERROR)
  179.       {
  180.           color(CONSCLR_ERROR);
  181.           printf("access failed\n");
  182.           err_win32(errcode);
  183.           continue;
  184.       }
  185.  
  186.       SENDCMDINPARAMS in = { 512 };
  187.       in.irDriveRegs.bCommandReg = ID_CMD;
  188.       struct
  189.       {
  190.           SENDCMDOUTPARAMS out;
  191.           char xx[512];
  192.       } res_buffer;
  193.       res_buffer.out.cBufferSize = 512;
  194.       DWORD sz;
  195.  
  196.       DISK_GEOMETRY geo = { };
  197.       int res1 = DeviceIoControl(ata.hDevice, SMART_RCV_DRIVE_DATA, &in, sizeof in, &res_buffer, sizeof res_buffer, &sz, nullptr);
  198.       if(!res1)
  199.       {
  200.           printf("cant get hdd info, %lu\n", GetLastError());
  201.       }
  202.       int res2 = DeviceIoControl(ata.hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &geo, sizeof geo, &sz, nullptr);
  203.       if(!res2)
  204.       {
  205.           printf("cant get hdd geometry, %lu\n", GetLastError());
  206.       }
  207.       if (geo.BytesPerSector != 512)
  208.       {
  209.           color(CONSCLR_ERROR);
  210.           printf("unsupported sector size (%lu bytes)\n", geo.BytesPerSector);
  211.           continue;
  212.       }
  213.  
  214.       ata.close();
  215.  
  216.       if (!res1)
  217.       {
  218.           color(CONSCLR_ERROR);
  219.           printf("identification failed\n");
  220.           continue;
  221.       }
  222.  
  223.       memcpy(dev->idsector, res_buffer.out.bBuffer, 512);
  224.       char model[42], serial[22];
  225.       swap_bytes(model, res_buffer.out.bBuffer+54, 20);
  226.       swap_bytes(serial, res_buffer.out.bBuffer+20, 10);
  227.  
  228.       dev->hdd_size = geo.Cylinders.LowPart * geo.SectorsPerTrack * geo.TracksPerCylinder;
  229.       unsigned shortsize = dev->hdd_size / 2; char mult = 'K';
  230.       if (shortsize >= 100000)
  231.       {
  232.          shortsize /= 1024; mult = 'M';
  233.          if(shortsize >= 100000)
  234.          {
  235.              shortsize /= 1024; mult = 'G';
  236.          }
  237.       }
  238.  
  239.       color(CONSCLR_HARDINFO);
  240.       printf("%-40s %-20s ", model, serial);
  241.       color(CONSCLR_HARDITEM);
  242.       printf("%8u %cb\n", shortsize, mult);
  243.       if (dev->hdd_size > 0xFFFFFFF)
  244.       {
  245.           color(CONSCLR_WARNING);
  246.           printf("     drive %u warning! LBA48 is not supported. only first 128GB visible\n", drive); //Alone Coder 0.36.7
  247.       }
  248.  
  249.       print_device_name(dev->viewname, dev);
  250.       res++;
  251.    }
  252.  
  253.    return res;
  254. }
  255.  
  256. unsigned ATA_PASSER::get_hdd_count() // static
  257. {
  258.     HDEVINFO DeviceInfoSet;
  259.     ULONG MemberIndex;
  260.  
  261.     // create a HDEVINFO with all present devices
  262.     DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  263.     if (DeviceInfoSet == INVALID_HANDLE_VALUE)
  264.     {
  265.         assert(FALSE);
  266.         return 0;
  267.     }
  268.  
  269.     // enumerate through all devices in the set
  270.     MemberIndex = 0;
  271.     while(true)
  272.     {
  273.         // get device interfaces
  274.         SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
  275.         DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  276.         if (!SetupDiEnumDeviceInterfaces(DeviceInfoSet, nullptr, &GUID_DEVINTERFACE_DISK, MemberIndex, &DeviceInterfaceData))
  277.         {
  278.             if (GetLastError() != ERROR_NO_MORE_ITEMS)
  279.             {
  280.                 // error
  281.                 assert(FALSE);
  282.             }
  283.  
  284.             // ok, reached end of the device enumeration
  285.             break;
  286.         }
  287.  
  288.         // process the next device next time
  289.         MemberIndex++;
  290.     }
  291.  
  292.     // destroy device info list
  293.     SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  294.  
  295.     return MemberIndex;
  296. }
  297.  
  298.  
  299. bool ATA_PASSER::seek(u64 nsector)
  300. {
  301.    LARGE_INTEGER offset;
  302.    offset.QuadPart = ((__int64)nsector) << 9;
  303.    DWORD code = SetFilePointer(hDevice, LONG(offset.LowPart), &offset.HighPart, FILE_BEGIN);
  304.    return (code != INVALID_SET_FILE_POINTER || GetLastError() == NO_ERROR);
  305. }
  306.  
  307. bool ATA_PASSER::read_sector(unsigned char *dst)
  308. {
  309.    DWORD sz = 0;
  310.    if (!ReadFile(hDevice, dst, 512, &sz, nullptr))
  311.        return false;
  312.    if (sz < 512)
  313.        memset(dst+sz, 0, 512-sz); // on EOF, or truncated file, read 00
  314.    return true;
  315. }
  316.  
  317. bool ATA_PASSER::write_sector(unsigned char *src)
  318. {
  319.    DWORD sz = 0;
  320.    return (WriteFile(hDevice, src, 512, &sz, nullptr) && sz == 512);
  321. }
  322.  
  323. DWORD ATAPI_PASSER::open(PHYS_DEVICE *dev)
  324. {
  325.    close();
  326.    this->dev = dev;
  327.    if (dev->type == ATA_ASPI_CD)
  328.        return NO_ERROR;
  329.  
  330.    hDevice = CreateFile(dev->filename,
  331.                 GENERIC_READ | GENERIC_WRITE, // R/W required!
  332.                 (temp.win9x?0:FILE_SHARE_DELETE) /*Dexus*/ | FILE_SHARE_READ | FILE_SHARE_WRITE,
  333.                 nullptr, OPEN_EXISTING, 0, nullptr);
  334.  
  335.    if (hDevice != INVALID_HANDLE_VALUE)
  336.        return NO_ERROR;
  337.    return GetLastError();
  338. }
  339.  
  340. void ATAPI_PASSER::close()
  341. {
  342.    if (!dev || dev->type == ATA_ASPI_CD)
  343.        return;
  344.    if (hDevice != INVALID_HANDLE_VALUE)
  345.        CloseHandle(hDevice);
  346.    hDevice = INVALID_HANDLE_VALUE;
  347.    dev = nullptr;
  348. }
  349.  
  350. unsigned ATAPI_PASSER::identify(PHYS_DEVICE *outlist, unsigned max)
  351. {
  352.    unsigned res = 0;
  353.    ATAPI_PASSER atapi;
  354.  
  355.    if (conf.cd_aspi)
  356.    {
  357.  
  358.       init_aspi();
  359.  
  360.  
  361.       for (unsigned adapterid = 0; ; adapterid++)
  362.       {
  363.  
  364.          SRB_HAInquiry SRB = { };
  365.          SRB.SRB_Cmd        = SC_HA_INQUIRY;
  366.          SRB.SRB_HaId       = (unsigned char)adapterid;
  367.          int ASPIStatus = _SendASPI32Command(&SRB);
  368.  
  369.          if (ASPIStatus != SS_COMP) break;
  370.  
  371.          char b1[20], b2[20];
  372.          memcpy(b1, SRB.HA_ManagerId, 16); b1[16] = 0;
  373.          memcpy(b2, SRB.HA_Identifier, 16); b2[16] = 0;
  374.  
  375.          if (adapterid == 0) {
  376.             color(CONSCLR_HARDITEM); printf("using ");
  377.             color(CONSCLR_WARNING); printf("%s", b1);
  378.             color(CONSCLR_HARDITEM); printf(" %s\n", b2);
  379.          }
  380.          if (adapterid >= SRB.HA_Count) break;
  381.          // int maxTargets = (int)SRB.HA_Unique[3]; // always 8 (?)
  382.  
  383.          for (unsigned targetid = 0; targetid < 8; targetid++) {
  384.  
  385.             PHYS_DEVICE *dev = outlist + res;
  386.             dev->type = ATA_ASPI_CD;
  387.             dev->adapterid = adapterid; // (int)SRB.HA_SCSI_ID; // does not work with Nero ASPI
  388.             dev->targetid = targetid;
  389.  
  390.             DWORD errcode = atapi.open(dev);
  391.             if (errcode != NO_ERROR) continue;
  392.  
  393.             int ok = atapi.read_atapi_id(dev->idsector, 1);
  394.             atapi.close();
  395.             if (ok != 2) continue; // not a CD-ROM
  396.  
  397.             print_device_name(dev->viewname, dev);
  398.             res++;
  399.          }
  400.       }
  401.  
  402.  
  403.        return res;
  404.    }
  405.    
  406.    // spti
  407.    for (unsigned drive = 0; drive < MAX_PHYS_CD_DRIVES && res < max; drive++)
  408.    {
  409.  
  410.       PHYS_DEVICE *dev = outlist + res;
  411.       dev->type = ATA_SPTI_CD;
  412.       dev->spti_id = drive;
  413.       dev->usage = ATA_OP_ENUM_ONLY;
  414.       sprintf(dev->filename, "\\\\.\\CdRom%u", dev->spti_id);
  415.  
  416.       DWORD errcode = atapi.open(dev);
  417.       if (errcode == ERROR_FILE_NOT_FOUND)
  418.           continue;
  419.  
  420.       color(CONSCLR_HARDITEM);
  421.       printf("cd%u: ", drive);
  422.       if (errcode != NO_ERROR)
  423.       {
  424.           color(CONSCLR_ERROR);
  425.           printf("access failed\n");
  426.           err_win32(errcode);
  427.           continue;
  428.       }
  429.  
  430.  
  431.       int ok = atapi.read_atapi_id(dev->idsector, 0);
  432.       atapi.close();
  433.       if (!ok)
  434.       {
  435.           color(CONSCLR_ERROR);
  436.           printf("identification failed\n");
  437.           continue;
  438.       }
  439.       if (ok < 2)
  440.           continue; // not a CD-ROM
  441.  
  442.       print_device_name(dev->viewname, dev);
  443.       res++;
  444.    }
  445.  
  446.    return res;
  447. }
  448.  
  449. int ATAPI_PASSER::pass_through(void *databuf, size_t bufsize)
  450. {
  451.    int res = (conf.cd_aspi)? SEND_ASPI_CMD(databuf, bufsize) : SEND_SPTI_CMD(databuf, bufsize);
  452.    return res;
  453. }
  454.  
  455. int ATAPI_PASSER::SEND_SPTI_CMD(void *databuf, size_t bufsize)
  456. {
  457.    memset(databuf, 0, bufsize);
  458.  
  459.    struct {
  460.       SCSI_PASS_THROUGH_DIRECT p;
  461.       unsigned char sense[MAX_SENSE_LEN];
  462.    } srb = { }, dst;
  463.  
  464.    srb.p.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
  465.    *(CDB*)&srb.p.Cdb = cdb;
  466.    srb.p.CdbLength = sizeof(CDB);
  467.    srb.p.DataIn = SCSI_IOCTL_DATA_IN;
  468.    srb.p.TimeOutValue = 10;
  469.    srb.p.DataBuffer = databuf;
  470.    srb.p.DataTransferLength = ULONG(bufsize);
  471.    srb.p.SenseInfoLength = sizeof(srb.sense);
  472.    srb.p.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT);
  473.  
  474.    DWORD outsize;
  475.    int r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT,
  476.                            &srb.p, sizeof(srb.p),
  477.                            &dst, sizeof(dst),
  478.                            &outsize, nullptr);
  479.  
  480.    if (!r) { return 0; }
  481.  
  482.    passed_length = dst.p.DataTransferLength;
  483.    if ((senselen = dst.p.SenseInfoLength)) memcpy(sense, dst.sense, senselen);
  484.  
  485. #ifdef DUMP_HDD_IO
  486. printf("sense=%d, data=%d, srbsz=%d/%d, dir=%d. ok%d\n", senselen, passed_length, outsize, sizeof(srb.p), dst.p.DataIn, res);
  487. printf("srb:"); dump1((BYTE*)&dst, outsize);
  488. printf("data:"); dump1((BYTE*)databuf, 0x40);
  489. #endif
  490.  
  491.    return 1;
  492. }
  493.  
  494. int ATAPI_PASSER::read_atapi_id(unsigned char *idsector, char prefix)
  495. {
  496.    memset(&cdb, 0, sizeof(CDB));
  497.    memset(idsector, 0, 512);
  498.  
  499.    INQUIRYDATA inq;
  500.    cdb.CDB6INQUIRY.OperationCode = 0x12; // INQUIRY
  501.    cdb.CDB6INQUIRY.AllocationLength = sizeof(inq);
  502.    if (!pass_through(&inq, sizeof(inq))) return 0;
  503.  
  504.    char vendor[10], product[18], revision[6], id[22], ata_name[26];
  505.  
  506.    memcpy(vendor, inq.VendorId, sizeof(inq.VendorId)); vendor[sizeof(inq.VendorId)] = 0;
  507.    memcpy(product, inq.ProductId, sizeof(inq.ProductId)); product[sizeof(inq.ProductId)] = 0;
  508.    memcpy(revision, inq.ProductRevisionLevel, sizeof(inq.ProductRevisionLevel)); revision[sizeof(inq.ProductRevisionLevel)] = 0;
  509.    memcpy(id, inq.VendorSpecific, sizeof(inq.VendorSpecific)); id[sizeof(inq.VendorSpecific)] = 0;
  510.  
  511.    if (prefix) {
  512.       color(CONSCLR_HARDITEM);
  513.       if (dev->type == ATA_ASPI_CD) printf("%u.%u: ", dev->adapterid, dev->targetid);
  514.       if (dev->type == ATA_SPTI_CD) printf("cd%u: ", dev->spti_id);
  515.    }
  516.  
  517.    trim(vendor); trim(product); trim(revision); trim(id);
  518.    sprintf(ata_name, "%s %s", vendor, product);
  519.  
  520.    idsector[0] = 0xC0; // removable, accelerated DRQ, 12-byte packet
  521.    idsector[1] = 0x85; // protocol: ATAPI, device type: CD-ROM
  522.  
  523.    make_ata_string(idsector+54, 20, ata_name);
  524.    make_ata_string(idsector+20, 10, id);
  525.    make_ata_string(idsector+46,  4, revision);
  526.  
  527.    idsector[0x63] = 0x0B; // caps: IORDY,LBA,DMA
  528.    idsector[0x67] = 4; // PIO timing
  529.    idsector[0x69] = 2; // DMA timing
  530.  
  531.    if (inq.DeviceType == 5) color(CONSCLR_HARDINFO);
  532.    printf("%-40s %-20s  ", ata_name, id);
  533.    color(CONSCLR_HARDITEM);
  534.    printf("rev.%-4s\n", revision);
  535.  
  536.    return 1 + (inq.DeviceType == 5);
  537. }
  538.  
  539. bool ATAPI_PASSER::read_sector(unsigned char *dst)
  540. {
  541.    DWORD sz = 0;
  542.    if (!ReadFile(hDevice, dst, 2048, &sz, nullptr))
  543.        return false;
  544.    if (sz < 2048)
  545.        memset(dst+sz, 0, 2048-sz); // on EOF, or truncated file, read 00
  546.    return true;
  547. }
  548.  
  549. bool ATAPI_PASSER::seek(unsigned nsector)
  550. {
  551.    LARGE_INTEGER offset;
  552.    offset.QuadPart = i64(nsector) * 2048;
  553.    DWORD code = SetFilePointer(hDevice, LONG(offset.LowPart), &offset.HighPart, FILE_BEGIN);
  554.    return (code != INVALID_SET_FILE_POINTER || GetLastError() == NO_ERROR);
  555. }
  556.  
  557. void make_ata_string(unsigned char *dst, unsigned n_words, const char *src)
  558. {
  559.    unsigned i; //Alone Coder 0.36.7
  560.    for (/*unsigned*/ i = 0; i < n_words*2 && src[i]; i++) dst[i] = u8(src[i]);
  561.    while (i < n_words*2) dst[i++] = ' ';
  562.    unsigned char tmp;
  563.    for(i = 0; i < n_words * 2; i += 2)
  564.    {
  565.        tmp = dst[i];
  566.        dst[i] = dst[i + 1];
  567.        dst[i + 1] = tmp;
  568.    }
  569. }
  570.  
  571. void swap_bytes(char *dst, BYTE *src, unsigned n_words)
  572. {
  573.    unsigned i; //Alone Coder 0.36.7
  574.    for (/*unsigned*/ i = 0; i < n_words; i++)
  575.    {
  576.       char c1 = char(src[2*i]), c2 = char(src[2*i+1]);
  577.       dst[2 * i] = c2;
  578.       dst[2 * i + 1] = c1;
  579.    }
  580.    dst[2*i] = 0;
  581.    trim(dst);
  582. }
  583.  
  584. void print_device_name(char *dst, PHYS_DEVICE *dev)
  585. {
  586.    char model[42], serial[22];
  587.    swap_bytes(model, dev->idsector + 54, 20);
  588.    swap_bytes(serial, dev->idsector + 20, 10);
  589.    sprintf(dst, "<%s,%s>", model, serial);
  590. }
  591.  
  592. void init_aspi()
  593. {
  594.    if (_SendASPI32Command)
  595.        return;
  596.    hAspiDll = LoadLibrary("WNASPI32.DLL");
  597.    if (!hAspiDll)
  598.    {
  599.        errmsg("failed to load WNASPI32.DLL");
  600.        err_win32();
  601.        exit();
  602.    }
  603.    _GetASPI32SupportInfo = (GetASPI32SupportInfo_t)GetProcAddress(hAspiDll, "GetASPI32SupportInfo");
  604.    _SendASPI32Command = (SendASPI32Command_t)GetProcAddress(hAspiDll, "SendASPI32Command");
  605.    if (!_GetASPI32SupportInfo || !_SendASPI32Command) errexit("invalid ASPI32 library");
  606.    int init = _GetASPI32SupportInfo();
  607.    if (((init >> 8) & 0xFF) != SS_COMP)
  608.        errexit("error in ASPI32 initialization");
  609.    hASPICompletionEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  610. }
  611.  
  612. int ATAPI_PASSER::SEND_ASPI_CMD(void *buf, size_t buf_sz)
  613. {
  614.    SRB_ExecSCSICmd SRB = { };
  615.    SRB.SRB_Cmd        = SC_EXEC_SCSI_CMD;
  616.    SRB.SRB_HaId       = (unsigned char)dev->adapterid;
  617.    SRB.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT;
  618.    SRB.SRB_Target     = (unsigned char)dev->targetid;
  619.    SRB.SRB_BufPointer = (unsigned char*)buf;
  620.    SRB.SRB_BufLen     = DWORD(buf_sz);
  621.    SRB.SRB_SenseLen   = sizeof(SRB.SenseArea);
  622.    SRB.SRB_CDBLen     = ATAPI_CDB_SIZE;
  623.    SRB.SRB_PostProc   = hASPICompletionEvent;
  624.    memcpy(SRB.CDBByte, &cdb, ATAPI_CDB_SIZE);
  625.  
  626.    /* DWORD ASPIStatus = */ _SendASPI32Command(&SRB);
  627.    passed_length = SRB.SRB_BufLen;
  628.  
  629.    if (SRB.SRB_Status == SS_PENDING)
  630.    {
  631.       DWORD ASPIEventStatus = WaitForSingleObject(hASPICompletionEvent, 10000); // timeout 10sec
  632.       if (ASPIEventStatus == WAIT_OBJECT_0)
  633.           ResetEvent(hASPICompletionEvent);
  634.    }
  635.    senselen = SRB.SRB_SenseLen;
  636.    memcpy(sense, SRB.SenseArea, senselen);
  637.    if (temp.win9x)
  638.        senselen = 0; //Alone Coder //makes possible to read one CD sector in win9x
  639.    if (/*(temp.win9x)&&*/(passed_length >= 0xffff))
  640.        passed_length = 2048; //Alone Coder //was >=65535 in win9x //makes possible to work in win9x (HDDoct, WDC, Time Gal) //XP fails too
  641.  
  642. #ifdef DUMP_HDD_IO
  643. printf("sense=%d, data=%d/%d, ok%d\n", senselen, passed_length, buf_sz, SRB.SRB_Status);
  644. printf("srb:"); dump1((BYTE*)&SRB, sizeof(SRB));
  645. printf("data:"); dump1((BYTE*)buf, 0x40);
  646. #endif
  647.  
  648.    return (SRB.SRB_Status == SS_COMP);
  649. }
  650.  
  651. void done_aspi()
  652. {
  653.    if (!hAspiDll)
  654.        return;
  655.    FreeLibrary(hAspiDll);
  656.    CloseHandle(hASPICompletionEvent);
  657. }
  658.