1 /***************************************************************************
2 * *
3 * LIBDSK: General floppy and diskimage access library *
4 * Copyright (C) 2001-2,2015 John Elliott <seasip.webmaster@gmail.com> *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU Library General Public *
8 * License as published by the Free Software Foundation; either *
9 * version 2 of the License, or (at your option) any later version. *
10 * *
11 * This library is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Library General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Library General Public *
17 * License along with this library; if not, write to the Free *
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
19 * MA 02111-1307, USA *
20 * *
21 ***************************************************************************/
22
23
24 /* Declarations for the JV3 driver */
25
26 /* JV3 spec at <http://www.tim-mann.org/trs80/dskspec.html> */
27
28 #include "drvi.h"
29 #include "drvjv3.h"
30
31
32 DRV_CLASS dc_jv3 =
33 {
34 sizeof(JV3_DSK_DRIVER),
35 "jv3",
36 "JV3 file driver",
37 jv3_open,
38 jv3_creat,
39 jv3_close,
40 jv3_read,
41 jv3_write,
42 jv3_format,
43 jv3_getgeom,
44 jv3_secid,
45 jv3_xseek,
46 jv3_status,
47 jv3_xread,
48 jv3_xwrite,
49 NULL, /* jv3_tread */
50 NULL, /* jv3_xtread */
51 NULL, /* jv3_option_enum */
52 NULL, /* jv3_option_set */
53 NULL, /* jv3_option_get */
54 jv3_trackids,
55 NULL /* jv3_rtread */
56 };
57
58 /* #define MONITOR(x) printf x */
59
60 #define MONITOR(x)
61
62
63 #define DC_CHECK(s) \
64 JV3_DSK_DRIVER *self; \
65 if (s->dr_class != &dc_jv3) return DSK_ERR_BADPTR; \
66 self = (JV3_DSK_DRIVER *)s;
67
68 typedef struct
69 {
70 /* Currently-loaded header block */
71 unsigned char cur_header[JV3_HEADER_LEN];
72
73 /* Its location within the disk file */
74 long header_offset;
75
76 /* Did the callback change anything? */
77 int touched;
78
79 /* Stop processing? */
80 int stop;
81
82 /* Offset of the current sector */
83 long data_offset;
84
85 /* Pointer to the encoded header of the current sector */
86 unsigned char *sector_head;
87
88 /* Location of the current sector, and its flags */
89 dsk_pcyl_t cyl;
90 dsk_phead_t head;
91 dsk_psect_t sector;
92 unsigned char flags;
93 /* Size of the current sector */
94 size_t secsize;
95
96 /* Is the current sector an empty slot? */
97 int isfree;
98 } JV3_ENUM_STATE;
99
100
101 /* If the header in 'st' has been touched, write the changes out */
flush_header(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * st)102 dsk_err_t flush_header(JV3_DSK_DRIVER *self, JV3_ENUM_STATE *st)
103 {
104 long pos;
105
106 if (st->touched)
107 {
108 /* Get current file position */
109 pos = ftell(self->jv3_fp);
110 if (pos < 0) return DSK_ERR_SYSERR;
111
112 /* Seek to the header */
113 if (fseek(self->jv3_fp, st->header_offset, SEEK_SET) < 0)
114 {
115 return DSK_ERR_SYSERR;
116 }
117 /* Write the header */
118 if (fwrite(st->cur_header, 1, JV3_HEADER_LEN, self->jv3_fp)
119 < JV3_HEADER_LEN)
120 {
121 return DSK_ERR_SYSERR;
122 }
123 /* Reset the 'touched' flag */
124 st->touched = 0;
125 /* And seek back to where we were */
126 if (fseek(self->jv3_fp, pos, SEEK_SET) < 0)
127 {
128 return DSK_ERR_SYSERR;
129 }
130 /* Update cached header if appropriate */
131 if (st->header_offset == 0)
132 memcpy(self->jv3_header, st->cur_header, JV3_HEADER_LEN);
133 }
134 return DSK_ERR_OK;
135 }
136
137 /* Decode the 2-bit size code as a sector size. Annoyingly the encoding
138 * is different for used and free sectors */
decode_size(int isfree,unsigned char size)139 static size_t decode_size(int isfree, unsigned char size)
140 {
141 switch (size & JV3_SIZE)
142 {
143 case 0: return (isfree) ? 512 : 256;
144 case 1: return (isfree) ? 1024 : 128;
145 case 2: return (isfree) ? 128 : 1024;
146 case 3: return (isfree) ? 256 : 512;
147 }
148 /* Can't happen */
149 return 256;
150 }
151
152
153 /* Encode the sector size as a 2-bit size code. Annoyingly the encoding
154 * is different for used and free sectors */
encode_size(int isfree,size_t size)155 unsigned char encode_size(int isfree, size_t size)
156 {
157 switch (size)
158 {
159 case 128: return (isfree) ? 2 : 1;
160 default:
161 case 256: return (isfree) ? 3 : 0;
162 case 512: return (isfree) ? 0 : 3;
163 case 1024: return (isfree) ? 1 : 2;
164 }
165 }
166
167
168
169
170
171 typedef dsk_err_t (*JV3_CALLBACK)(JV3_DSK_DRIVER *self,
172 JV3_ENUM_STATE *state, void *param);
173
174 /* Because of the awkward chunked nature of JV3 (it consists of one or more
175 * blocks, each containing 0-JV3_HEADER_COUNT sectors, and you need to parse
176 * each block completely to find the next) this driver uses a callback
177 * mechanism. jv3_enum_sectors() handles all the grubby business of
178 * enumerating each sector in turn
179 *
180 * The function should return DSK_ERR_OK to continue, other values to abort
181 * with error.
182 *
183 * To stop the enumeration set state->stop to nonzero.
184 */
jv3_enum_sectors(JV3_DSK_DRIVER * self,unsigned char append,JV3_CALLBACK cbk,void * param)185 dsk_err_t jv3_enum_sectors(JV3_DSK_DRIVER *self, unsigned char append,
186 JV3_CALLBACK cbk, void *param)
187 {
188 JV3_ENUM_STATE state;
189
190 dsk_err_t err;
191 int n;
192
193 memset(&state, 0, sizeof(state));
194
195 memcpy(state.cur_header, self->jv3_header, JV3_HEADER_LEN);
196 state.header_offset = 0;
197 state.data_offset = JV3_HEADER_LEN;
198
199 while (state.data_offset < self->jv3_len)
200 {
201 for (n = 0; n < JV3_HEADER_COUNT; n++)
202 {
203 state.sector_head = state.cur_header + 3 * n;
204 state.cyl = state.sector_head[0];
205 state.sector = state.sector_head[1];
206 state.flags = state.sector_head[2];
207 state.head = (state.flags & JV3_SIDE) ? 1 : 0;
208 state.isfree = (state.cyl == JV3_FREE
209 && state.sector == JV3_FREE);
210 state.secsize = decode_size(state.isfree, state.flags);
211
212 err = (*cbk)(self, &state, param);
213
214 if (state.stop)
215 {
216 dsk_err_t e2 = flush_header(self, &state);
217 return (err == DSK_ERR_OK) ? e2 : err;
218 }
219
220 state.data_offset += state.secsize;
221 /* If we have reached EOF and 'stop' is not set and 'append' is nonzero,
222 * append a blank sector of the appropriate type */
223
224 if (state.data_offset >= self->jv3_len)
225 {
226 if (append && !state.stop &&
227 n < (JV3_HEADER_COUNT - 1))
228 {
229 /* sector_head points at the last valid sector. If there is space for
230 * another sector in the current header, insert it */
231 state.sector_head += 3;
232 state.sector_head[0] = JV3_FREE;
233 state.sector_head[1] = JV3_FREE;
234 state.sector_head[2] = append;
235 state.flags = append;
236 state.isfree = 1;
237 state.secsize = decode_size(1, append);
238
239 err = (*cbk)(self, &state, param);
240 if (err)
241 {
242 flush_header(self, &state);
243 return err;
244 }
245 append = 0;
246 }
247 break;
248 }
249 }
250 /* Have searched the header to no avail. Try the next
251 * header. */
252 if (fseek(self->jv3_fp, state.data_offset, SEEK_SET) < 0)
253 {
254 flush_header(self, &state);
255 return DSK_ERR_SYSERR;
256 }
257 if (fread(state.cur_header, 1, JV3_HEADER_LEN, self->jv3_fp)
258 < JV3_HEADER_LEN)
259 {
260 flush_header(self, &state);
261 return DSK_ERR_OK;
262 }
263 }
264 err = flush_header(self, &state);
265 if (err) return err;
266
267 /* OK, we need to append a sector, but the existing header is
268 * entirely full. Create a new header and create that. */
269 if (append && !state.stop)
270 {
271 memset(state.cur_header, JV3_FREE, JV3_HEADER_LEN);
272 /* If the last block in the file is a header block,
273 * replace it. Otherwise, append a new header block. */
274 if (state.data_offset > state.header_offset + JV3_HEADER_LEN)
275 {
276 state.header_offset = self->jv3_len;
277 state.data_offset = self->jv3_len + JV3_HEADER_LEN;
278 }
279 state.sector_head = state.cur_header;
280 state.sector_head[0] = JV3_FREE;
281 state.sector_head[1] = JV3_FREE;
282 state.sector_head[2] = append;
283 state.flags = append;
284 state.isfree = 1;
285 state.secsize = decode_size(1, append);
286
287 err = (*cbk)(self, &state, param);
288 if (!err)
289 {
290 return flush_header(self, &state);
291 }
292 else
293 {
294 flush_header(self, &state);
295 return err;
296 }
297 }
298 return DSK_ERR_OK;
299 }
300
301
302
303
304
305 /*
306 dsk_err_t dump_callback(JV3_DSK_DRIVER *self, JV3_ENUM_STATE *state,
307 void *param)
308 {
309 printf("cyl=%02x head=%02x sec=%02x size=%4d offset=%6ld free=%d flags=%02x\n",
310 state->cyl, state->head, state->sector,
311 (int)state->secsize, state->data_offset, state->isfree,
312 state->flags);
313 return DSK_ERR_OK;
314 }*/
315
316
jv3_open(DSK_DRIVER * s,const char * filename)317 dsk_err_t jv3_open(DSK_DRIVER *s, const char *filename)
318 {
319 DC_CHECK(s);
320
321 self->jv3_fp = fopen(filename, "rb");
322 if (!self->jv3_fp) return DSK_ERR_NOTME;
323
324 /* Get file size */
325 if (fseek(self->jv3_fp, 0, SEEK_END) < 0 ||
326 ((self->jv3_len = ftell(self->jv3_fp)) < 0) ||
327 fseek(self->jv3_fp, 0, SEEK_SET) < 0)
328 {
329 return DSK_ERR_NOTME;
330 }
331
332 if (fread(self->jv3_header, 1, sizeof(self->jv3_header), self->jv3_fp)
333 < (int)sizeof(self->jv3_header))
334 {
335 fclose(self->jv3_fp);
336 return DSK_ERR_NOTME;
337 }
338 /* Diagnostic dump of what we just loaded
339 jv3_enum_sectors(self, 0, dump_callback, NULL);
340 */
341 /* OK, the header loaded. There's no magic number or other
342 * metadata we can check, so just assume it worked */
343 return DSK_ERR_OK;
344 }
345
jv3_creat(DSK_DRIVER * s,const char * filename)346 dsk_err_t jv3_creat(DSK_DRIVER *s, const char *filename)
347 {
348 DC_CHECK(s);
349
350 self->jv3_fp = fopen(filename, "wb");
351 if (!self->jv3_fp) return DSK_ERR_SYSERR;
352
353 memset(self->jv3_header, JV3_FREE, sizeof(self->jv3_header));
354 self->jv3_len = sizeof(self->jv3_header);
355
356 if (fwrite(self->jv3_header, 1, sizeof(self->jv3_header), self->jv3_fp)
357 < (int)sizeof(self->jv3_header))
358 {
359 return DSK_ERR_SYSERR;
360 }
361 return DSK_ERR_OK;
362 }
363
364
365
jv3_close(DSK_DRIVER * s)366 dsk_err_t jv3_close(DSK_DRIVER *s)
367 {
368 DC_CHECK(s);
369
370 if (fclose(self->jv3_fp)) return DSK_ERR_SYSERR;
371 return DSK_ERR_OK;
372 }
373
374
375
jv3_write(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)376 dsk_err_t jv3_write(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
377 const void *buf, dsk_pcyl_t cylinder,
378 dsk_phead_t head, dsk_psect_t sector)
379 {
380 return jv3_xwrite (self, geom, buf, cylinder, head,
381 cylinder, head, sector, geom->dg_secsize, 0);
382 }
383
384
385 typedef struct
386 {
387 int found;
388 dsk_pcyl_t cylinder;
389 dsk_phead_t head;
390 dsk_psect_t sector;
391 int deleted;
392 int fm;
393 size_t sector_size;
394 void *buf;
395 dsk_err_t result;
396
397 } READSEC_DATA;
398
399
400
401
droptrack_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)402 dsk_err_t droptrack_callback(JV3_DSK_DRIVER *self, JV3_ENUM_STATE *state,
403 void *param)
404 {
405 READSEC_DATA *rsd = (READSEC_DATA *)param;
406
407 if (state->cyl == rsd->cylinder &&
408 state->head == rsd->head &&
409 state->isfree == 0)
410 {
411 state->sector_head[0] = JV3_FREE;
412 state->sector_head[1] = JV3_FREE;
413 state->sector_head[2] = JV3_FREEF;
414 state->sector_head[2] |= encode_size(1, state->secsize);
415 state->touched = 1;
416 }
417 return DSK_ERR_OK;
418 }
419
420
dropsector_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)421 dsk_err_t dropsector_callback(JV3_DSK_DRIVER *self, JV3_ENUM_STATE *state,
422 void *param)
423 {
424 READSEC_DATA *rsd = (READSEC_DATA *)param;
425
426 if (state->cyl == rsd->cylinder &&
427 state->head == rsd->head &&
428 state->sector == rsd->sector &&
429 state->isfree == 0)
430 {
431 state->sector_head[0] = JV3_FREE;
432 state->sector_head[1] = JV3_FREE;
433 state->sector_head[2] = JV3_FREEF;
434 state->sector_head[2] |= encode_size(1, state->secsize);
435 state->touched = 1;
436 }
437 return DSK_ERR_OK;
438 }
439
format_sector_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)440 dsk_err_t format_sector_callback(JV3_DSK_DRIVER *self,
441 JV3_ENUM_STATE *state, void *param)
442 {
443 READSEC_DATA *rsd = (READSEC_DATA *)param;
444 unsigned n;
445 long pos;
446
447 if (!state->isfree || state->secsize != rsd->sector_size)
448 {
449 return DSK_ERR_OK;
450 }
451 /* We've got a suitable blank space */
452 state->touched = 1;
453 state->sector_head[0] = rsd->cylinder;
454 state->sector_head[1] = rsd->sector;
455 state->sector_head[2] = encode_size(0, rsd->sector_size) & JV3_SIZE;
456 if (!rsd->fm) state->sector_head[2] |= JV3_DENSITY;
457 if (rsd->head) state->sector_head[2] |= JV3_SIDE;
458
459 /* Write fillers */
460 if (fseek(self->jv3_fp, state->data_offset, SEEK_SET) < 0)
461 return DSK_ERR_SYSERR;
462
463 for (n = 0; n < state->secsize; n++)
464 {
465 if (fputc(rsd->deleted, self->jv3_fp) == EOF)
466 return DSK_ERR_SYSERR;
467 }
468 pos = ftell(self->jv3_fp);
469 /* If we have extended the file, record the fact. */
470 if (pos > self->jv3_len)
471 {
472 self->jv3_len = pos;
473 }
474 state->stop = 1; /* New sector written. */
475
476 return DSK_ERR_OK;
477 }
478
479
jv3_format(DSK_DRIVER * s,DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,const DSK_FORMAT * format,unsigned char filler)480 dsk_err_t jv3_format(DSK_DRIVER *s, DSK_GEOMETRY *geom,
481 dsk_pcyl_t cylinder, dsk_phead_t head,
482 const DSK_FORMAT *format, unsigned char filler)
483 {
484 READSEC_DATA rsd;
485 dsk_psect_t sec;
486 dsk_err_t err;
487 unsigned char blanksize;
488
489 DC_CHECK(s);
490
491 if (self->jv3_header[JV3_HEADER_LEN - 1] == 0) return DSK_ERR_RDONLY;
492
493 rsd.found = 0;
494 rsd.cylinder = cylinder;
495 rsd.head = head;
496
497 /* Delete any existing sectors */
498 err = jv3_enum_sectors(self, 0, droptrack_callback, &rsd);
499
500 if (err) return err;
501
502 /* And write a blank set */
503 for (sec = 0; sec < geom->dg_sectors; sec++)
504 {
505 rsd.found = 0;
506 rsd.cylinder = cylinder;
507 rsd.head = head;
508 rsd.sector = format[sec].fmt_sector;
509 rsd.fm = (geom->dg_fm & RECMODE_MASK) == RECMODE_FM;
510 rsd.sector_size = format[sec].fmt_secsize;
511 rsd.deleted = filler;
512 blanksize = JV3_FREEF | encode_size(1, rsd.sector_size);
513 err = jv3_enum_sectors(self, blanksize, format_sector_callback, &rsd);
514 if (err) return err;
515 }
516 return DSK_ERR_OK;
517 }
518
519
520
jv3_secid(DSK_DRIVER * s,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,DSK_FORMAT * result)521 dsk_err_t jv3_secid(DSK_DRIVER *s, const DSK_GEOMETRY *geom,
522 dsk_pcyl_t cylinder, dsk_phead_t head,
523 DSK_FORMAT *result)
524 {
525 DSK_FORMAT *buf = NULL;
526 dsk_psect_t count = 0;
527 dsk_err_t err;
528 int offset;
529
530 DC_CHECK(s)
531
532 /* Gather all the sector IDs for a track together, and then
533 * pick one */
534 err = jv3_trackids(s, geom, cylinder, head, &count, &buf);
535
536 if (count == 0 && !err)
537 {
538 self->jv3_sector = 0;
539 err = DSK_ERR_NOADDR;
540 }
541 if (!err)
542 {
543 offset = self->jv3_sector % count;
544
545 *result = buf[offset];
546
547 ++self->jv3_sector;
548 }
549 if (buf)
550 {
551 dsk_free(buf);
552 }
553 return err;
554 }
555
556
jv3_xseek(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head)557 dsk_err_t jv3_xseek(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
558 dsk_pcyl_t cylinder, dsk_phead_t head)
559 {
560 DSK_FORMAT dummy;
561
562 dsk_err_t err = jv3_secid(self, geom, cylinder, head, &dummy);
563
564 if (err == DSK_ERR_NOADDR) return DSK_ERR_SEEKFAIL;
565
566 return err;
567 }
568
569
jv3_read(DSK_DRIVER * self,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)570 dsk_err_t jv3_read(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
571 void *buf, dsk_pcyl_t cylinder,
572 dsk_phead_t head, dsk_psect_t sector)
573 {
574 return jv3_xread(self, geom, buf, cylinder, head, cylinder,
575 dg_x_head(geom, head),
576 dg_x_sector(geom, head, sector), geom->dg_secsize, NULL);
577 }
578
579
580
581
xread_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)582 static dsk_err_t xread_callback(JV3_DSK_DRIVER *self,
583 JV3_ENUM_STATE *state, void *param)
584 {
585 READSEC_DATA *rsd = (READSEC_DATA *)param;
586
587 size_t sec_size = state->secsize;
588
589 int fm = (state->flags & JV3_DENSITY) ? 0 : 1;
590 int deleted = (state->flags & JV3_DAM) ? 1 : 0;
591
592 if (state->isfree ||
593 state->cyl != rsd->cylinder ||
594 state->head != rsd->head ||
595 state->sector != rsd->sector ||
596 fm != rsd->fm ||
597 deleted != rsd->deleted) return DSK_ERR_OK; /* No match */
598
599 if (fseek(self->jv3_fp, state->data_offset, SEEK_SET) < 0)
600 return DSK_ERR_SYSERR;
601 if (sec_size > rsd->sector_size) sec_size = rsd->sector_size;
602
603 sec_size = fread(rsd->buf, 1, sec_size, self->jv3_fp);
604 for (; sec_size < rsd->sector_size; sec_size++)
605 {
606 ((unsigned char *)(rsd->buf))[sec_size] = 0xE5;
607 }
608 rsd->result = (state->flags & JV3_ERROR) ? DSK_ERR_DATAERR : DSK_ERR_OK;
609 rsd->deleted = deleted;
610 state->stop = 1;
611 return DSK_ERR_OK;
612 }
613
614
615 /* Attempt to write to an existing sector */
xwrite_callback1(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)616 static dsk_err_t xwrite_callback1(JV3_DSK_DRIVER *self,
617 JV3_ENUM_STATE *state, void *param)
618 {
619 READSEC_DATA *rsd = (READSEC_DATA *)param;
620
621 size_t sec_size = state->secsize;
622
623 int fm = (state->flags & JV3_DENSITY) ? 0 : 1;
624 int deleted = (state->flags & JV3_DAM) ? 1 : 0;
625
626 if (state->isfree ||
627 state->cyl != rsd->cylinder ||
628 state->head != rsd->head ||
629 state->sector != rsd->sector ||
630 fm != rsd->fm ||
631 deleted != rsd->deleted) return DSK_ERR_OK; /* No match */
632
633 if (fseek(self->jv3_fp, state->data_offset, SEEK_SET) < 0)
634 return DSK_ERR_SYSERR;
635 if (sec_size > rsd->sector_size) sec_size = rsd->sector_size;
636
637 if (fwrite(rsd->buf, 1, sec_size, self->jv3_fp) < sec_size)
638 return DSK_ERR_SYSERR;
639
640 if (rsd->deleted)
641 {
642 state->sector_head[2] &= ~JV3_DAM;
643 state->sector_head[2] |= 0x20;
644 }
645 else
646 {
647 state->sector_head[2] &= ~JV3_DAM;
648 }
649 if (state->sector_head[2] != state->flags)
650 state->touched = 1;
651 state->stop = 1;
652 rsd->found = 1;
653 return DSK_ERR_OK;
654 }
655
656
657
658
659
jv3_xread(DSK_DRIVER * s,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int * deleted)660 dsk_err_t jv3_xread(DSK_DRIVER *s, const DSK_GEOMETRY *geom, void *buf,
661 dsk_pcyl_t cylinder, dsk_phead_t head,
662 dsk_pcyl_t cyl_expected,
663 dsk_phead_t head_expected,
664 dsk_psect_t sector, size_t sector_size,
665 int *deleted)
666 {
667 dsk_err_t err = DSK_ERR_OK;
668 READSEC_DATA rsd;
669
670 DC_CHECK(s);
671
672
673 rsd.cylinder = cylinder;
674 rsd.head = head;
675 rsd.sector = sector;
676 if (deleted && *deleted) rsd.deleted = 1;
677 else rsd.deleted = 0;
678 rsd.fm = (geom->dg_fm & RECMODE_MASK) == RECMODE_FM;
679 rsd.sector_size = sector_size;
680 rsd.buf = buf;
681 rsd.result = DSK_ERR_NOADDR;
682
683 err = jv3_enum_sectors(self, 0, xread_callback, &rsd);
684
685 if (err) return err;
686 if (rsd.result == DSK_ERR_NOADDR)
687 {
688 self->jv3_sector = 0;
689 }
690 if (deleted) *deleted = rsd.deleted;
691 return rsd.result;
692 }
693
jv3_xwrite(DSK_DRIVER * s,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int deleted)694 dsk_err_t jv3_xwrite(DSK_DRIVER *s, const DSK_GEOMETRY *geom, const void *buf,
695 dsk_pcyl_t cylinder, dsk_phead_t head,
696 dsk_pcyl_t cyl_expected, dsk_phead_t head_expected,
697 dsk_psect_t sector, size_t sector_size, int deleted)
698 {
699 dsk_err_t err = DSK_ERR_OK;
700 READSEC_DATA rsd;
701
702 DC_CHECK(s);
703
704 if (self->jv3_header[JV3_HEADER_LEN - 1] == 0) return DSK_ERR_RDONLY;
705
706 rsd.cylinder = cylinder;
707 rsd.head = head;
708 rsd.sector = sector;
709 rsd.deleted = deleted;
710 rsd.fm = (geom->dg_fm & RECMODE_MASK) == RECMODE_FM;
711 rsd.sector_size = sector_size;
712 rsd.buf = (void *)buf;
713 rsd.result = DSK_ERR_NOADDR;
714 rsd.found = 0;
715
716 err = jv3_enum_sectors(self, 0, xwrite_callback1, &rsd);
717
718 if (err) return err;
719
720 if (!rsd.found)
721 {
722 /* If the sector has not been found, should we create it? Probably not; only
723 * jv3_format should create sectors if they aren't there. */
724 self->jv3_sector = 0;
725 return DSK_ERR_NOADDR;
726 }
727 return DSK_ERR_OK;
728 }
729
730 typedef struct
731 {
732 int fm;
733 dsk_pcyl_t cylinder;
734 dsk_phead_t head;
735 unsigned count;
736 DSK_FORMAT *result;
737 } TRACKIDS_PARAM;
738
739
trackids_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * p)740 static dsk_err_t trackids_callback(JV3_DSK_DRIVER *self,
741 JV3_ENUM_STATE *state, void *p)
742 {
743 TRACKIDS_PARAM *param = (TRACKIDS_PARAM *)p;
744
745 int fm = (state->flags & JV3_DENSITY) ? 0 : 1;
746
747 if (state->cyl == param->cylinder &&
748 state->head == param->head &&
749 fm == param->fm &&
750 state->isfree == 0)
751 {
752 if (param->result)
753 {
754 param->result[param->count].fmt_cylinder = state->cyl;
755 param->result[param->count].fmt_head = state->head;
756 param->result[param->count].fmt_sector = state->sector;
757 param->result[param->count].fmt_secsize = state->secsize;
758
759 }
760 ++param->count;
761 }
762 return DSK_ERR_OK;
763 }
764
765
766
jv3_trackids(DSK_DRIVER * s,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t * count,DSK_FORMAT ** result)767 dsk_err_t jv3_trackids(DSK_DRIVER *s, const DSK_GEOMETRY *geom,
768 dsk_pcyl_t cylinder, dsk_phead_t head,
769 dsk_psect_t *count, DSK_FORMAT **result)
770 {
771 TRACKIDS_PARAM param;
772 dsk_err_t err;
773
774 DC_CHECK(s);
775
776 param.fm = (geom->dg_fm & RECMODE_MASK) == RECMODE_FM;
777 param.cylinder = cylinder;
778 param.head = head;
779 param.count = 0;
780 param.result = NULL;
781
782 /* We call this function twice: Once to count the number of
783 * sectors with the given cylinder and head; then allocate the
784 * results array; then call again to populate the array. */
785 err = jv3_enum_sectors(self, 0, trackids_callback, ¶m);
786 if (err) return err;
787
788 if (!param.count)
789 {
790 *count = 0;
791 *result = NULL;
792 return DSK_ERR_OK;
793 }
794 param.result = dsk_malloc(param.count * sizeof(DSK_FORMAT));
795 if (!param.result) return DSK_ERR_NOMEM;
796
797 param.count = 0;
798 err = jv3_enum_sectors(self, 0, trackids_callback, ¶m);
799 if (err) return err;
800
801 *count = param.count;
802 *result = param.result;
803
804 return DSK_ERR_OK;
805 }
806
jv3_status(DSK_DRIVER * s,const DSK_GEOMETRY * geom,dsk_phead_t head,unsigned char * result)807 dsk_err_t jv3_status(DSK_DRIVER *s, const DSK_GEOMETRY *geom,
808 dsk_phead_t head, unsigned char *result)
809 {
810 DC_CHECK(s);
811
812 if (!self->jv3_fp)
813 *result &= ~DSK_ST3_READY;
814
815 if (self->jv3_header[JV3_HEADER_LEN - 1] == 0)
816 *result |= DSK_ST3_RO;
817
818 return DSK_ERR_OK;
819 }
820
821
822 typedef struct
823 {
824 DSK_GEOMETRY testgeom;
825 dsk_psect_t minsec0, maxsec0, minsec1, maxsec1;
826 } GEOM_RESULT;
827
geom_callback(JV3_DSK_DRIVER * self,JV3_ENUM_STATE * state,void * param)828 static dsk_err_t geom_callback(JV3_DSK_DRIVER *self,
829 JV3_ENUM_STATE *state, void *param)
830 {
831 GEOM_RESULT *gr = (GEOM_RESULT *)param;
832
833 /* Ignore free sectors */
834 if (state->isfree) return DSK_ERR_OK;
835
836 gr->testgeom.dg_secsize = state->secsize;
837 if (state->cyl >= gr->testgeom.dg_cylinders)
838 gr->testgeom.dg_cylinders = state->cyl + 1;
839 if (state->head >= gr->testgeom.dg_heads)
840 gr->testgeom.dg_heads = state->head + 1;
841 gr->testgeom.dg_datarate = RATE_SD;
842 gr->testgeom.dg_fm = (state->flags & JV3_DENSITY) ? RECMODE_MFM : RECMODE_FM;
843 if (state->head == 1)
844 {
845 if (state->sector < gr->minsec1) gr->minsec1 = state->sector;
846 if (state->sector > gr->maxsec1) gr->maxsec1 = state->sector;
847 }
848 else
849 {
850 if (state->sector < gr->minsec0) gr->minsec0 = state->sector;
851 if (state->sector > gr->maxsec0) gr->maxsec0 = state->sector;
852 }
853 return DSK_ERR_OK;
854 }
855
856
jv3_getgeom(DSK_DRIVER * s,DSK_GEOMETRY * geom)857 dsk_err_t jv3_getgeom(DSK_DRIVER *s, DSK_GEOMETRY *geom)
858 {
859 dsk_err_t err;
860 GEOM_RESULT result;
861
862 DC_CHECK(s);
863
864 /* First try the normal geometry probe */
865 err = dsk_defgetgeom(s, geom);
866
867 if (!err) return err;
868
869 dg_stdformat(&result.testgeom, FMT_180K, NULL, NULL);
870 result.testgeom.dg_cylinders = 0;
871 result.testgeom.dg_sectors = 0;
872 result.testgeom.dg_heads = 0;
873
874 result.minsec0 = result.minsec1 = 256;
875 result.maxsec0 = result.maxsec1 = 0;
876
877 err = jv3_enum_sectors(self, 0, geom_callback, &result);
878
879 if (err) return err;
880
881 result.testgeom.dg_secbase = result.minsec0;
882 result.testgeom.dg_sectors = (result.maxsec0 - result.minsec0) + 1;
883
884 if (result.testgeom.dg_cylinders == 0 ||
885 result.testgeom.dg_sectors == 0) return DSK_ERR_BADFMT;
886
887 memcpy(geom, &result.testgeom, sizeof(*geom));
888 return DSK_ERR_OK;
889
890 }
891
892
893