1 /*
2 * vdrive-bam.c - Virtual disk-drive implementation. BAM specific functions.
3 *
4 * Written by
5 * Andreas Boose <viceteam@t-online.de>
6 * Ingo Korb <ingo@akana.de>
7 *
8 * Based on old code by
9 * Teemu Rantanen <tvr@cs.hut.fi>
10 * Jarkko Sonninen <sonninen@lut.fi>
11 * Jouko Valta <jopi@stekt.oulu.fi>
12 * Olaf Seibert <rhialto@mbfys.kun.nl>
13 * Andre Fachat <a.fachat@physik.tu-chemnitz.de>
14 * Ettore Perazzoli <ettore@comm2000.it>
15 * pottendo <pottendo@gmx.net>
16 *
17 * This file is part of VICE, the Versatile Commodore Emulator.
18 * See README for copyright notice.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
33 * 02111-1307 USA.
34 *
35 */
36
37 #include "vice.h"
38
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "attach.h"
43 #include "cbmdos.h"
44 #include "diskconstants.h"
45 #include "diskimage.h"
46 #include "log.h"
47 #include "types.h"
48 #include "vdrive-bam.h"
49 #include "vdrive-command.h"
50 #include "vdrive.h"
51
52 /* #define DEBUG_DRIVE */
53
54 /*
55 return Maximum distance from dir track to start/end of disk.
56
57 FIXME: partition support
58 */
vdrive_calculate_disk_half(vdrive_t * vdrive)59 static int vdrive_calculate_disk_half(vdrive_t *vdrive)
60 {
61 switch (vdrive->image_format) {
62 case VDRIVE_IMAGE_FORMAT_1541:
63 case VDRIVE_IMAGE_FORMAT_2040:
64 return 17 + 5;
65 case VDRIVE_IMAGE_FORMAT_1571:
66 return 17 + 35;
67 case VDRIVE_IMAGE_FORMAT_1581:
68 return 40;
69 case VDRIVE_IMAGE_FORMAT_8050:
70 return 39;
71 case VDRIVE_IMAGE_FORMAT_8250:
72 return 39 + 78;
73 case VDRIVE_IMAGE_FORMAT_4000:
74 return vdrive->num_tracks - 1;
75 case VDRIVE_IMAGE_FORMAT_9000:
76 return vdrive->num_tracks - 1;
77 default:
78 log_error(LOG_ERR,
79 "Unknown disk type %u. Cannot calculate disk half.",
80 vdrive->image_format);
81 }
82 return -1;
83 }
84
85 /*
86 This function is used by the next 3 to find an available sector in
87 a single track. Typically this would be a simple loop, but the D9090/60
88 adds another dimension (heads) to the search.
89 It only updates the sector if it finds something (returns 0).
90 */
vdrive_bam_alloc_worker(vdrive_t * vdrive,unsigned int track,unsigned int * sector)91 static int vdrive_bam_alloc_worker(vdrive_t *vdrive,
92 unsigned int track, unsigned int *sector)
93 {
94 unsigned int max_sector, max_sector_all, s, h, s2, h2;
95
96 max_sector = vdrive_get_max_sectors_per_head(vdrive, track);
97 max_sector_all = vdrive_get_max_sectors(vdrive, track);
98 /* start at supplied sector - but it is usually always 0 */
99 s = *sector % max_sector;
100 h = (*sector / max_sector) * max_sector;
101 /* go through all groups, 1 round for most CBM drives */
102 for (h2 = 0; h2 < max_sector_all; h2 += max_sector) {
103 /* scan sectors in group */
104 for (s2 = 0; s2 < max_sector; s2++) {
105 /* skip the first 64 sectors of track 1 on DNP */
106 if (s < 64 && vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000
107 && track == vdrive->Dir_Track) {
108 s = 64;
109 }
110 if (vdrive_bam_allocate_sector(vdrive, track, s + h)) {
111 *sector = s + h;
112 return 0;
113 }
114 s++;
115 if (s >= max_sector) {
116 s = 0;
117 }
118 }
119 /* for D9090/60 only move on to next track if we scanned all
120 the sector groups */
121 h += max_sector;
122 if (h >= max_sector_all) {
123 h = 0;
124 }
125 }
126 return -1;
127 }
128
129 /*
130 FIXME: partition support
131 */
vdrive_bam_alloc_first_free_sector(vdrive_t * vdrive,unsigned int * track,unsigned int * sector)132 int vdrive_bam_alloc_first_free_sector(vdrive_t *vdrive,
133 unsigned int *track,
134 unsigned int *sector)
135 {
136 unsigned int d, max_tracks;
137 unsigned int origt = *track, origs = *sector;
138 int t;
139
140 /* For D9090/60, it simply uses a toggle to decide on which side of
141 the directory to start, and then uses the "next sector" routine.
142 see $fb81 in ROM */
143 /* this obviously means the behavior selecting the first sector of the
144 drive depends on what it did in the past since reset */
145 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
146 vdrive->d90toggle ^= 1;
147 *track = vdrive->Dir_Track;
148 *sector = 0;
149 if (vdrive->d90toggle) {
150 (*track)++;
151 } else {
152 (*track)--;
153 }
154 return vdrive_bam_alloc_next_free_sector(vdrive, track, sector);
155 }
156
157 max_tracks = vdrive_calculate_disk_half(vdrive);
158 /* this is okay since the D9090/60 code doesn't use this algorithm */
159 *sector = 0;
160
161 /* For everything else, do the basic butterfly search */
162 for (d = 0; d <= max_tracks; d++) {
163 t = vdrive->Dir_Track - d;
164 #ifdef DEBUG_DRIVE
165 log_message(LOG_DEFAULT, "Allocate first free sector on track %d.", t);
166 #endif
167 if (d && t >= 1) {
168 if (!vdrive_bam_alloc_worker(vdrive, t, sector)) {
169 *track = t;
170 #ifdef DEBUG_DRIVE
171 log_message(LOG_DEFAULT,
172 "Allocate first free sector: %d,%u.", t, s);
173 #endif
174 return 0;
175 }
176 }
177 t = vdrive->Dir_Track + d;
178 #ifdef DEBUG_DRIVE
179 log_message(LOG_DEFAULT, "Allocate first free sector on track %d.", t);
180 #endif
181 if (t <= (int)(vdrive->num_tracks)) {
182 if (d || vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
183 if (!vdrive_bam_alloc_worker(vdrive, t, sector)) {
184 *track = t;
185 #ifdef DEBUG_DRIVE
186 log_message(LOG_DEFAULT,
187 "Allocate first free sector: %d,%u.", t, s);
188 #endif
189 return 0;
190 }
191 }
192 }
193 }
194
195 /* nothing, no space, recover saved variables and leave */
196 *track = origt;
197 *sector = origs;
198 return -1;
199 }
200
201 /* add interleave to current sector and adjust for overflow */
vdrive_bam_alloc_add_interleave(vdrive_t * vdrive,unsigned int track,unsigned int sector,unsigned int interleave)202 int vdrive_bam_alloc_add_interleave(vdrive_t *vdrive,
203 unsigned int track,
204 unsigned int sector,
205 unsigned int interleave)
206 {
207 unsigned int max_sector, max_sector_all, s, h;
208
209 /* Calculate the next sector for the current interleave */
210 max_sector = vdrive_get_max_sectors_per_head(vdrive, track);
211 max_sector_all = vdrive_get_max_sectors(vdrive, track);
212 /* the starting sector may be out of bounds on the new track, so
213 adjust head accordingly and follow through */
214 if (sector >= max_sector_all) {
215 s = sector;
216 h = 0;
217 } else {
218 s = sector % max_sector;
219 h = (sector / max_sector) * max_sector;
220 }
221 /* add the interleave and adjust if we go over */
222 s = s + interleave;
223 if (s >= max_sector) {
224 s -= max_sector;
225 if (s != 0) {
226 s--;
227 }
228 }
229 return s + h;
230 }
231
232 /* starting from the currently used track/sector, look for a new sector
233 downwards */
vdrive_bam_alloc_down(vdrive_t * vdrive,unsigned int * track,unsigned int * sector,unsigned int interleave)234 static int vdrive_bam_alloc_down(vdrive_t *vdrive,
235 unsigned int *track, unsigned int *sector,
236 unsigned int interleave)
237 {
238 unsigned int t, s;
239
240 /* scan downwards */
241 for (t = *track; t >= 1; t--) {
242 /* find next sector on this track based on interleave */
243 s = vdrive_bam_alloc_add_interleave(vdrive, t, *sector, interleave);
244 if (!vdrive_bam_alloc_worker(vdrive, t, &s)) {
245 *track = t;
246 *sector = s;
247 return 0;
248 }
249 }
250 return -1;
251 }
252
253 /* starting from the currently used track/sector, look for a new sector
254 upwards */
vdrive_bam_alloc_up(vdrive_t * vdrive,unsigned int * track,unsigned int * sector,unsigned int interleave)255 static int vdrive_bam_alloc_up(vdrive_t *vdrive,
256 unsigned int *track, unsigned int *sector,
257 unsigned int interleave)
258 {
259 unsigned int t, s;
260
261 /* scan upwards */
262 for (t = *track; t <= vdrive->num_tracks; t++) {
263 /* find next sector on this track based on interleave */
264 s = vdrive_bam_alloc_add_interleave(vdrive, t, *sector, interleave);
265 if (!vdrive_bam_alloc_worker(vdrive, t, &s)) {
266 *track = t;
267 *sector = s;
268 return 0;
269 }
270 }
271 return -1;
272 }
273
274 /* resets the "sector" to zero, but keeps the "head" value; for D9090/60 */
vdrive_bam_alloc_next_free_sector_reset(vdrive_t * vdrive,unsigned int track,unsigned int sector,unsigned int interleave)275 static int vdrive_bam_alloc_next_free_sector_reset(vdrive_t *vdrive,
276 unsigned int track,
277 unsigned int sector,
278 unsigned int interleave)
279 {
280 unsigned int max_sector, s, h;
281
282 s = vdrive_bam_alloc_add_interleave(vdrive, track, sector, interleave);
283 max_sector = vdrive_get_max_sectors_per_head(vdrive, track);
284 h = (s / max_sector) * max_sector;
285 return h;
286 }
287
288 /*
289 FIXME: partition support
290 */
291 /* function reworked to use smaller functions above and to behave like DOS
292 code */
vdrive_bam_alloc_next_free_sector_interleave(vdrive_t * vdrive,unsigned int * track,unsigned int * sector,unsigned int interleave)293 int vdrive_bam_alloc_next_free_sector_interleave(vdrive_t *vdrive,
294 unsigned int *track,
295 unsigned int *sector,
296 unsigned int interleave)
297 {
298 unsigned int split = vdrive->Dir_Track;
299 unsigned int origt = *track, origs = *sector;
300 unsigned int s;
301 int pass;
302
303 /* Check if we are dealing with the directory track */
304 /* I dislike inverse logic, we will just make it readable */
305 if (*track == vdrive->Dir_Track) {
306 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
307 /* allowed on D9090/60 */
308 } else if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000 && *sector >= 64) {
309 /* allowed on DNP as long as sector >= 64 */
310 } else {
311 /* everything else: no */
312 return -1;
313 }
314 }
315
316 /* find next sector on this track based on interleave */
317 s = vdrive_bam_alloc_add_interleave(vdrive, *track, *sector, interleave);
318 /* starting from there, see if there is an available sector */
319 if (!vdrive_bam_alloc_worker(vdrive, *track, &s)) {
320 *sector = s;
321 return 0;
322 }
323
324 /* nothing here; if DNP, move on to next track if we are track 1 */
325 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000
326 && *track == vdrive->Dir_Track) {
327 (*track)++;
328 /* reset sector position */
329 *sector = vdrive_bam_alloc_next_free_sector_reset(vdrive, *track, *sector, interleave);
330 }
331
332 /* use a multi-pass approach here just like the DOS code */
333 for (pass = 0; pass < 3; pass++) {
334 /* on the first pass, look downward if we are already below the dir track */
335 /* on subsequence passes, we start one below the dir track and look down */
336 /* DNP goes here second */
337 if (*track > 0 && *track < split) {
338 if (vdrive_bam_alloc_down(vdrive, track, sector, interleave) == 0) {
339 return 0;
340 }
341 /* For DNP, at this point, there is no space, leave search */
342 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
343 break;
344 }
345 /* after first pass, reset the starting track, and set sector to 0 */
346 *track = split + 1;
347 /* reset sector position */
348 *sector = vdrive_bam_alloc_next_free_sector_reset(vdrive, *track, *sector, interleave);
349 } else if (*track >= split) {
350 /* on the first pass, look upward if we are already above the dir track */
351 /* on subsequence passes, we start one above the dir track and look up */
352 /* DNP goes here first */
353 if (vdrive_bam_alloc_up(vdrive, track, sector, interleave) == 0) {
354 return 0;
355 }
356 /* For DNP, set the new split point to the original start track */
357 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
358 split = *track;
359 }
360 /* after first pass, reset the starting track, and set sector to 0 */
361 *track = split - 1;
362 /* reset sector position */
363 *sector = vdrive_bam_alloc_next_free_sector_reset(vdrive, *track, *sector, interleave);
364 }
365 }
366
367 /* For D9090/60, when all the other space is full, we can use the
368 directory track */
369 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
370 /* start at sector 10 (interleave), as head gets set back to 0 */
371 *sector = 10;
372 *track = vdrive->Dir_Track;
373 if (!vdrive_bam_alloc_worker(vdrive, *track, sector)) {
374 return 0;
375 }
376 }
377
378 /* nothing, no space, recover saved variables and leave */
379 *track = origt;
380 *sector = origs;
381 return -1;
382 }
383
384 /*
385 FIXME: partition support
386 */
387 /* function reworked to use smaller functions above and to behave like DOS
388 code */
vdrive_bam_alloc_next_free_sector(vdrive_t * vdrive,unsigned int * track,unsigned int * sector)389 int vdrive_bam_alloc_next_free_sector(vdrive_t *vdrive,
390 unsigned int *track,
391 unsigned int *sector)
392 {
393 return vdrive_bam_alloc_next_free_sector_interleave(vdrive, track,
394 sector, vdrive_bam_get_interleave(vdrive->image_format));
395 }
396
vdrive_bam_set(uint8_t * bamp,unsigned int sector)397 static void vdrive_bam_set(uint8_t *bamp, unsigned int sector)
398 {
399 bamp[1 + sector / 8] |= (1 << (sector % 8));
400 return;
401 }
402
vdrive_bam_clr(uint8_t * bamp,unsigned int sector)403 static void vdrive_bam_clr(uint8_t *bamp, unsigned int sector)
404 {
405 bamp[1 + sector / 8] &= ~(1 << (sector % 8));
406 return;
407 }
408
409 /* this function used to be used by c1541, but it is too particular to
410 drives which have the block count in the bam entries */
vdrive_bam_isset(uint8_t * bamp,unsigned int sector)411 static int vdrive_bam_isset(uint8_t *bamp, unsigned int sector)
412 {
413 return bamp[1 + sector / 8] & (1 << (sector % 8));
414 }
415
416 /* allocate the chain of sectors given a track and sector starting point */
vdrive_bam_allocate_chain(vdrive_t * vdrive,unsigned int t,unsigned int s)417 int vdrive_bam_allocate_chain(vdrive_t *vdrive, unsigned int t, unsigned int s)
418 {
419 uint8_t tmp[256];
420 int rc;
421
422 while (t) {
423 /* Check for illegal track or sector. */
424 if (disk_image_check_sector(vdrive->image, t, s) < 0) {
425 vdrive_command_set_error(vdrive, CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR,
426 s, t);
427 return CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR;
428 }
429 if (!vdrive_bam_allocate_sector(vdrive, t, s)) {
430 /* The real drive does not seem to catch this error. */
431 vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_BLOCK, s, t);
432 return CBMDOS_IPE_NO_BLOCK;
433 }
434 rc = vdrive_read_sector(vdrive, tmp, t, s);
435 if (rc > 0) {
436 return rc;
437 }
438 if (rc < 0) {
439 return CBMDOS_IPE_NOT_READY;
440 }
441
442 t = (int)tmp[0];
443 s = (int)tmp[1];
444 }
445 return CBMDOS_IPE_OK;
446 }
447
448 /* save as above, but stops when track is 255; this is what they used in the
449 D9090/60 for the BAM */
vdrive_bam_allocate_chain_255(vdrive_t * vdrive,unsigned int t,unsigned int s)450 int vdrive_bam_allocate_chain_255(vdrive_t *vdrive, unsigned int t, unsigned int s)
451 {
452 uint8_t tmp[256];
453 int rc;
454
455 while (t != 255) {
456 /* Check for illegal track or sector. */
457 if (disk_image_check_sector(vdrive->image, t, s) < 0) {
458 vdrive_command_set_error(vdrive, CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR,
459 s, t);
460 return CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR;
461 }
462 if (!vdrive_bam_allocate_sector(vdrive, t, s)) {
463 /* The real drive does not seem to catch this error. */
464 vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_BLOCK, s, t);
465 return CBMDOS_IPE_NO_BLOCK;
466 }
467 rc = vdrive_read_sector(vdrive, tmp, t, s);
468 if (rc > 0) {
469 return rc;
470 }
471 if (rc < 0) {
472 return CBMDOS_IPE_NOT_READY;
473 }
474
475 t = (int)tmp[0];
476 s = (int)tmp[1];
477 }
478 return CBMDOS_IPE_OK;
479 }
480
481 /** \brief Get pointer to the BAM entry for \a track in \a vdrive's image
482 *
483 * A CBMDOS BAM entry consists of a single byte indication the number of free
484 * sectors (unreliable since there's a lot of disks out there which set this
485 * to 0 to get a "0 blocks free."), followed by a bitmap of free/used sectors.
486 * The size of the bitmap depends on the image type, 1541 and 1571 have three
487 * bytes (enough for 21 sectors), while 1581 has 5 bytes (40 sectors).
488 *
489 * \param[in] vdrive vdrive object
490 * \param[in] track track number
491 * \param[in] sector sector number ( needed for D9090/60)
492 *
493 * \return pointer to BAM entry
494 *
495 *( FIXME: partition support
496 */
vdrive_bam_get_track_entry(vdrive_t * vdrive,unsigned int track,unsigned int sector)497 static uint8_t *vdrive_bam_get_track_entry(vdrive_t *vdrive, unsigned int track,
498 unsigned int sector)
499 {
500 uint8_t *bamp = NULL;
501 uint8_t *bam = vdrive->bam;
502
503 /* D9090/60 has track 0, and it has a BAM entry */
504 if (track == 0 && vdrive->image_format != VDRIVE_IMAGE_FORMAT_9000) {
505 log_error(LOG_ERR, "invalid track number: 0");
506 return NULL;
507 }
508
509 switch (vdrive->image_format) {
510 case VDRIVE_IMAGE_FORMAT_1541:
511 case VDRIVE_IMAGE_FORMAT_2040:
512 bamp = (track <= NUM_TRACKS_1541) ?
513 &bam[BAM_BIT_MAP + 4 * (track - 1)] :
514 &bam[BAM_EXT_BIT_MAP_1541 + 4 * (track - NUM_TRACKS_1541 - 1)];
515 break;
516 case VDRIVE_IMAGE_FORMAT_1571:
517 bamp = (track <= NUM_TRACKS_1571 / 2) ?
518 &bam[BAM_BIT_MAP + 4 * (track - 1)] :
519 &bam[0x100 + 3 * (track - NUM_TRACKS_1571 / 2 - 1) - 1];
520 break;
521 case VDRIVE_IMAGE_FORMAT_1581:
522 bamp = (track <= BAM_TRACK_1581) ?
523 &bam[0x100 + BAM_BIT_MAP_1581 + 6 * (track - 1)] :
524 &bam[0x200 + BAM_BIT_MAP_1581 + 6 *
525 (track - BAM_TRACK_1581 - 1)];
526 break;
527 case VDRIVE_IMAGE_FORMAT_8050:
528 {
529 int i;
530 for (i = 1; i < 3; i++) {
531 if (track >= bam[(i * 0x100) + 4] && track < bam[(i * 0x100) + 5]) {
532 bamp = &bam[(i * 0x100) + BAM_BIT_MAP_8050 + 5 * (track - bam[(i * 0x100) + 4])];
533 break;
534 }
535 }
536 }
537 break;
538 case VDRIVE_IMAGE_FORMAT_8250:
539 {
540 int i;
541 for (i = 1; i < 5; i++) {
542 if (track >= bam[(i * 0x100) + 4] && track < bam[(i * 0x100) + 5]) {
543 bamp = &bam[(i * 0x100) + BAM_BIT_MAP_8050 + 5 * (track - bam[(i * 0x100) + 4])];
544 break;
545 }
546 }
547 }
548 break;
549 case VDRIVE_IMAGE_FORMAT_4000:
550 bamp = &bam[0x100 + BAM_BIT_MAP_4000 + 32 * (track - 1) - 1];
551 break;
552 case VDRIVE_IMAGE_FORMAT_9000:
553 {
554 int i;
555 sector = sector >> 5;
556 for (i = 1; i < (vdrive->bam_size >> 8); i++) {
557 if (track >= bam[(i * 0x100) + 4] && track < bam[(i * 0x100) + 5]) {
558 bamp = &bam[(i * 0x100) + BAM_BIT_MAP_9000 + 5
559 * ((track - bam[(i * 0x100) + 4])
560 * (vdrive->image->sectors >> 5) + sector)];
561 break;
562 }
563 }
564 }
565 break;
566 default:
567 log_error(LOG_ERR, "Unknown disk type %u. Cannot calculate BAM track.",
568 vdrive->image_format);
569 }
570 return bamp;
571 }
572
vdrive_bam_sector_free(vdrive_t * vdrive,uint8_t * bamp,unsigned int track,int add)573 static void vdrive_bam_sector_free(vdrive_t *vdrive, uint8_t *bamp,
574 unsigned int track, int add)
575 {
576 switch (vdrive->image_format) {
577 case VDRIVE_IMAGE_FORMAT_1541:
578 case VDRIVE_IMAGE_FORMAT_2040:
579 case VDRIVE_IMAGE_FORMAT_1581:
580 case VDRIVE_IMAGE_FORMAT_8050:
581 case VDRIVE_IMAGE_FORMAT_8250:
582 case VDRIVE_IMAGE_FORMAT_9000:
583 *bamp += add;
584 break;
585 case VDRIVE_IMAGE_FORMAT_1571:
586 if (track <= NUM_TRACKS_1571 / 2) {
587 *bamp += add;
588 } else {
589 vdrive->bam[BAM_EXT_BIT_MAP_1571 + track - NUM_TRACKS_1571 / 2 - 1] += add;
590 }
591 break;
592 case VDRIVE_IMAGE_FORMAT_4000:
593 break;
594 default:
595 log_error(LOG_ERR, "Unknown disk type %u. Cannot find free sector.",
596 vdrive->image_format);
597 }
598 }
599
vdrive_bam_allocate_sector(vdrive_t * vdrive,unsigned int track,unsigned int sector)600 int vdrive_bam_allocate_sector(vdrive_t *vdrive,
601 unsigned int track, unsigned int sector)
602 {
603 uint8_t *bamp;
604
605 /* Tracks > 70 don't go into the (regular) BAM on 1571 */
606 if ((track > NUM_TRACKS_1571) && (vdrive->image_format == VDRIVE_IMAGE_FORMAT_1571)) {
607 return 0;
608 }
609 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
610 sector ^= 7;
611 }
612
613 bamp = vdrive_bam_get_track_entry(vdrive, track, sector);
614 /* D9090/60 groups 32 sectors per bam group */
615 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
616 sector &= 31;
617 }
618 if (vdrive_bam_isset(bamp, sector)) {
619 vdrive_bam_sector_free(vdrive, bamp, track, -1);
620 vdrive_bam_clr(bamp, sector);
621 return 1;
622 }
623 return 0;
624 }
625
vdrive_bam_free_sector(vdrive_t * vdrive,unsigned int track,unsigned int sector)626 int vdrive_bam_free_sector(vdrive_t *vdrive, unsigned int track,
627 unsigned int sector)
628 {
629 uint8_t *bamp;
630
631 /* Tracks > 70 don't go into the (regular) BAM on 1571 */
632 if ((track > NUM_TRACKS_1571) && (vdrive->image_format == VDRIVE_IMAGE_FORMAT_1571)) {
633 return 0;
634 }
635 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
636 sector ^= 7;
637 }
638
639 bamp = vdrive_bam_get_track_entry(vdrive, track, sector);
640 /* D9090/60 groups 32 sectors per bam group */
641 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
642 sector &= 31;
643 }
644 if (!(vdrive_bam_isset(bamp, sector))) {
645 vdrive_bam_set(bamp, sector);
646 vdrive_bam_sector_free(vdrive, bamp, track, 1);
647 return 1;
648 }
649 return 0;
650 }
651
652 /* check to see if a sector is allocated */
653 /* made for c1541 so it can keep out of the bitmaps since they aren't standard
654 between devices. */
655 /* return of 1 if yes, 0 if not, -1 if failed (1571 > 70 tracks) */
vdrive_bam_is_sector_allocated(struct vdrive_s * vdrive,unsigned int track,unsigned int sector)656 int vdrive_bam_is_sector_allocated(struct vdrive_s *vdrive,
657 unsigned int track, unsigned int sector)
658 {
659 uint8_t *bamp;
660
661 /* Tracks > 70 don't go into the (regular) BAM on 1571 */
662 if ((track > NUM_TRACKS_1571) && (vdrive->image_format == VDRIVE_IMAGE_FORMAT_1571)) {
663 return -1;
664 }
665 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
666 sector ^= 7;
667 }
668 bamp = vdrive_bam_get_track_entry(vdrive, track, sector);
669 /* D9090/60 groups 32 sectors per bam group */
670 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_9000) {
671 sector &= 31;
672 }
673 if (bamp && !vdrive_bam_isset(bamp, sector)) return 1;
674 return 0;
675 }
676
vdrive_bam_clear_all(vdrive_t * vdrive)677 void vdrive_bam_clear_all(vdrive_t *vdrive)
678 {
679 uint8_t *bam = vdrive->bam;
680
681 switch (vdrive->image_format) {
682 case VDRIVE_IMAGE_FORMAT_1541:
683 memset(bam + BAM_EXT_BIT_MAP_1541, 0, 4 * 5);
684 /* fallthrough */
685 case VDRIVE_IMAGE_FORMAT_2040:
686 memset(bam + BAM_BIT_MAP, 0, 4 * NUM_TRACKS_1541);
687 break;
688 case VDRIVE_IMAGE_FORMAT_1571:
689 memset(bam + BAM_BIT_MAP, 0, 4 * NUM_TRACKS_1571 / 2);
690 memset(bam + BAM_EXT_BIT_MAP_1571, 0, NUM_TRACKS_1571 / 2);
691 memset(bam + 0x100, 0, 3 * NUM_TRACKS_1571 / 2);
692 break;
693 case VDRIVE_IMAGE_FORMAT_1581:
694 memset(bam + 0x100 + BAM_BIT_MAP_1581, 0, 6 * NUM_TRACKS_1581 / 2);
695 memset(bam + 0x200 + BAM_BIT_MAP_1581, 0, 6 * NUM_TRACKS_1581 / 2);
696 break;
697 case VDRIVE_IMAGE_FORMAT_8050:
698 memset(bam + 0x100 + BAM_BIT_MAP_8050, 0, 0x100 - BAM_BIT_MAP_8050);
699 memset(bam + 0x200 + BAM_BIT_MAP_8050, 0, 0x100 - BAM_BIT_MAP_8050);
700 break;
701 case VDRIVE_IMAGE_FORMAT_8250:
702 memset(bam + 0x100 + BAM_BIT_MAP_8250, 0, 0x100 - BAM_BIT_MAP_8250);
703 memset(bam + 0x200 + BAM_BIT_MAP_8250, 0, 0x100 - BAM_BIT_MAP_8250);
704 memset(bam + 0x300 + BAM_BIT_MAP_8250, 0, 0x100 - BAM_BIT_MAP_8250);
705 memset(bam + 0x400 + BAM_BIT_MAP_8250, 0, 0x100 - BAM_BIT_MAP_8250);
706 break;
707 case VDRIVE_IMAGE_FORMAT_4000:
708 memset(bam + 0x100 + BAM_BIT_MAP_4000, 255, 255 * 32);
709 break;
710 case VDRIVE_IMAGE_FORMAT_9000:
711 {
712 int i;
713 for (i = 0x100; i < vdrive->bam_size; i += 0x100) {
714 memset(bam + i + BAM_BIT_MAP_9000, 0, 0x100 - BAM_BIT_MAP_9000);
715 }
716 }
717 break;
718 default:
719 log_error(LOG_ERR,
720 "Unknown disk type %u. Cannot clear BAM.",
721 vdrive->image_format);
722 }
723 }
724
725 /* FIXME: Should be removed some day.
726 *
727 * Fixed up a little bit to behave more like strncpy(3), but it's still screwed.
728 */
mystrncpy(uint8_t * d,const uint8_t * s,size_t n)729 static uint8_t *mystrncpy(uint8_t *d, const uint8_t *s, size_t n)
730 {
731 while (n > 0 && *s != 0) {
732 *d++ = *s++;
733 n--;
734 }
735 /* libc's strncpy(3) would add a 0x00 here if there's space for it, so the
736 * 'mystrncpy() name is a bit misleading and might lead to incorrect
737 * assumptions when using this code.
738 * Maybe call this `petscii_strncpy` or so?
739 */
740 return d;
741 }
742
vdrive_bam_create_empty_bam(vdrive_t * vdrive,const char * name,uint8_t * id)743 void vdrive_bam_create_empty_bam(vdrive_t *vdrive, const char *name, uint8_t *id)
744 {
745 /* Create Disk Format for 1541/1571/1581/2040/4000 disks. */
746 memset(vdrive->bam, 0, vdrive->bam_size);
747 if (vdrive->image_format != VDRIVE_IMAGE_FORMAT_8050
748 && vdrive->image_format != VDRIVE_IMAGE_FORMAT_8250
749 && vdrive->image_format != VDRIVE_IMAGE_FORMAT_9000) {
750 vdrive->bam[0] = vdrive->Dir_Track;
751 vdrive->bam[1] = vdrive->Dir_Sector;
752 /* position 2 will be overwritten later for 2040/1581/4000 */
753 vdrive->bam[2] = 65;
754
755 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_1571) {
756 vdrive->bam[3] = 0x80;
757 }
758
759 memset(vdrive->bam + vdrive->bam_name, 0xa0,
760 (vdrive->image_format == VDRIVE_IMAGE_FORMAT_1581
761 || vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) ? 25 : 27);
762 mystrncpy(vdrive->bam + vdrive->bam_name, (const uint8_t *)name, 16U);
763 mystrncpy(vdrive->bam + vdrive->bam_id, id, 2U);
764 }
765
766 switch (vdrive->image_format) {
767 case VDRIVE_IMAGE_FORMAT_2040:
768 vdrive->bam[0x02] = 0x01;
769 vdrive->bam[0xa4] = 0x20;
770 vdrive->bam[0xa5] = 0x20;
771 break;
772 case VDRIVE_IMAGE_FORMAT_1541:
773 case VDRIVE_IMAGE_FORMAT_1571:
774 vdrive->bam[BAM_VERSION_1541] = 50;
775 vdrive->bam[BAM_VERSION_1541 + 1] = 65;
776 break;
777 case VDRIVE_IMAGE_FORMAT_1581:
778 vdrive->bam[0x02] = 68;
779 /* Setup BAM linker. */
780 vdrive->bam[0x100] = vdrive->Bam_Track;
781 vdrive->bam[0x100 + 1] = 2;
782 vdrive->bam[0x200] = 0;
783 vdrive->bam[0x200 + 1] = 0xff;
784 /* Setup BAM version. */
785 vdrive->bam[BAM_VERSION_1581] = 51;
786 vdrive->bam[BAM_VERSION_1581 + 1] = 68;
787 vdrive->bam[0x100 + 2] = 68;
788 vdrive->bam[0x100 + 3] = 0xbb;
789 vdrive->bam[0x100 + 4] = id[0];
790 vdrive->bam[0x100 + 5] = id[1];
791 vdrive->bam[0x100 + 6] = 0xc0;
792 vdrive->bam[0x200 + 2] = 68;
793 vdrive->bam[0x200 + 3] = 0xbb;
794 vdrive->bam[0x200 + 4] = id[0];
795 vdrive->bam[0x200 + 5] = id[1];
796 vdrive->bam[0x200 + 6] = 0xc0;
797 break;
798 case VDRIVE_IMAGE_FORMAT_8050:
799 case VDRIVE_IMAGE_FORMAT_8250:
800 /* the first BAM block with the disk name is at 39/0, but it
801 points to the first bitmap BAM block at 38/0 ...
802 Only the last BAM block at 38/3 resp. 38/9 points to the
803 first dir block at 39/1 */
804 vdrive->bam[0] = BAM_TRACK_8050;
805 vdrive->bam[1] = BAM_SECTOR_8050;
806 vdrive->bam[2] = 67;
807 /* byte 3-5 unused */
808 /* bytes 6- disk name + id + version */
809 memset(vdrive->bam + vdrive->bam_name, 0xa0, 27);
810 mystrncpy(vdrive->bam + vdrive->bam_name, (const uint8_t *)name, 16U);
811 mystrncpy(vdrive->bam + vdrive->bam_id, id, 2U);
812 vdrive->bam[BAM_VERSION_8050] = 50;
813 vdrive->bam[BAM_VERSION_8050 + 1] = 67;
814 /* rest of first block unused */
815
816 /* first bitmap block at 38/0 */
817 vdrive->bam[0x100] = BAM_TRACK_8050;
818 vdrive->bam[0x100 + 1] = 3;
819 vdrive->bam[0x100 + 2] = 67;
820 vdrive->bam[0x100 + 4] = 1; /* In this block from track ... */
821 vdrive->bam[0x100 + 5] = 51; /* till excluding track ... */
822
823 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) {
824 /* second bitmap block at 38/3 */
825 vdrive->bam[0x200] = DIR_TRACK_8050;
826 vdrive->bam[0x200 + 1] = 1;
827 vdrive->bam[0x200 + 2] = 67;
828 vdrive->bam[0x200 + 4] = 51; /* In this block from track ... */
829 vdrive->bam[0x200 + 5] = 78; /* till excluding track ... */
830 } else
831 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8250) {
832 /* second bitmap block at 38/3 */
833 vdrive->bam[0x200] = BAM_TRACK_8050;
834 vdrive->bam[0x200 + 1] = 6;
835 vdrive->bam[0x200 + 2] = 67;
836 vdrive->bam[0x200 + 4] = 51; /* In this block from track ... */
837 vdrive->bam[0x200 + 5] = 101; /* till excluding track ... */
838 /* third bitmap block at 38/6 */
839 vdrive->bam[0x300] = BAM_TRACK_8050;
840 vdrive->bam[0x300 + 1] = 9;
841 vdrive->bam[0x300 + 2] = 67;
842 vdrive->bam[0x300 + 4] = 101; /* In this block from track ... */
843 vdrive->bam[0x300 + 5] = 151; /* till excluding track ... */
844 /* fourth bitmap block at 38/9 */
845 vdrive->bam[0x400] = DIR_TRACK_8050;
846 vdrive->bam[0x400 + 1] = 1;
847 vdrive->bam[0x400 + 2] = 67;
848 vdrive->bam[0x400 + 4] = 151; /* In this block from track ... */
849 vdrive->bam[0x400 + 5] = 155; /* till excluding track ... */
850 }
851 break;
852 case VDRIVE_IMAGE_FORMAT_4000:
853 vdrive->bam[0x02] = 72;
854 /* Setup BAM version. */
855 vdrive->bam[BAM_VERSION_4000] = 49;
856 vdrive->bam[BAM_VERSION_4000 + 1] = 72;
857 vdrive->bam[0x20] = vdrive->Bam_Track;
858 vdrive->bam[0x21] = vdrive->Bam_Sector;
859 vdrive->bam[0x100 + 2] = 72;
860 vdrive->bam[0x100 + 3] = ~72;
861 vdrive->bam[0x100 + 4] = id[0];
862 vdrive->bam[0x100 + 5] = id[1];
863 vdrive->bam[0x100 + 6] = 0xc0;
864 vdrive->bam[0x100 + 8] = vdrive->num_tracks;
865 break;
866 case VDRIVE_IMAGE_FORMAT_9000:
867 {
868 uint8_t tmp[256];
869 int i;
870 unsigned int t, tp, sp, td, tn;
871
872 /* build track 0, sector 0 */
873 memset(tmp, 0, 256);
874 /* tmp[0] is track for bad blocks is 0 */
875 tmp[1] = 1; /* sector for bad blocks */
876 tmp[3] = 0xff; /* DOS 3.0 signature */
877 /* everything starts at sector 10 as sector 0 might have a
878 BAM entry */
879 tmp[4] = vdrive->num_tracks / 2; /* dir track */
880 tmp[5] = 10; /* dir sector */
881 tmp[6] = tmp[4]; /* header track */
882 tmp[7] = tmp[5] + 10; /* header sector */
883 tmp[8] = 1; /* bam track */
884 /* tmp[9] is bam sector */
885 tmp[10] = id[0];
886 tmp[11] = id[1];
887 vdrive_write_sector(vdrive, tmp, 0, 0);
888 /* just incase the vdrive settings are wrong */
889 vdrive->Bam_Track = tmp[8];
890 vdrive->Bam_Sector = tmp[9];
891 vdrive->Header_Track = tmp[6];
892 vdrive->Header_Sector = tmp[7];
893 vdrive->Dir_Track = tmp[4];
894 vdrive->Dir_Sector = tmp[5];
895
896 /* build track 0, sector 1 */
897 memset(tmp, 0xff, 256);
898 vdrive_write_sector(vdrive, tmp, 0, 1);
899
900 /* build bam */
901 vdrive->bam[0] = vdrive->Dir_Track;
902 vdrive->bam[1] = vdrive->Dir_Sector;
903 /* byte 2-5 unused */
904 /* bytes 6- disk name + id + version */
905 memset(vdrive->bam + vdrive->bam_name, 0xa0, 27);
906 mystrncpy(vdrive->bam + vdrive->bam_name, (const uint8_t *)name, 16U);
907 mystrncpy(vdrive->bam + vdrive->bam_id, id, 2U);
908 vdrive->bam[BAM_VERSION_9000] = 51;
909 vdrive->bam[BAM_VERSION_9000 + 1] = 65;
910
911 t = 1;
912 tp = 255;
913 sp = 255;
914 td = 240 / ( vdrive->image->sectors >> 5) / 5;
915 /* fill all BAM entries */
916 for (i = 0x100; i < vdrive->bam_size; i += 0x100 ) {
917 if (i + 0x100 >= vdrive->bam_size) {
918 vdrive->bam[i + 0] = 255;
919 vdrive->bam[i + 1] = 255;
920 vdrive->bam[i + 4] = t - 1;
921 vdrive->bam[i + 5] = vdrive->num_tracks + 1;
922 } else {
923 tn = t + td;
924 if (tn > vdrive->num_tracks) {
925 tn = vdrive->num_tracks;
926 }
927 vdrive->bam[i + 0] = tn;
928 vdrive->bam[i + 1] = 0;
929 vdrive->bam[i + 4] = t - 1;
930 vdrive->bam[i + 5] = t + td - 1;
931 }
932 vdrive->bam[i + 2] = tp;
933 vdrive->bam[i + 3] = sp;
934 tp = t;
935 sp = 0;
936 t += td;
937 }
938 }
939 break;
940 default:
941 log_error(LOG_ERR,
942 "Unknown disk type %u. Cannot create BAM.",
943 vdrive->image_format);
944 }
945 return;
946 }
947
vdrive_bam_get_disk_id(unsigned int unit,unsigned int drive,uint8_t * id)948 int vdrive_bam_get_disk_id(unsigned int unit, unsigned int drive, uint8_t *id)
949 {
950 vdrive_t *vdrive;
951
952 vdrive = file_system_get_vdrive(unit, drive);
953
954 if (vdrive == NULL || id == NULL || vdrive->bam == NULL) {
955 return -1;
956 }
957
958 memcpy(id, vdrive->bam + vdrive->bam_id, 2);
959
960 return 0;
961 }
962
vdrive_bam_set_disk_id(unsigned int unit,unsigned int drive,uint8_t * id)963 int vdrive_bam_set_disk_id(unsigned int unit, unsigned int drive, uint8_t *id)
964 {
965 vdrive_t *vdrive;
966
967 vdrive = file_system_get_vdrive(unit, drive);
968
969 if (vdrive == NULL || id == NULL || vdrive->bam == NULL) {
970 return -1;
971 }
972
973 memcpy(vdrive->bam + vdrive->bam_id, id, 2);
974
975 return 0;
976 }
977
vdrive_bam_get_interleave(unsigned int type)978 int vdrive_bam_get_interleave(unsigned int type)
979 {
980 /* Note: Values for 2040/8050/8250 determined empirically */
981 switch (type) {
982 case VDRIVE_IMAGE_FORMAT_1541:
983 case VDRIVE_IMAGE_FORMAT_2040:
984 return 10;
985 case VDRIVE_IMAGE_FORMAT_1571:
986 return 6;
987 case VDRIVE_IMAGE_FORMAT_1581:
988 return 1;
989 case VDRIVE_IMAGE_FORMAT_8050:
990 return 6;
991 case VDRIVE_IMAGE_FORMAT_8250:
992 return 5;
993 case VDRIVE_IMAGE_FORMAT_4000:
994 return 1;
995 case VDRIVE_IMAGE_FORMAT_9000:
996 return 10;
997 default:
998 log_error(LOG_ERR, "Unknown disk type %u. Using interleave 10.",
999 type);
1000 return 10;
1001 }
1002 }
1003
1004 /* ------------------------------------------------------------------------- */
1005
1006 /*
1007 * Load/Store BAM Image.
1008 */
1009 /*
1010 FIXME: partition support
1011 */
1012
1013 /* probably we should make a list with BAM blocks for each drive type... (AF)*/
vdrive_bam_read_bam(vdrive_t * vdrive)1014 int vdrive_bam_read_bam(vdrive_t *vdrive)
1015 {
1016 int err = -1, i;
1017 unsigned int t, s;
1018
1019 switch (vdrive->image_format) {
1020 case VDRIVE_IMAGE_FORMAT_2040:
1021 case VDRIVE_IMAGE_FORMAT_1541:
1022 err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1541, BAM_SECTOR_1541);
1023 break;
1024 case VDRIVE_IMAGE_FORMAT_1571:
1025 err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1571, BAM_SECTOR_1571);
1026 if (err != 0) {
1027 break;
1028 }
1029 err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1571 + 35, BAM_SECTOR_1571);
1030 break;
1031 case VDRIVE_IMAGE_FORMAT_1581:
1032 err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1581, BAM_SECTOR_1581);
1033 if (err != 0) {
1034 break;
1035 }
1036 err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1581, BAM_SECTOR_1581 + 1);
1037 if (err != 0) {
1038 break;
1039 }
1040 err = vdrive_read_sector(vdrive, vdrive->bam + 512, BAM_TRACK_1581, BAM_SECTOR_1581 + 2);
1041 break;
1042 case VDRIVE_IMAGE_FORMAT_8050:
1043 case VDRIVE_IMAGE_FORMAT_8250:
1044 err = vdrive_read_sector(vdrive, vdrive->bam, HDR_TRACK_8050, HDR_SECTOR_8050);
1045 if (err != 0) {
1046 break;
1047 }
1048 err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_8050, BAM_SECTOR_8050);
1049 if (err != 0) {
1050 break;
1051 }
1052 err = vdrive_read_sector(vdrive, vdrive->bam + 512, BAM_TRACK_8050, BAM_SECTOR_8050 + 3);
1053 if (err != 0) {
1054 break;
1055 }
1056
1057 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) {
1058 break;
1059 }
1060
1061 err = vdrive_read_sector(vdrive, vdrive->bam + 768, BAM_TRACK_8050, BAM_SECTOR_8050 + 6);
1062 if (err != 0) {
1063 break;
1064 }
1065 err = vdrive_read_sector(vdrive, vdrive->bam + 1024, BAM_TRACK_8050, BAM_SECTOR_8050 + 9);
1066 break;
1067 case VDRIVE_IMAGE_FORMAT_4000:
1068 for (i = 0; i < 33; i++) {
1069 err = vdrive_read_sector(vdrive, vdrive->bam + i * 256, BAM_TRACK_4000, BAM_SECTOR_4000 + i);
1070 if (err != 0) {
1071 break;
1072 }
1073 }
1074 break;
1075 case VDRIVE_IMAGE_FORMAT_9000:
1076 err = vdrive_read_sector(vdrive, vdrive->bam, vdrive->Header_Track,
1077 vdrive->Header_Sector);
1078 if (err != 0) {
1079 break;
1080 }
1081 /* follow chain to load bam */
1082 t = vdrive->Bam_Track;
1083 s = vdrive->Bam_Sector;
1084 /* use a for here to read it as t/s links could be bad */
1085 for (i = 0x100; i < vdrive->bam_size; i+=0x100) {
1086 if (t > vdrive->num_tracks
1087 || s > vdrive_get_max_sectors(vdrive, t)) {
1088 break;
1089 }
1090 err = vdrive_read_sector(vdrive, vdrive->bam + i, t, s);
1091 if (err != 0) {
1092 break;
1093 }
1094 t = *(vdrive->bam + i);
1095 s = *(vdrive->bam + i + 1);
1096 }
1097 break;
1098 default:
1099 log_error(LOG_ERR, "Unknown disk type %u. Cannot read BAM.",
1100 vdrive->image_format);
1101 }
1102
1103 if (err < 0) {
1104 return CBMDOS_IPE_NOT_READY;
1105 }
1106
1107 return err;
1108 }
1109
1110 /* Temporary hack. */
vdrive_bam_reread_bam(unsigned int unit,unsigned int drive)1111 int vdrive_bam_reread_bam(unsigned int unit, unsigned int drive)
1112 {
1113 return vdrive_bam_read_bam(file_system_get_vdrive(unit, drive));
1114 }
1115 /*
1116 FIXME: partition support
1117 */
1118
vdrive_bam_write_bam(vdrive_t * vdrive)1119 int vdrive_bam_write_bam(vdrive_t *vdrive)
1120 {
1121 int err = -1, i;
1122 unsigned int t, s;
1123
1124 switch (vdrive->image_format) {
1125 case VDRIVE_IMAGE_FORMAT_1541:
1126 case VDRIVE_IMAGE_FORMAT_2040:
1127 err = vdrive_write_sector(vdrive, vdrive->bam, BAM_TRACK_1541, BAM_SECTOR_1541);
1128 break;
1129 case VDRIVE_IMAGE_FORMAT_1571:
1130 err = vdrive_write_sector(vdrive, vdrive->bam, BAM_TRACK_1571, BAM_SECTOR_1571);
1131 err |= vdrive_write_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1571 + (vdrive->num_tracks / 2), BAM_SECTOR_1571);
1132 break;
1133 case VDRIVE_IMAGE_FORMAT_1581:
1134 err = vdrive_write_sector(vdrive, vdrive->bam, BAM_TRACK_1581, BAM_SECTOR_1581);
1135 err |= vdrive_write_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1581, BAM_SECTOR_1581 + 1);
1136 err |= vdrive_write_sector(vdrive, vdrive->bam + 512, BAM_TRACK_1581, BAM_SECTOR_1581 + 2);
1137 break;
1138 case VDRIVE_IMAGE_FORMAT_8050:
1139 case VDRIVE_IMAGE_FORMAT_8250:
1140 err = vdrive_write_sector(vdrive, vdrive->bam, DIR_TRACK_8050, BAM_SECTOR_8050);
1141 err |= vdrive_write_sector(vdrive, vdrive->bam + 256, BAM_TRACK_8050, BAM_SECTOR_8050);
1142 err |= vdrive_write_sector(vdrive, vdrive->bam + 512, BAM_TRACK_8050, BAM_SECTOR_8050 + 3);
1143
1144 if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) {
1145 break;
1146 }
1147
1148 err |= vdrive_write_sector(vdrive, vdrive->bam + 768, BAM_TRACK_8050, BAM_SECTOR_8050 + 6);
1149 err |= vdrive_write_sector(vdrive, vdrive->bam + 1024, BAM_TRACK_8050, BAM_SECTOR_8050 + 9);
1150 break;
1151 case VDRIVE_IMAGE_FORMAT_4000:
1152 err = 0;
1153 for (i = 0; i < 33; i++) {
1154 err |= vdrive_write_sector(vdrive, vdrive->bam + i * 256, BAM_TRACK_4000, BAM_SECTOR_4000 + i);
1155 }
1156 break;
1157 case VDRIVE_IMAGE_FORMAT_9000:
1158 err = vdrive_write_sector(vdrive, vdrive->bam, vdrive->Header_Track,
1159 vdrive->Header_Sector);
1160 if (err != 0) {
1161 break;
1162 }
1163 /* follow chain to save bam */
1164 t = vdrive->Bam_Track;
1165 s = vdrive->Bam_Sector;
1166 /* use a for here to write it as t/s links could be bad */
1167 for (i = 0x100; i < vdrive->bam_size; i+=0x100) {
1168 if (t > vdrive->num_tracks
1169 || s > vdrive_get_max_sectors(vdrive, t)) {
1170 break;
1171 }
1172 err = vdrive_write_sector(vdrive, vdrive->bam + i, t, s);
1173 if (err != 0) {
1174 break;
1175 }
1176 t = *(vdrive->bam + i);
1177 s = *(vdrive->bam + i + 1);
1178 }
1179 break;
1180 default:
1181 log_error(LOG_ERR, "Unknown disk type %u. Cannot read BAM.",
1182 vdrive->image_format);
1183 }
1184 return err;
1185 }
1186
1187 /* ------------------------------------------------------------------------- */
1188
1189 /*
1190 * Return the number of free blocks on disk.
1191 */
1192
vdrive_bam_free_block_count(vdrive_t * vdrive)1193 unsigned int vdrive_bam_free_block_count(vdrive_t *vdrive)
1194 {
1195 unsigned int blocks;
1196 unsigned int i;
1197 unsigned int j; /* FIXME: j looks a lot like i or l */
1198
1199 for (blocks = 0, i = 1; i <= vdrive->num_tracks; i++) {
1200 switch (vdrive->image_format) {
1201 case VDRIVE_IMAGE_FORMAT_2040:
1202 case VDRIVE_IMAGE_FORMAT_1541:
1203 if (i != vdrive->Dir_Track) {
1204 blocks += (i <= NUM_TRACKS_1541) ?
1205 vdrive->bam[BAM_BIT_MAP + 4 * (i - 1)] :
1206 vdrive->bam[BAM_EXT_BIT_MAP_1541 + 4 * (i - NUM_TRACKS_1541 - 1)];
1207 }
1208 break;
1209 case VDRIVE_IMAGE_FORMAT_1571:
1210 if (i != vdrive->Dir_Track && i != vdrive->Dir_Track + 35) {
1211 blocks += (i <= NUM_TRACKS_1571 / 2) ?
1212 vdrive->bam[BAM_BIT_MAP + 4 * (i - 1)] :
1213 vdrive->bam[BAM_EXT_BIT_MAP_1571 + i - 1 - NUM_TRACKS_1571 / 2];
1214 }
1215 break;
1216 case VDRIVE_IMAGE_FORMAT_1581:
1217 if (i != vdrive->Dir_Track) {
1218 blocks += (i <= NUM_TRACKS_1581 / 2) ?
1219 vdrive->bam[BAM_BIT_MAP_1581 + 256 + 6 * (i - 1)] :
1220 vdrive->bam[BAM_BIT_MAP_1581 + 512 + 6 * (i - 1 - NUM_TRACKS_1581 / 2)];
1221 }
1222 break;
1223 case VDRIVE_IMAGE_FORMAT_8050:
1224 if (i != vdrive->Dir_Track) {
1225 for (j = 1; j < 3; j++) {
1226 if (i >= vdrive->bam[(j * 0x100) + 4] && i < vdrive->bam[(j * 0x100) + 5]) {
1227 blocks += vdrive->bam[(j * 0x100) + BAM_BIT_MAP_8050 + 5 * (i - vdrive->bam[(j * 0x100) + 4])];
1228 break;
1229 }
1230 }
1231 }
1232 break;
1233 case VDRIVE_IMAGE_FORMAT_8250:
1234 if (i != vdrive->Dir_Track) {
1235 for (j = 1; j < 5; j++) {
1236 if (i >= vdrive->bam[(j * 0x100) + 4] && i < vdrive->bam[(j * 0x100) + 5]) {
1237 blocks += vdrive->bam[(j * 0x100) + BAM_BIT_MAP_8050 + 5 * (i - vdrive->bam[(j * 0x100) + 4])];
1238 break;
1239 }
1240 }
1241 }
1242 break;
1243 case VDRIVE_IMAGE_FORMAT_4000:
1244 for (j = ((i == vdrive->Bam_Track) ? 64 : 0); j < 256; j++) {
1245 blocks += (vdrive->bam[BAM_BIT_MAP_4000 + 256 + 32 * (i - 1) + j / 8] >> (j % 8)) & 1;
1246 }
1247 break;
1248 case VDRIVE_IMAGE_FORMAT_9000:
1249 {
1250 uint8_t *bamp;
1251 /* above should use vdrive_bam_get_track_entry as well */
1252 for (j = 0; j < vdrive->image->sectors ; j += 32 ) {
1253 bamp = vdrive_bam_get_track_entry(vdrive, i, j);
1254 blocks += *bamp;
1255 }
1256 break;
1257 }
1258 default:
1259 log_error(LOG_ERR,
1260 "Unknown disk type %u. Cannot calculate free sectors.",
1261 vdrive->image_format);
1262 }
1263 }
1264 return blocks;
1265 }
1266