OSDN Git Service

[VM][Qt] Fix FTBFSs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / scsi_hdd.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2016.03.01-
6
7         [ SCSI hard disk drive ]
8 */
9
10 #include "scsi_hdd.h"
11 #include "../fifo.h"
12
13 void SCSI_HDD::initialize_max_logical_block_addr()
14 {
15         if(max_logical_block_addr == 0) {
16                 FILEIO* fio = new FILEIO();
17                 uint32_t file_size = 0;
18                 
19                 if(default_drive_size == 0) {
20                         default_drive_size = 0x2800000; // 40MB
21                 }
22                 if(FILEIO::IsFileExisting(create_local_path(_T("SCSI%d.DAT"), scsi_id))) {
23                         if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_WRITE_BINARY)) {
24                                 if((file_size = fio->FileLength()) == 0) {
25                                         uint32_t remain = (file_size = default_drive_size);
26                                         void *tmp = calloc(1, SCSI_BUFFER_SIZE);
27                                         while(remain > 0) {
28                                                 uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
29                                                 fio->Fwrite(tmp, length, 1);
30                                                 remain -= length;
31                                         }
32                                         free(tmp);
33                                 }
34                                 fio->Fclose();
35                         }
36                 } else {
37                         if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_WRITE_BINARY)) {
38                                 uint32_t remain = (file_size = default_drive_size);
39                                 void *tmp = calloc(1, SCSI_BUFFER_SIZE);
40                                 while(remain > 0) {
41                                         uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
42                                         fio->Fwrite(tmp, length, 1);
43                                         remain -= length;
44                                 }
45                                 free(tmp);
46                                 fio->Fclose();
47                         }
48                 }
49                 if(file_size != 0) {
50                         max_logical_block_addr = (file_size / logical_block_size) - 1;
51                 }
52                 delete fio;
53         }
54 }
55
56 void SCSI_HDD::start_command()
57 {
58         switch(command[0]) {
59         case SCSI_CMD_INQUIRY:
60                 #ifdef _SCSI_DEBUG_LOG
61                         emu->out_debug_log(_T("[SCSI_HDD:ID=%d] Command: Inquiry\n"), scsi_id);
62                 #endif
63                 // start position
64                 position = ((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]) * logical_block_size;
65                 // transfer length
66                 remain = 32;
67                 // create sense data table
68                 buffer->clear();
69                 buffer->write(0x00);
70                 buffer->write(0x00);
71                 buffer->write(0x02); // ANSI SCSI2
72                 buffer->write(0x01); // ANSI-CCS
73                 buffer->write(0x1c);
74                 buffer->write(0x00);
75                 buffer->write(0x00);
76                 buffer->write(0x18);
77                 for(int i = 0; i < (int)strlen(vendor_id) && i < 8; i++) {
78                         buffer->write(vendor_id[i]);
79                 }
80                 for(int i = strlen(vendor_id); i < 8; i++) {
81                         buffer->write(0x20);
82                 }
83                 for(int i = 0; i < (int)strlen(product_id) && i < 16; i++) {
84                         buffer->write(vendor_id[i]);
85                 }
86                 for(int i = strlen(product_id); i < 16; i++) {
87                         buffer->write(0x20);
88                 }
89                 // set first data
90                 set_dat(buffer->read());
91                 // change to data in phase
92                 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
93                 break;
94                 
95         case SCSI_CMD_RD_CAPAC:
96                 #ifdef _SCSI_DEBUG_LOG
97                         emu->out_debug_log(_T("[SCSI_HDD:ID=%d] Command: Read Capacity\n"), scsi_id);
98                 #endif
99                 // initialize max logical block address
100                 initialize_max_logical_block_addr();
101                 // start position
102                 position = (command[2] * 0x1000000 + command[3] * 0x10000 + command[4] * 0x100 + command[5]) * logical_block_size;
103                 // transfer length
104                 remain = 8;
105                 // create capacity data table
106                 buffer->clear();
107                 buffer->write((max_logical_block_addr >> 24) & 0xff);
108                 buffer->write((max_logical_block_addr >> 16) & 0xff);
109                 buffer->write((max_logical_block_addr >>  8) & 0xff);
110                 buffer->write((max_logical_block_addr >>  0) & 0xff);
111                 buffer->write((    logical_block_size >> 24) & 0xff);
112                 buffer->write((    logical_block_size >> 16) & 0xff);
113                 buffer->write((    logical_block_size >>  8) & 0xff);
114                 buffer->write((    logical_block_size >>  0) & 0xff);
115                 // set first data
116                 set_dat(buffer->read());
117                 // change to data in phase
118                 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
119                 break;
120                 
121         default:
122                 SCSI_DEV::start_command();
123                 break;
124         }
125 }
126
127 void SCSI_HDD::read_buffer(int length)
128 {
129         // make sure drive size is not zero
130         initialize_max_logical_block_addr();
131         
132         // read blocks
133         FILEIO* fio = new FILEIO();
134         if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_BINARY)) {
135                 // FIXME: consider the case that disk size is bigger than MAX_LONG
136                 fio->Fseek((long)position, FILEIO_SEEK_SET);
137                 while(length > 0) {
138                         uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
139                         int tmp_length = min(length, (int)sizeof(tmp_buffer));
140                         
141                         fio->Fread(tmp_buffer, tmp_length, 1);
142                         for(int i = 0; i < tmp_length; i++) {
143                                 buffer->write(tmp_buffer[i]);
144                         }
145                         length -= tmp_length;
146                         position += tmp_length;
147                 }
148                 fio->Fclose();
149         }
150         delete fio;
151 }
152
153 void SCSI_HDD::write_buffer(int length)
154 {
155         // make sure drive size is not zero
156         initialize_max_logical_block_addr();
157         
158         // write blocks
159         FILEIO* fio = new FILEIO();
160         if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_WRITE_BINARY)) {
161                 // FIXME: consider the case that disk size is bigger than MAX_LONG
162                 fio->Fseek((long)position, FILEIO_SEEK_SET);
163                 while(length > 0) {
164                         uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
165                         int tmp_length = min(length, (int)sizeof(tmp_buffer));
166                         
167                         for(int i = 0; i < tmp_length; i++) {
168                                 tmp_buffer[i] = buffer->read();
169                         }
170                         fio->Fwrite(tmp_buffer, tmp_length, 1);
171                         length -= tmp_length;
172                         position += tmp_length;
173                 }
174                 fio->Fclose();
175         }
176         delete fio;
177 }
178