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