Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /*************************************************************************\r |
2 | * *\r | |
3 | * $Id: s100_disk2.c 1771 2008-01-09 07:10:46Z hharte $ *\r | |
4 | * *\r | |
5 | * Copyright (c) 2007-2008 Howard M. Harte. *\r | |
6 | * http://www.hartetec.com *\r | |
7 | * *\r | |
8 | * Permission is hereby granted, free of charge, to any person obtaining *\r | |
9 | * a copy of this software and associated documentation files (the *\r | |
10 | * "Software"), to deal in the Software without restriction, including *\r | |
11 | * without limitation the rights to use, copy, modify, merge, publish, *\r | |
12 | * distribute, sublicense, and/or sell copies of the Software, and to *\r | |
13 | * permit persons to whom the Software is furnished to do so, subject to *\r | |
14 | * the following conditions: *\r | |
15 | * *\r | |
16 | * The above copyright notice and this permission notice shall be *\r | |
17 | * included in all copies or substantial portions of the Software. *\r | |
18 | * *\r | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *\r | |
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *\r | |
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *\r | |
22 | * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *\r | |
23 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *\r | |
24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *\r | |
25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *\r | |
26 | * *\r | |
27 | * Except as contained in this notice, the name of Howard M. Harte shall *\r | |
28 | * not be used in advertising or otherwise to promote the sale, use or *\r | |
29 | * other dealings in this Software without prior written authorization *\r | |
30 | * Howard M. Harte. *\r | |
31 | * *\r | |
32 | * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *\r | |
33 | * *\r | |
34 | * Module Description: *\r | |
35 | * CompuPro DISK2 Hard Disk Controller module for SIMH. *\r | |
36 | * This module must be used in conjunction with the CompuPro Selector *\r | |
37 | * Channel Module for proper operation. *\r | |
38 | * *\r | |
39 | * Environment: *\r | |
40 | * User mode only *\r | |
41 | * *\r | |
42 | *************************************************************************/\r | |
43 | \r | |
44 | #include "altairz80_defs.h"\r | |
45 | \r | |
46 | #if defined (_WIN32)\r | |
47 | #include <windows.h>\r | |
48 | #endif\r | |
49 | \r | |
50 | #include "sim_imd.h"\r | |
51 | \r | |
52 | #define SEEK_MSG 0x01\r | |
53 | #define BUG_MSG 0x02\r | |
54 | #define CMD_MSG 0x04\r | |
55 | #define RD_DATA_MSG 0x08\r | |
56 | #define WR_DATA_MSG 0x10\r | |
57 | #define STATUS_MSG 0x20\r | |
58 | #define VERBOSE_MSG 0x80\r | |
59 | \r | |
60 | #define DISK2_MAX_DRIVES 4\r | |
61 | \r | |
62 | typedef union {\r | |
63 | uint8 raw[2051];\r | |
64 | struct {\r | |
65 | uint8 header[3];\r | |
66 | uint8 data[2048];\r | |
67 | } u;\r | |
68 | } SECTOR_FORMAT;\r | |
69 | \r | |
70 | static SECTOR_FORMAT sdata;\r | |
71 | \r | |
72 | typedef struct {\r | |
73 | UNIT *uptr;\r | |
74 | DISK_INFO *imd;\r | |
75 | uint16 ntracks; /* number of tracks */\r | |
76 | uint8 nheads; /* number of heads */\r | |
77 | uint8 nsectors; /* number of sectors/track */\r | |
78 | uint32 sectsize; /* sector size, not including pre/postamble */\r | |
79 | uint16 track; /* Current Track */\r | |
80 | uint8 ready; /* Is drive ready? */\r | |
81 | } DISK2_DRIVE_INFO;\r | |
82 | \r | |
83 | typedef struct {\r | |
84 | PNP_INFO pnp; /* Plug and Play */\r | |
85 | uint8 sel_drive; /* Currently selected drive */\r | |
86 | uint8 head_sel; /* Head select (signals to drive itself) */\r | |
87 | uint8 head; /* Head set by write to the HEAD register */\r | |
88 | uint8 cyl; /* Cyl that the current operation is targetting */\r | |
89 | uint8 sector; /* Sector the current READ/WRITE operation is targetting */\r | |
90 | uint8 hdr_sector; /* Current sector for WRITE_HEADER */\r | |
91 | uint8 ctl_attn;\r | |
92 | uint8 ctl_run;\r | |
93 | uint8 ctl_op;\r | |
94 | uint8 ctl_fault_clr;\r | |
95 | uint8 ctl_us;\r | |
96 | uint8 timeout;\r | |
97 | uint8 crc_error;\r | |
98 | uint8 overrun;\r | |
99 | uint8 seek_complete;\r | |
100 | uint8 write_fault;\r | |
101 | DISK2_DRIVE_INFO drive[DISK2_MAX_DRIVES];\r | |
102 | } DISK2_INFO;\r | |
103 | \r | |
104 | static DISK2_INFO disk2_info_data = { { 0x0, 0, 0xC8, 2 } };\r | |
105 | static DISK2_INFO *disk2_info = &disk2_info_data;\r | |
106 | \r | |
107 | extern uint32 PCX;\r | |
108 | extern REG *sim_PC;\r | |
109 | extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
110 | extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
111 | extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r | |
112 | int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r | |
113 | extern int32 selchan_dma(uint8 *buf, uint32 len);\r | |
114 | extern int32 find_unit_index(UNIT *uptr);\r | |
115 | \r | |
116 | /* These are needed for DMA. PIO Mode has not been implemented yet. */\r | |
117 | extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);\r | |
118 | extern uint8 GetBYTEWrapper(const uint32 Addr);\r | |
119 | \r | |
120 | #define UNIT_V_DISK2_WLK (UNIT_V_UF + 0) /* write locked */\r | |
121 | #define UNIT_DISK2_WLK (1 << UNIT_V_DISK2_WLK)\r | |
122 | #define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */\r | |
123 | #define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE)\r | |
124 | #define DISK2_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */\r | |
125 | #define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */\r | |
126 | #define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */\r | |
127 | #define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */\r | |
128 | \r | |
129 | static t_stat disk2_reset(DEVICE *disk2_dev);\r | |
130 | static t_stat disk2_attach(UNIT *uptr, char *cptr);\r | |
131 | static t_stat disk2_detach(UNIT *uptr);\r | |
132 | \r | |
133 | static int32 disk2dev(const int32 port, const int32 io, const int32 data);\r | |
134 | \r | |
135 | static uint8 DISK2_Read(const uint32 Addr);\r | |
136 | static uint8 DISK2_Write(const uint32 Addr, uint8 cData);\r | |
137 | \r | |
138 | static int32 trace_level = 0; /* Disable all tracing by default */\r | |
139 | \r | |
140 | static UNIT disk2_unit[] = {\r | |
141 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) },\r | |
142 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) },\r | |
143 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) },\r | |
144 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) }\r | |
145 | };\r | |
146 | \r | |
147 | static REG disk2_reg[] = {\r | |
148 | { HRDATA (TRACELEVEL, trace_level, 16), },\r | |
149 | { NULL }\r | |
150 | };\r | |
151 | \r | |
152 | static MTAB disk2_mod[] = {\r | |
153 | { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },\r | |
154 | { UNIT_DISK2_WLK, 0, "WRTENB", "WRTENB", NULL },\r | |
155 | { UNIT_DISK2_WLK, UNIT_DISK2_WLK, "WRTLCK", "WRTLCK", NULL },\r | |
156 | /* quiet, no warning messages */\r | |
157 | { UNIT_DISK2_VERBOSE, 0, "QUIET", "QUIET", NULL },\r | |
158 | /* verbose, show warning messages */\r | |
159 | { UNIT_DISK2_VERBOSE, UNIT_DISK2_VERBOSE, "VERBOSE", "VERBOSE", NULL },\r | |
160 | { 0 }\r | |
161 | };\r | |
162 | \r | |
163 | DEVICE disk2_dev = {\r | |
164 | "DISK2", disk2_unit, disk2_reg, disk2_mod,\r | |
165 | DISK2_MAX_DRIVES, 10, 31, 1, DISK2_MAX_DRIVES, DISK2_MAX_DRIVES,\r | |
166 | NULL, NULL, &disk2_reset,\r | |
167 | NULL, &disk2_attach, &disk2_detach,\r | |
168 | &disk2_info_data, (DEV_DISABLE | DEV_DIS), 0,\r | |
169 | NULL, NULL, NULL\r | |
170 | };\r | |
171 | \r | |
172 | /* Reset routine */\r | |
173 | static t_stat disk2_reset(DEVICE *dptr)\r | |
174 | {\r | |
175 | PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r | |
176 | \r | |
177 | if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */\r | |
178 | sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk2dev, TRUE);\r | |
179 | } else {\r | |
180 | /* Connect DISK2 at base address */\r | |
181 | if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk2dev, FALSE) != 0) {\r | |
182 | printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);\r | |
183 | return SCPE_ARG;\r | |
184 | }\r | |
185 | }\r | |
186 | return SCPE_OK;\r | |
187 | }\r | |
188 | \r | |
189 | \r | |
190 | /* Attach routine */\r | |
191 | static t_stat disk2_attach(UNIT *uptr, char *cptr)\r | |
192 | {\r | |
193 | t_stat r = SCPE_OK;\r | |
194 | DISK2_DRIVE_INFO *pDrive;\r | |
195 | char header[4];\r | |
196 | unsigned int i = 0;\r | |
197 | \r | |
198 | i = find_unit_index(uptr);\r | |
199 | if (i == -1) {\r | |
200 | return (SCPE_IERR);\r | |
201 | }\r | |
202 | pDrive = &disk2_info->drive[i];\r | |
203 | \r | |
204 | pDrive->ready = 1;\r | |
205 | disk2_info->write_fault = 1;\r | |
206 | pDrive->track = 5;\r | |
207 | pDrive->ntracks = 243;\r | |
208 | pDrive->nheads = 8;\r | |
209 | pDrive->nsectors = 11;\r | |
210 | pDrive->sectsize = 1024;\r | |
211 | \r | |
212 | r = attach_unit(uptr, cptr); /* attach unit */\r | |
213 | if ( r != SCPE_OK) /* error? */\r | |
214 | return r;\r | |
215 | \r | |
216 | /* Determine length of this disk */\r | |
217 | if(sim_fsize(uptr->fileref) != 0) {\r | |
218 | uptr->capac = sim_fsize(uptr->fileref);\r | |
219 | } else {\r | |
220 | uptr->capac = (pDrive->ntracks * pDrive->nsectors * pDrive->nheads * pDrive->sectsize);\r | |
221 | }\r | |
222 | \r | |
223 | pDrive->uptr = uptr;\r | |
224 | \r | |
225 | /* Default for new file is DSK */\r | |
226 | uptr->u3 = IMAGE_TYPE_DSK;\r | |
227 | \r | |
228 | if(uptr->capac > 0) {\r | |
229 | fgets(header, 4, uptr->fileref);\r | |
230 | if(!strcmp(header, "IMD")) {\r | |
231 | uptr->u3 = IMAGE_TYPE_IMD;\r | |
232 | } else if(!strcmp(header, "CPT")) {\r | |
233 | printf("CPT images not yet supported\n");\r | |
234 | uptr->u3 = IMAGE_TYPE_CPT;\r | |
235 | disk2_detach(uptr);\r | |
236 | return SCPE_OPENERR;\r | |
237 | } else {\r | |
238 | uptr->u3 = IMAGE_TYPE_DSK;\r | |
239 | }\r | |
240 | }\r | |
241 | \r | |
242 | if (uptr->flags & UNIT_DISK2_VERBOSE)\r | |
243 | printf("DISK2%d, attached to '%s', type=%s, len=%d\n", i, cptr,\r | |
244 | uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",\r | |
245 | uptr->capac);\r | |
246 | \r | |
247 | if(uptr->u3 == IMAGE_TYPE_IMD) {\r | |
248 | if(uptr->capac < 318000) {\r | |
249 | printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n");\r | |
250 | disk2_detach(uptr);\r | |
251 | return SCPE_OPENERR;\r | |
252 | }\r | |
253 | \r | |
254 | if (uptr->flags & UNIT_DISK2_VERBOSE)\r | |
255 | printf("--------------------------------------------------------\n");\r | |
256 | disk2_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_DISK2_VERBOSE));\r | |
257 | if (uptr->flags & UNIT_DISK2_VERBOSE) printf("\n");\r | |
258 | } else {\r | |
259 | disk2_info->drive[i].imd = NULL;\r | |
260 | }\r | |
261 | \r | |
262 | return SCPE_OK;\r | |
263 | }\r | |
264 | \r | |
265 | \r | |
266 | /* Detach routine */\r | |
267 | t_stat disk2_detach(UNIT *uptr)\r | |
268 | {\r | |
269 | t_stat r;\r | |
270 | int8 i;\r | |
271 | \r | |
272 | i = find_unit_index(uptr);\r | |
273 | \r | |
274 | if (i == -1) {\r | |
275 | return (SCPE_IERR);\r | |
276 | }\r | |
277 | \r | |
278 | if (uptr->flags & UNIT_DISK2_VERBOSE)\r | |
279 | printf("Detach DISK2%d\n", i);\r | |
280 | \r | |
281 | r = detach_unit(uptr); /* detach unit */\r | |
282 | if ( r != SCPE_OK)\r | |
283 | return r;\r | |
284 | \r | |
285 | return SCPE_OK;\r | |
286 | }\r | |
287 | \r | |
288 | \r | |
289 | static int32 disk2dev(const int32 port, const int32 io, const int32 data)\r | |
290 | {\r | |
291 | /* TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */\r | |
292 | if(io) {\r | |
293 | DISK2_Write(port, data);\r | |
294 | return 0;\r | |
295 | } else {\r | |
296 | return(DISK2_Read(port));\r | |
297 | }\r | |
298 | }\r | |
299 | \r | |
300 | #define DISK2_CSR 0 /* R=DISK2 Status / W=DISK2 Control Register */\r | |
301 | #define DISK2_DATA 1 /* R=Step Pulse / W=Write Data Register */\r | |
302 | \r | |
303 | static uint8 DISK2_Read(const uint32 Addr)\r | |
304 | {\r | |
305 | uint8 cData;\r | |
306 | DISK2_DRIVE_INFO *pDrive;\r | |
307 | \r | |
308 | pDrive = &disk2_info->drive[disk2_info->sel_drive];\r | |
309 | cData = 0x00;\r | |
310 | \r | |
311 | switch(Addr & 0x1) {\r | |
312 | case DISK2_CSR:\r | |
313 | cData = (disk2_info->ctl_attn) << 7;\r | |
314 | cData |= (disk2_info->timeout) << 6;\r | |
315 | cData |= (disk2_info->crc_error) << 5;\r | |
316 | cData |= (disk2_info->overrun) << 4;\r | |
317 | cData |= (pDrive->ready == 0) ? 0x08 : 0x00;\r | |
318 | cData |= (disk2_info->seek_complete == 0) ? 0x04 : 0x00;\r | |
319 | cData |= (disk2_info->write_fault) << 1;\r | |
320 | cData |= ((pDrive->track != 0) || (disk2_info->seek_complete == 0)) ? 0x01 : 0x00;\r | |
321 | TRACE_PRINT(STATUS_MSG, ("DISK2: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData));\r | |
322 | \r | |
323 | disk2_info->seek_complete = 1;\r | |
324 | break;\r | |
325 | case DISK2_DATA:\r | |
326 | if(disk2_info->ctl_op & 0x04) {\r | |
327 | if(pDrive->track < pDrive->ntracks) {\r | |
328 | pDrive->track ++;\r | |
329 | }\r | |
330 | } else {\r | |
331 | if(pDrive->track > 0) {\r | |
332 | pDrive->track --;\r | |
333 | }\r | |
334 | }\r | |
335 | TRACE_PRINT(SEEK_MSG, ("DISK2: " ADDRESS_FORMAT " Step %s, Track=%d" NLP,\r | |
336 | PCX, disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track));\r | |
337 | disk2_info->seek_complete = 0;\r | |
338 | cData = 0xFF; /* Return High-Z data */\r | |
339 | break;\r | |
340 | }\r | |
341 | \r | |
342 | return (cData);\r | |
343 | }\r | |
344 | \r | |
345 | #define DISK2_OP_DRIVE 0x00\r | |
346 | #define DISK2_OP_CYL 0x01\r | |
347 | #define DISK2_OP_HEAD 0x02\r | |
348 | #define DISK2_OP_SECTOR 0x03\r | |
349 | \r | |
350 | #define DISK2_CMD_NULL 0x00\r | |
351 | #define DISK2_CMD_READ_DATA 0x01\r | |
352 | #define DISK2_CMD_WRITE_DATA 0x02\r | |
353 | #define DISK2_CMD_WRITE_HEADER 0x03\r | |
354 | #define DISK2_CMD_READ_HEADER 0x04\r | |
355 | \r | |
356 | static uint8 DISK2_Write(const uint32 Addr, uint8 cData)\r | |
357 | {\r | |
358 | uint32 track_offset;\r | |
359 | uint8 result = 0;\r | |
360 | uint8 i;\r | |
361 | long file_offset;\r | |
362 | DISK2_DRIVE_INFO *pDrive;\r | |
363 | \r | |
364 | pDrive = &disk2_info->drive[disk2_info->sel_drive];\r | |
365 | \r | |
366 | switch(Addr & 0x1) {\r | |
367 | case DISK2_CSR: /* Write CTL register */\r | |
368 | disk2_info->ctl_attn = (cData & 0x80) >> 7;\r | |
369 | disk2_info->ctl_run = (cData & 0x40) >> 6;\r | |
370 | disk2_info->ctl_op = (cData & 0x38) >> 3;\r | |
371 | disk2_info->ctl_fault_clr = (cData & 0x04) >> 2;\r | |
372 | if(disk2_info->ctl_fault_clr == 1) {\r | |
373 | disk2_info->timeout = 0;\r | |
374 | }\r | |
375 | disk2_info->ctl_us = (cData & 0x03);\r | |
376 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d" NLP,\r | |
377 | PCX,\r | |
378 | disk2_info->ctl_attn,\r | |
379 | disk2_info->ctl_run,\r | |
380 | disk2_info->ctl_op,\r | |
381 | disk2_info->ctl_fault_clr,\r | |
382 | disk2_info->ctl_us));\r | |
383 | \r | |
384 | /* FIXME: seek_complete = 1 is needed by CP/M, but why? Also, maybe related,\r | |
385 | * there appears to be a bug in the seeking logic. For some reason, the\r | |
386 | * pDrive->track does not equal the disk2_info->cyl, when doing READ_DATA and\r | |
387 | * WRITE_DATA commands. For this reason, disk2_info->cyl is used instead of\r | |
388 | * pDrive->track for these commands. For READ_HEADER and WRITE_HEADER,\r | |
389 | * pDrive->track is used, because the DISK2 format program (DISK2.COM) does not\r | |
390 | * issue DISK2_OP_CYL. The root cause of this anomaly needs to be determined,\r | |
391 | * because it is surely a bug in the logic somewhere.\r | |
392 | */\r | |
393 | /* pDrive->track may be different from disk2_info->cyl when a program such as DISK2.COM\r | |
394 | moves the position of the track without informing the CP/M BIOS which stores the\r | |
395 | current track for each drive. This appears to be an application program bug.\r | |
396 | */\r | |
397 | disk2_info->seek_complete = 1;\r | |
398 | \r | |
399 | if(disk2_info->ctl_run == 1) {\r | |
400 | disk2_info->timeout = 0;\r | |
401 | track_offset = disk2_info->cyl * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);\r | |
402 | \r | |
403 | switch(disk2_info->ctl_op) {\r | |
404 | case DISK2_CMD_NULL:\r | |
405 | TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " NULL Command" NLP, PCX));\r | |
406 | break;\r | |
407 | case DISK2_CMD_READ_DATA:\r | |
408 | TRACE_PRINT(RD_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: (C:%d/H:%d/S:%d)" NLP,\r | |
409 | PCX,\r | |
410 | disk2_info->cyl,\r | |
411 | disk2_info->head,\r | |
412 | disk2_info->sector));\r | |
413 | if(disk2_info->head_sel != disk2_info->head) {\r | |
414 | printf("DISK2: " ADDRESS_FORMAT " READ_DATA: head_sel != head" NLP, PCX);\r | |
415 | }\r | |
416 | /* See FIXME above... that might be why this does not work properly... */\r | |
417 | if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */\r | |
418 | TRACE_PRINT(BUG_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: cyl=%d, track=%d" NLP,\r | |
419 | PCX, disk2_info->cyl, pDrive->track));\r | |
420 | pDrive->track = disk2_info->cyl; /* update track */\r | |
421 | }\r | |
422 | fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);\r | |
423 | for(i=0;i<pDrive->nsectors;i++) {\r | |
424 | /* Read sector */\r | |
425 | fread(sdata.raw, (pDrive->sectsize + 3), 1, (pDrive->uptr)->fileref);\r | |
426 | if(sdata.u.header[2] == disk2_info->sector) {\r | |
427 | if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */\r | |
428 | printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX);\r | |
429 | disk2_info->timeout = 1;\r | |
430 | }\r | |
431 | if(sdata.u.header[1] != disk2_info->head) {\r | |
432 | printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: head" NLP, PCX);\r | |
433 | disk2_info->timeout = 1;\r | |
434 | }\r | |
435 | \r | |
436 | selchan_dma(sdata.u.data, pDrive->sectsize);\r | |
437 | break;\r | |
438 | }\r | |
439 | if(i == pDrive->nsectors) {\r | |
440 | printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX);\r | |
441 | disk2_info->timeout = 1;\r | |
442 | }\r | |
443 | }\r | |
444 | \r | |
445 | break;\r | |
446 | case DISK2_CMD_WRITE_DATA:\r | |
447 | TRACE_PRINT(WR_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: (C:%d/H:%d/S:%d)" NLP,\r | |
448 | PCX,\r | |
449 | disk2_info->cyl,\r | |
450 | disk2_info->head,\r | |
451 | disk2_info->sector));\r | |
452 | if(disk2_info->head_sel != disk2_info->head) {\r | |
453 | printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA: head_sel != head" NLP, PCX);\r | |
454 | }\r | |
455 | if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */\r | |
456 | TRACE_PRINT(BUG_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA = 0x%02x, cyl=%d, track=%d" NLP,\r | |
457 | PCX, cData, disk2_info->cyl, pDrive->track));\r | |
458 | pDrive->track = disk2_info->cyl; /* update track */\r | |
459 | }\r | |
460 | \r | |
461 | fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);\r | |
462 | for(i=0;i<pDrive->nsectors;i++) {\r | |
463 | /* Read sector */\r | |
464 | file_offset = ftell((pDrive->uptr)->fileref);\r | |
465 | fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref);\r | |
466 | if(sdata.u.header[2] == disk2_info->sector) {\r | |
467 | if(sdata.u.header[0] != disk2_info->cyl) {\r | |
468 | printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX);\r | |
469 | disk2_info->timeout = 1;\r | |
470 | }\r | |
471 | if(sdata.u.header[1] != disk2_info->head) {\r | |
472 | printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: head" NLP, PCX);\r | |
473 | disk2_info->timeout = 1;\r | |
474 | }\r | |
475 | \r | |
476 | selchan_dma(sdata.u.data, pDrive->sectsize);\r | |
477 | fseek((pDrive->uptr)->fileref, file_offset+3, SEEK_SET);\r | |
478 | fwrite(sdata.u.data, (pDrive->sectsize), 1, (pDrive->uptr)->fileref);\r | |
479 | break;\r | |
480 | }\r | |
481 | fread(sdata.raw, pDrive->sectsize, 1, (pDrive->uptr)->fileref);\r | |
482 | if(i == pDrive->nsectors) {\r | |
483 | printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX);\r | |
484 | disk2_info->timeout = 1;\r | |
485 | }\r | |
486 | }\r | |
487 | break;\r | |
488 | case DISK2_CMD_WRITE_HEADER:\r | |
489 | track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);\r | |
490 | TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d" NLP,\r | |
491 | PCX,\r | |
492 | pDrive->track,\r | |
493 | disk2_info->cyl,\r | |
494 | disk2_info->head_sel,\r | |
495 | disk2_info->hdr_sector));\r | |
496 | \r | |
497 | i = disk2_info->hdr_sector;\r | |
498 | selchan_dma(sdata.raw, 3);\r | |
499 | fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * (pDrive->sectsize + 3) * pDrive->nsectors) + (i * (pDrive->sectsize + 3)), SEEK_SET);\r | |
500 | fwrite(sdata.raw, 3, 1, (pDrive->uptr)->fileref);\r | |
501 | \r | |
502 | disk2_info->hdr_sector++;\r | |
503 | if(disk2_info->hdr_sector >= pDrive->nsectors) {\r | |
504 | disk2_info->hdr_sector = 0;\r | |
505 | disk2_info->timeout = 1;\r | |
506 | }\r | |
507 | break;\r | |
508 | case DISK2_CMD_READ_HEADER:\r | |
509 | track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);\r | |
510 | TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX));\r | |
511 | fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);\r | |
512 | fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref);\r | |
513 | selchan_dma(sdata.raw, 3);\r | |
514 | break;\r | |
515 | default:\r | |
516 | printf("DISK2: " ADDRESS_FORMAT " Unknown CMD=%d" NLP, PCX, disk2_info->ctl_op);\r | |
517 | break;\r | |
518 | }\r | |
519 | \r | |
520 | disk2_info->ctl_attn = 0;\r | |
521 | }\r | |
522 | \r | |
523 | break;\r | |
524 | case DISK2_DATA:\r | |
525 | switch(disk2_info->ctl_op) {\r | |
526 | case DISK2_OP_DRIVE:\r | |
527 | switch(cData >> 4) {\r | |
528 | case 0x01:\r | |
529 | disk2_info->sel_drive = 0;\r | |
530 | break;\r | |
531 | case 0x02:\r | |
532 | disk2_info->sel_drive = 1;\r | |
533 | break;\r | |
534 | case 0x04:\r | |
535 | disk2_info->sel_drive = 2;\r | |
536 | break;\r | |
537 | case 0x08:\r | |
538 | disk2_info->sel_drive = 3;\r | |
539 | break;\r | |
540 | default:\r | |
541 | printf("DISK2: " ADDRESS_FORMAT " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4);\r | |
542 | break;\r | |
543 | }\r | |
544 | \r | |
545 | disk2_info->head_sel = cData & 0x0F;\r | |
546 | \r | |
547 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [DRIVE]=%d, Head=%d" NLP,\r | |
548 | PCX, disk2_info->sel_drive, disk2_info->head));\r | |
549 | break;\r | |
550 | case DISK2_OP_CYL:\r | |
551 | disk2_info->cyl = cData;\r | |
552 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [CYL] = %02x" NLP,\r | |
553 | PCX, cData));\r | |
554 | break;\r | |
555 | case DISK2_OP_HEAD:\r | |
556 | disk2_info->head = cData;\r | |
557 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [HEAD] = %02x" NLP,\r | |
558 | PCX, cData));\r | |
559 | break;\r | |
560 | case DISK2_OP_SECTOR:\r | |
561 | disk2_info->sector = cData;\r | |
562 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register [SECTOR] = %02x" NLP,\r | |
563 | PCX, cData));\r | |
564 | break;\r | |
565 | default:\r | |
566 | TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register unknown op [%d] = %02x" NLP,\r | |
567 | PCX, disk2_info->ctl_op, cData));\r | |
568 | break;\r | |
569 | }\r | |
570 | }\r | |
571 | \r | |
572 | return (result);\r | |
573 | }\r | |
574 | \r |