summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/imgtool/modules/pc_flop.cpp
blob: 8ee5ae8a8ec679639ff380b91b957afb9633d42d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// license:BSD-3-Clause
// copyright-holders:Raphael Nabet
/****************************************************************************

    pc_flop.c

    PC floppies

****************************************************************************/

#include "imgtool.h"
#include "formats/imageutl.h"
#include "formats/pc_dsk.h"
#include "fat.h"
#include "iflopimg.h"

#define FAT_SECLEN              512


static imgtoolerr_t fat_image_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts)
{
	imgtoolerr_t err;
	uint32_t tracks, heads, sectors;
	uint8_t buffer[FAT_SECLEN];
	imgtool_class imgclass = { fat_get_info };
	imgtoolerr_t (*fat_partition_create)(imgtool::image &image, uint64_t first_block, uint64_t block_count);

	tracks = opts->lookup_int('T');
	heads = opts->lookup_int('H');
	sectors = opts->lookup_int('S');

	/* set up just enough of a boot sector to specify geometry */
	memset(buffer, 0, sizeof(buffer));
	place_integer_le(buffer, 24, 2, sectors);
	place_integer_le(buffer, 26, 2, heads);
	place_integer_le(buffer, 19, 2, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 0));
	place_integer_le(buffer, 32, 4, (uint16_t) (((uint64_t) tracks * heads * sectors) >> 16));
	err = image.write_block(0, buffer);
	if (err)
		goto done;

	/* load fat_partition_create */
	fat_partition_create = (imgtoolerr_t (*)(imgtool::image &, uint64_t, uint64_t))
		imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION);

	/* actually create the partition */
	err = fat_partition_create(image, 0, ((uint64_t) tracks) * heads * sectors);
	if (err)
		goto done;

done:
	return err;
}



static imgtoolerr_t fat_image_get_geometry(imgtool::image &image, uint32_t *tracks, uint32_t *heads, uint32_t *sectors)
{
	imgtoolerr_t err;
	uint64_t total_sectors;
	uint8_t buffer[FAT_SECLEN];

	err = image.read_block(0, buffer);
	if (err)
		return err;

	total_sectors = pick_integer_le(buffer, 19, 2)
		| (pick_integer_le(buffer, 32, 4) << 16);

	*sectors = pick_integer_le(buffer, 24, 2);
	*heads = pick_integer_le(buffer, 26, 2);
	*tracks = total_sectors / *heads / *sectors;
	return IMGTOOLERR_SUCCESS;
}



static imgtoolerr_t fat_get_sector_position(imgtool::image &image, uint32_t sector_index,
	uint32_t *track, uint32_t *head, uint32_t *sector)
{
	imgtoolerr_t err;
	uint32_t tracks, heads, sectors;

	if (sector_index == 0)
	{
		/* special case */
		*head = 0;
		*track = 0;
		*sector = 1;
	}
	else
	{
		err = image.get_geometry(&tracks, &heads, &sectors);
		if (err)
			return err;

		*track = sector_index / sectors / heads;
		*head = (sector_index / sectors) % heads;
		*sector = 1 + (sector_index % sectors);
	}
	return IMGTOOLERR_SUCCESS;
}



static imgtoolerr_t fat_image_readblock(imgtool::image &image, void *buffer, uint64_t block)
{
	imgtoolerr_t err;
	floperr_t ferr;
	uint32_t track, head, sector;
	uint32_t block_size;

	err = image.get_block_size(block_size);
	if (err)
		return err;

	err = fat_get_sector_position(image, block, &track, &head, &sector);
	if (err)
		return err;

	ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size);
	if (ferr)
		return imgtool_floppy_error(ferr);
	return IMGTOOLERR_SUCCESS;
}



static imgtoolerr_t fat_image_writeblock(imgtool::image &image, const void *buffer, uint64_t block)
{
	imgtoolerr_t err;
	floperr_t ferr;
	uint32_t track, head, sector;
	uint32_t block_size;

	err = image.get_block_size(block_size);
	if (err)
		return err;

	err = fat_get_sector_position(image, block, &track, &head, &sector);
	if (err)
		return err;

	ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, block_size, 0);   /* TODO: pass ddam argument from imgtool */
	if (ferr)
		return imgtool_floppy_error(ferr);
	return IMGTOOLERR_SUCCESS;
}



void pc_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info)
{
	switch(state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case IMGTOOLINFO_INT_BLOCK_SIZE:                    info->i = FAT_SECLEN; break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case IMGTOOLINFO_STR_NAME:                          strcpy(info->s = imgtool_temp_str(), "fat"); break;
		case IMGTOOLINFO_STR_DESCRIPTION:                   strcpy(info->s = imgtool_temp_str(), "FAT format"); break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case IMGTOOLINFO_PTR_MAKE_CLASS:                    info->make_class = imgtool_floppy_make_class; break;
		case IMGTOOLINFO_PTR_FLOPPY_CREATE:                 info->create = fat_image_create; break;
		case IMGTOOLINFO_PTR_FLOPPY_FORMAT:                 info->p = nullptr; break;
		case IMGTOOLINFO_PTR_READ_BLOCK:                    info->read_block = fat_image_readblock; break;
		case IMGTOOLINFO_PTR_WRITE_BLOCK:                   info->write_block = fat_image_writeblock; break;
		case IMGTOOLINFO_PTR_GET_GEOMETRY:                  info->get_geometry = fat_image_get_geometry; break;

		default: fat_get_info(imgclass, state, info); break;
	}
}