Subversion Repositories pentevo

Rev

Rev 716 | Blame | Last modification | View Log | Download | RSS feed

  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. GetASPI32SupportInfo_t _GetASPI32SupportInfo = 0;
  16. SendASPI32Command_t _SendASPI32Command = 0;
  17. HMODULE hAspiDll = 0;
  18. 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.                 0, OPEN_EXISTING, 0, 0);
  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.            int 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, 0, OPEN_EXISTING, 0, 0);
  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, 0, 0, Buf, sizeof(Buf), &Junk, 0))
  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, 0, 0, 0, 0, &Junk, 0))
  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, 0, 0, 0, 0, &Junk, 0))
  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, 0, 0, 0, 0, &Junk, 0);
  141.                CloseHandle(Vols[i]);
  142.                Vols[i] = 0;
  143.            }
  144.        }
  145.  
  146.        CloseHandle(hDevice);
  147.    }
  148.    hDevice = INVALID_HANDLE_VALUE;
  149.    dev = 0;
  150. }
  151.  
  152. unsigned ATA_PASSER::identify(PHYS_DEVICE *outlist, int max)
  153. {
  154.    int 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%d", 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%d: ", 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 = { 0 };
  197.       int res1 = DeviceIoControl(ata.hDevice, SMART_RCV_DRIVE_DATA, &in, sizeof in, &res_buffer, sizeof res_buffer, &sz, 0);
  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, 0, 0, &geo, sizeof geo, &sz, 0);
  203.       if (geo.BytesPerSector != 512)
  204.       {
  205.           color(CONSCLR_ERROR);
  206.           printf("unsupported sector size (%lu bytes)\n", geo.BytesPerSector);
  207.           continue;
  208.       }
  209.  
  210.       ata.close();
  211.  
  212.       if (!res1)
  213.       {
  214.           color(CONSCLR_ERROR);
  215.           printf("identification failed\n");
  216.           continue;
  217.       }
  218.  
  219.       memcpy(dev->idsector, res_buffer.out.bBuffer, 512);
  220.       char model[42], serial[22];
  221.       swap_bytes(model, res_buffer.out.bBuffer+54, 20);
  222.       swap_bytes(serial, res_buffer.out.bBuffer+20, 10);
  223.  
  224.       dev->hdd_size = geo.Cylinders.LowPart * geo.SectorsPerTrack * geo.TracksPerCylinder;
  225.       unsigned shortsize = dev->hdd_size / 2; char mult = 'K';
  226.       if (shortsize >= 100000)
  227.       {
  228.          shortsize /= 1024, mult = 'M';
  229.          if (shortsize >= 100000)
  230.              shortsize /= 1024, mult = 'G';
  231.       }
  232.  
  233.       color(CONSCLR_HARDINFO);
  234.       printf("%-40s %-20s ", model, serial);
  235.       color(CONSCLR_HARDITEM);
  236.       printf("%8d %cb\n", shortsize, mult);
  237.       if (dev->hdd_size > 0xFFFFFFF)
  238.       {
  239.           color(CONSCLR_WARNING);
  240.           printf("     drive %d warning! LBA48 is not supported. only first 128GB visible\n", drive); //Alone Coder 0.36.7
  241.       }
  242.  
  243.       print_device_name(dev->viewname, dev);
  244.       res++;
  245.    }
  246.  
  247.    return res;
  248. }
  249.  
  250. unsigned ATA_PASSER::get_hdd_count() // static
  251. {
  252.     HDEVINFO DeviceInfoSet;
  253.     ULONG MemberIndex;
  254.  
  255.     // create a HDEVINFO with all present devices
  256.     DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  257.     if (DeviceInfoSet == INVALID_HANDLE_VALUE)
  258.     {
  259.         assert(FALSE);
  260.         return 0;
  261.     }
  262.  
  263.     // enumerate through all devices in the set
  264.     MemberIndex = 0;
  265.     while(true)
  266.     {
  267.         // get device interfaces
  268.         SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
  269.         DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  270.         if (!SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &GUID_DEVINTERFACE_DISK, MemberIndex, &DeviceInterfaceData))
  271.         {
  272.             if (GetLastError() != ERROR_NO_MORE_ITEMS)
  273.             {
  274.                 // error
  275.                 assert(FALSE);
  276.             }
  277.  
  278.             // ok, reached end of the device enumeration
  279.             break;
  280.         }
  281.  
  282.         // process the next device next time
  283.         MemberIndex++;
  284.     }
  285.  
  286.     // destroy device info list
  287.     SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  288.  
  289.     return MemberIndex;
  290. }
  291.  
  292.  
  293. bool ATA_PASSER::seek(u64 nsector)
  294. {
  295.    LARGE_INTEGER offset;
  296.    offset.QuadPart = ((__int64)nsector) << 9;
  297.    DWORD code = SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
  298.    return (code != INVALID_SET_FILE_POINTER || GetLastError() == NO_ERROR);
  299. }
  300.  
  301. bool ATA_PASSER::read_sector(unsigned char *dst)
  302. {
  303.    DWORD sz = 0;
  304.    if (!ReadFile(hDevice, dst, 512, &sz, 0))
  305.        return false;
  306.    if (sz < 512)
  307.        memset(dst+sz, 0, 512-sz); // on EOF, or truncated file, read 00
  308.    return true;
  309. }
  310.  
  311. bool ATA_PASSER::write_sector(unsigned char *src)
  312. {
  313.    DWORD sz = 0;
  314.    return (WriteFile(hDevice, src, 512, &sz, 0) && sz == 512);
  315. }
  316.  
  317. DWORD ATAPI_PASSER::open(PHYS_DEVICE *dev)
  318. {
  319.    close();
  320.    this->dev = dev;
  321.    if (dev->type == ATA_ASPI_CD)
  322.        return NO_ERROR;
  323.  
  324.    hDevice = CreateFile(dev->filename,
  325.                 GENERIC_READ | GENERIC_WRITE, // R/W required!
  326.                 (temp.win9x?0:FILE_SHARE_DELETE) /*Dexus*/ | FILE_SHARE_READ | FILE_SHARE_WRITE,
  327.                 0, OPEN_EXISTING, 0, 0);
  328.  
  329.    if (hDevice != INVALID_HANDLE_VALUE)
  330.        return NO_ERROR;
  331.    return GetLastError();
  332. }
  333.  
  334. void ATAPI_PASSER::close()
  335. {
  336.    if (!dev || dev->type == ATA_ASPI_CD)
  337.        return;
  338.    if (hDevice != INVALID_HANDLE_VALUE)
  339.        CloseHandle(hDevice);
  340.    hDevice = INVALID_HANDLE_VALUE;
  341.    dev = 0;
  342. }
  343.  
  344. unsigned ATAPI_PASSER::identify(PHYS_DEVICE *outlist, int max)
  345. {
  346.    int res = 0;
  347.    ATAPI_PASSER atapi;
  348.  
  349.    if (conf.cd_aspi)
  350.    {
  351.  
  352.       init_aspi();
  353.  
  354.  
  355.       for (int adapterid = 0; ; adapterid++)
  356.       {
  357.  
  358.          SRB_HAInquiry SRB = { 0 };
  359.          SRB.SRB_Cmd        = SC_HA_INQUIRY;
  360.          SRB.SRB_HaId       = (unsigned char)adapterid;
  361.          DWORD ASPIStatus = _SendASPI32Command(&SRB);
  362.  
  363.          if (ASPIStatus != SS_COMP) break;
  364.  
  365.          char b1[20], b2[20];
  366.          memcpy(b1, SRB.HA_ManagerId, 16); b1[16] = 0;
  367.          memcpy(b2, SRB.HA_Identifier, 16); b2[16] = 0;
  368.  
  369.          if (adapterid == 0) {
  370.             color(CONSCLR_HARDITEM); printf("using ");
  371.             color(CONSCLR_WARNING); printf("%s", b1);
  372.             color(CONSCLR_HARDITEM); printf(" %s\n", b2);
  373.          }
  374.          if (adapterid >= (int)SRB.HA_Count) break;
  375.          // int maxTargets = (int)SRB.HA_Unique[3]; // always 8 (?)
  376.  
  377.          for (int targetid = 0; targetid < 8; targetid++) {
  378.  
  379.             PHYS_DEVICE *dev = outlist + res;
  380.             dev->type = ATA_ASPI_CD;
  381.             dev->adapterid = adapterid; // (int)SRB.HA_SCSI_ID; // does not work with Nero ASPI
  382.             dev->targetid = targetid;
  383.  
  384.             DWORD errcode = atapi.open(dev);
  385.             if (errcode != NO_ERROR) continue;
  386.  
  387.             int ok = atapi.read_atapi_id(dev->idsector, 1);
  388.             atapi.close();
  389.             if (ok != 2) continue; // not a CD-ROM
  390.  
  391.             print_device_name(dev->viewname, dev);
  392.             res++;
  393.          }
  394.       }
  395.  
  396.  
  397.        return res;
  398.    }
  399.    
  400.    // spti
  401.    for (int drive = 0; drive < MAX_PHYS_CD_DRIVES && res < max; drive++)
  402.    {
  403.  
  404.       PHYS_DEVICE *dev = outlist + res;
  405.       dev->type = ATA_SPTI_CD;
  406.       dev->spti_id = drive;
  407.       dev->usage = ATA_OP_ENUM_ONLY;
  408.       sprintf(dev->filename, "\\\\.\\CdRom%d", dev->spti_id);
  409.  
  410.       DWORD errcode = atapi.open(dev);
  411.       if (errcode == ERROR_FILE_NOT_FOUND)
  412.           continue;
  413.  
  414.       color(CONSCLR_HARDITEM);
  415.       printf("cd%d: ", drive);
  416.       if (errcode != NO_ERROR)
  417.       {
  418.           color(CONSCLR_ERROR);
  419.           printf("access failed\n");
  420.           err_win32(errcode);
  421.           continue;
  422.       }
  423.  
  424.  
  425.       int ok = atapi.read_atapi_id(dev->idsector, 0);
  426.       atapi.close();
  427.       if (!ok)
  428.       {
  429.           color(CONSCLR_ERROR);
  430.           printf("identification failed\n");
  431.           continue;
  432.       }
  433.       if (ok < 2)
  434.           continue; // not a CD-ROM
  435.  
  436.       print_device_name(dev->viewname, dev);
  437.       res++;
  438.    }
  439.  
  440.    return res;
  441. }
  442.  
  443. int ATAPI_PASSER::pass_through(void *databuf, int bufsize)
  444. {
  445.    int res = (conf.cd_aspi)? SEND_ASPI_CMD(databuf, bufsize) : SEND_SPTI_CMD(databuf, bufsize);
  446.    return res;
  447. }
  448.  
  449. int ATAPI_PASSER::SEND_SPTI_CMD(void *databuf, int bufsize)
  450. {
  451.    memset(databuf, 0, bufsize);
  452.  
  453.    struct {
  454.       SCSI_PASS_THROUGH_DIRECT p;
  455.       unsigned char sense[MAX_SENSE_LEN];
  456.    } srb = { 0 }, dst;
  457.  
  458.    srb.p.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
  459.    *(CDB*)&srb.p.Cdb = cdb;
  460.    srb.p.CdbLength = sizeof(CDB);
  461.    srb.p.DataIn = SCSI_IOCTL_DATA_IN;
  462.    srb.p.TimeOutValue = 10;
  463.    srb.p.DataBuffer = databuf;
  464.    srb.p.DataTransferLength = bufsize;
  465.    srb.p.SenseInfoLength = sizeof(srb.sense);
  466.    srb.p.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT);
  467.  
  468.    DWORD outsize;
  469.    int r = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT,
  470.                            &srb.p, sizeof(srb.p),
  471.                            &dst, sizeof(dst),
  472.                            &outsize, 0);
  473.  
  474.    if (!r) { return 0; }
  475.  
  476.    passed_length = dst.p.DataTransferLength;
  477.    if ((senselen = dst.p.SenseInfoLength)) memcpy(sense, dst.sense, senselen);
  478.  
  479. #ifdef DUMP_HDD_IO
  480. printf("sense=%d, data=%d, srbsz=%d/%d, dir=%d. ok%d\n", senselen, passed_length, outsize, sizeof(srb.p), dst.p.DataIn, res);
  481. printf("srb:"); dump1((BYTE*)&dst, outsize);
  482. printf("data:"); dump1((BYTE*)databuf, 0x40);
  483. #endif
  484.  
  485.    return 1;
  486. }
  487.  
  488. int ATAPI_PASSER::read_atapi_id(unsigned char *idsector, char prefix)
  489. {
  490.    memset(&cdb, 0, sizeof(CDB));
  491.    memset(idsector, 0, 512);
  492.  
  493.    INQUIRYDATA inq;
  494.    cdb.CDB6INQUIRY.OperationCode = 0x12; // INQUIRY
  495.    cdb.CDB6INQUIRY.AllocationLength = sizeof(inq);
  496.    if (!pass_through(&inq, sizeof(inq))) return 0;
  497.  
  498.    char vendor[10], product[18], revision[6], id[22], ata_name[26];
  499.  
  500.    memcpy(vendor, inq.VendorId, sizeof(inq.VendorId)); vendor[sizeof(inq.VendorId)] = 0;
  501.    memcpy(product, inq.ProductId, sizeof(inq.ProductId)); product[sizeof(inq.ProductId)] = 0;
  502.    memcpy(revision, inq.ProductRevisionLevel, sizeof(inq.ProductRevisionLevel)); revision[sizeof(inq.ProductRevisionLevel)] = 0;
  503.    memcpy(id, inq.VendorSpecific, sizeof(inq.VendorSpecific)); id[sizeof(inq.VendorSpecific)] = 0;
  504.  
  505.    if (prefix) {
  506.       color(CONSCLR_HARDITEM);
  507.       if (dev->type == ATA_ASPI_CD) printf("%d.%d: ", dev->adapterid, dev->targetid);
  508.       if (dev->type == ATA_SPTI_CD) printf("cd%d: ", dev->spti_id);
  509.    }
  510.  
  511.    trim(vendor); trim(product); trim(revision); trim(id);
  512.    sprintf(ata_name, "%s %s", vendor, product);
  513.  
  514.    idsector[0] = 0xC0; // removable, accelerated DRQ, 12-byte packet
  515.    idsector[1] = 0x85; // protocol: ATAPI, device type: CD-ROM
  516.  
  517.    make_ata_string(idsector+54, 20, ata_name);
  518.    make_ata_string(idsector+20, 10, id);
  519.    make_ata_string(idsector+46,  4, revision);
  520.  
  521.    idsector[0x63] = 0x0B; // caps: IORDY,LBA,DMA
  522.    idsector[0x67] = 4; // PIO timing
  523.    idsector[0x69] = 2; // DMA timing
  524.  
  525.    if (inq.DeviceType == 5) color(CONSCLR_HARDINFO);
  526.    printf("%-40s %-20s  ", ata_name, id);
  527.    color(CONSCLR_HARDITEM);
  528.    printf("rev.%-4s\n", revision);
  529.  
  530.    return 1 + (inq.DeviceType == 5);
  531. }
  532.  
  533. bool ATAPI_PASSER::read_sector(unsigned char *dst)
  534. {
  535.    DWORD sz = 0;
  536.    if (!ReadFile(hDevice, dst, 2048, &sz, 0))
  537.        return false;
  538.    if (sz < 2048)
  539.        memset(dst+sz, 0, 2048-sz); // on EOF, or truncated file, read 00
  540.    return true;
  541. }
  542.  
  543. bool ATAPI_PASSER::seek(unsigned nsector)
  544. {
  545.    LARGE_INTEGER offset;
  546.    offset.QuadPart = i64(nsector) * 2048;
  547.    DWORD code = SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
  548.    return (code != INVALID_SET_FILE_POINTER || GetLastError() == NO_ERROR);
  549. }
  550.  
  551. void make_ata_string(unsigned char *dst, unsigned n_words, const char *src)
  552. {
  553.    unsigned i; //Alone Coder 0.36.7
  554.    for (/*unsigned*/ i = 0; i < n_words*2 && src[i]; i++) dst[i] = src[i];
  555.    while (i < n_words*2) dst[i++] = ' ';
  556.    unsigned char tmp;
  557.    for (i = 0; i < n_words*2; i += 2)
  558.       tmp = dst[i], dst[i] = dst[i+1], dst[i+1] = tmp;
  559. }
  560.  
  561. void swap_bytes(char *dst, BYTE *src, unsigned n_words)
  562. {
  563.    unsigned i; //Alone Coder 0.36.7
  564.    for (/*unsigned*/ i = 0; i < n_words; i++)
  565.    {
  566.       char c1 = src[2*i], c2 = src[2*i+1];
  567.       dst[2*i] = c2, dst[2*i+1] = c1;
  568.    }
  569.    dst[2*i] = 0;
  570.    trim(dst);
  571. }
  572.  
  573. void print_device_name(char *dst, PHYS_DEVICE *dev)
  574. {
  575.    char model[42], serial[22];
  576.    swap_bytes(model, dev->idsector + 54, 20);
  577.    swap_bytes(serial, dev->idsector + 20, 10);
  578.    sprintf(dst, "<%s,%s>", model, serial);
  579. }
  580.  
  581. void init_aspi()
  582. {
  583.    if (_SendASPI32Command)
  584.        return;
  585.    hAspiDll = LoadLibrary("WNASPI32.DLL");
  586.    if (!hAspiDll)
  587.    {
  588.        errmsg("failed to load WNASPI32.DLL");
  589.        err_win32();
  590.        exit();
  591.    }
  592.    _GetASPI32SupportInfo = (GetASPI32SupportInfo_t)GetProcAddress(hAspiDll, "GetASPI32SupportInfo");
  593.    _SendASPI32Command = (SendASPI32Command_t)GetProcAddress(hAspiDll, "SendASPI32Command");
  594.    if (!_GetASPI32SupportInfo || !_SendASPI32Command) errexit("invalid ASPI32 library");
  595.    DWORD init = _GetASPI32SupportInfo();
  596.    if (((init >> 8) & 0xFF) != SS_COMP)
  597.        errexit("error in ASPI32 initialization");
  598.    hASPICompletionEvent = CreateEvent(0,0,0,0);
  599. }
  600.  
  601. int ATAPI_PASSER::SEND_ASPI_CMD(void *buf, int buf_sz)
  602. {
  603.    SRB_ExecSCSICmd SRB = { 0 };
  604.    SRB.SRB_Cmd        = SC_EXEC_SCSI_CMD;
  605.    SRB.SRB_HaId       = (unsigned char)dev->adapterid;
  606.    SRB.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT;
  607.    SRB.SRB_Target     = (unsigned char)dev->targetid;
  608.    SRB.SRB_BufPointer = (unsigned char*)buf;
  609.    SRB.SRB_BufLen     = buf_sz;
  610.    SRB.SRB_SenseLen   = sizeof(SRB.SenseArea);
  611.    SRB.SRB_CDBLen     = ATAPI_CDB_SIZE;
  612.    SRB.SRB_PostProc   = hASPICompletionEvent;
  613.    memcpy(SRB.CDBByte, &cdb, ATAPI_CDB_SIZE);
  614.  
  615.    /* DWORD ASPIStatus = */ _SendASPI32Command(&SRB);
  616.    passed_length = SRB.SRB_BufLen;
  617.  
  618.    if (SRB.SRB_Status == SS_PENDING)
  619.    {
  620.       DWORD ASPIEventStatus = WaitForSingleObject(hASPICompletionEvent, 10000); // timeout 10sec
  621.       if (ASPIEventStatus == WAIT_OBJECT_0)
  622.           ResetEvent(hASPICompletionEvent);
  623.    }
  624.    if (senselen = SRB.SRB_SenseLen)
  625.        memcpy(sense, SRB.SenseArea, senselen);
  626.    if (temp.win9x)
  627.        senselen = 0; //Alone Coder //makes possible to read one CD sector in win9x
  628.    if (/*(temp.win9x)&&*/(passed_length >= 0xffff))
  629.        passed_length = 2048; //Alone Coder //was >=65535 in win9x //makes possible to work in win9x (HDDoct, WDC, Time Gal) //XP fails too
  630.  
  631. #ifdef DUMP_HDD_IO
  632. printf("sense=%d, data=%d/%d, ok%d\n", senselen, passed_length, buf_sz, SRB.SRB_Status);
  633. printf("srb:"); dump1((BYTE*)&SRB, sizeof(SRB));
  634. printf("data:"); dump1((BYTE*)buf, 0x40);
  635. #endif
  636.  
  637.    return (SRB.SRB_Status == SS_COMP);
  638. }
  639.  
  640. void done_aspi()
  641. {
  642.    if (!hAspiDll)
  643.        return;
  644.    FreeLibrary(hAspiDll);
  645.    CloseHandle(hASPICompletionEvent);
  646. }
  647.