First Commit of my working state
[simh.git] / AltairZ80 / s100_disk2.c
CommitLineData
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
62typedef 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
70static SECTOR_FORMAT sdata;\r
71\r
72typedef 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
83typedef 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
104static DISK2_INFO disk2_info_data = { { 0x0, 0, 0xC8, 2 } };\r
105static DISK2_INFO *disk2_info = &disk2_info_data;\r
106\r
107extern uint32 PCX;\r
108extern REG *sim_PC;\r
109extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);\r
110extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);\r
111extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r
112 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r
113extern int32 selchan_dma(uint8 *buf, uint32 len);\r
114extern int32 find_unit_index(UNIT *uptr);\r
115\r
116/* These are needed for DMA. PIO Mode has not been implemented yet. */\r
117extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);\r
118extern 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
129static t_stat disk2_reset(DEVICE *disk2_dev);\r
130static t_stat disk2_attach(UNIT *uptr, char *cptr);\r
131static t_stat disk2_detach(UNIT *uptr);\r
132\r
133static int32 disk2dev(const int32 port, const int32 io, const int32 data);\r
134\r
135static uint8 DISK2_Read(const uint32 Addr);\r
136static uint8 DISK2_Write(const uint32 Addr, uint8 cData);\r
137\r
138static int32 trace_level = 0; /* Disable all tracing by default */\r
139\r
140static 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
147static REG disk2_reg[] = {\r
148 { HRDATA (TRACELEVEL, trace_level, 16), },\r
149 { NULL }\r
150};\r
151\r
152static 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
163DEVICE 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
173static 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
191static 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
267t_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
289static 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
303static 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
356static 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