1 /***************************************************************************
2 * *
3 * LIBDSK: General floppy and diskimage access library *
4 * Copyright (C) 2001 John Elliott <seasip.webmaster@gmail.com> *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU Library General Public *
8 * License as published by the Free Software Foundation; either *
9 * version 2 of the License, or (at your option) any later version. *
10 * *
11 * This library is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Library General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Library General Public *
17 * License along with this library; if not, write to the Free *
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
19 * MA 02111-1307, USA *
20 * *
21 ***************************************************************************/
22
23 /* Functions to convert logical <--> physical tracks/sectors */
24
25 #include "drvi.h"
26
27 /* Convert physical sector to logical */
dg_ps2ls(const DSK_GEOMETRY * self,dsk_pcyl_t cyl,dsk_phead_t head,dsk_psect_t sec,dsk_lsect_t * logical)28 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_ps2ls(const DSK_GEOMETRY *self,
29 /* in */ dsk_pcyl_t cyl, dsk_phead_t head, dsk_psect_t sec,
30 /* out */ dsk_lsect_t *logical)
31 {
32 dsk_ltrack_t track;
33 dsk_lsect_t sector;
34 dsk_err_t e;
35
36 e = dg_pt2lt(self, cyl, head, &track);
37 if (e) return e;
38
39 if (sec < self->dg_secbase ||
40 sec >= self->dg_secbase + self->dg_sectors) return DSK_ERR_BADPTR;
41
42 sector = track * self->dg_sectors;
43 sector += (sec - self->dg_secbase);
44
45 if (logical) *logical = sector;
46
47 return DSK_ERR_OK;
48 }
49
50 /* Convert logical sector to physical */
dg_ls2ps(const DSK_GEOMETRY * self,dsk_lsect_t logical,dsk_pcyl_t * cyl,dsk_phead_t * head,dsk_psect_t * sec)51 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_ls2ps(const DSK_GEOMETRY *self,
52 /* in */ dsk_lsect_t logical,
53 /* out */ dsk_pcyl_t *cyl, dsk_phead_t *head, dsk_psect_t *sec)
54 {
55 dsk_err_t err;
56
57 if (!self) return DSK_ERR_BADPTR;
58 if (!self->dg_sectors || !self->dg_heads) return DSK_ERR_DIVZERO;
59
60 if (logical >= self->dg_cylinders * self->dg_heads * self->dg_sectors)
61 return DSK_ERR_BADPARM;
62
63 if (sec)
64 {
65 if (self->dg_sidedness == SIDES_EXTSURFACE)
66 {
67 dsk_phead_t h;
68
69 logical /= self->dg_sectors;
70 err = dg_lt2pt(self, (dsk_ltrack_t)logical, cyl, &h);
71 if (err) return err;
72
73 *sec = (dsk_psect_t)((logical % self->dg_sectors)
74 + h * self->dg_sectors
75 + self->dg_secbase);
76
77 }
78 else
79 {
80 *sec = (dsk_psect_t)((logical % self->dg_sectors) + self->dg_secbase);
81 }
82 }
83
84 logical /= self->dg_sectors;
85 return dg_lt2pt(self, (dsk_ltrack_t)logical, cyl, head);
86 }
87
88
89
90
91 /* Convert physical cyl/head to logical track */
dg_pt2lt(const DSK_GEOMETRY * self,dsk_pcyl_t cyl,dsk_phead_t head,dsk_ltrack_t * logical)92 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_pt2lt(const DSK_GEOMETRY *self,
93 /* in */ dsk_pcyl_t cyl, dsk_phead_t head,
94 /* out */ dsk_ltrack_t *logical)
95 {
96 dsk_ltrack_t track = 0;
97
98 if (!self ) return DSK_ERR_BADPTR;
99 if (!self->dg_heads) return DSK_ERR_DIVZERO;
100
101 if (head >= self->dg_heads ||
102 cyl >= self->dg_cylinders) return DSK_ERR_BADPARM;
103
104 switch(self->dg_sidedness)
105 {
106 case SIDES_EXTSURFACE: /* [1.3.7] */
107 case SIDES_ALT: track = (cyl * self->dg_heads) + head; break;
108 case SIDES_OUTBACK: if (self->dg_heads > 2) return DSK_ERR_BADPARM;
109 if (!head) track = cyl;
110 else track = (2 * self->dg_cylinders) - (1 + cyl);
111 break;
112 case SIDES_OUTOUT: track = (head * self->dg_cylinders) + cyl;
113 break;
114 }
115
116 if (logical) *logical = track;
117
118 return DSK_ERR_OK;
119 }
120
121 /* Convert logical track to physical */
dg_lt2pt(const DSK_GEOMETRY * self,dsk_ltrack_t logical,dsk_pcyl_t * cyl,dsk_phead_t * head)122 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_lt2pt(const DSK_GEOMETRY *self,
123 /* in */ dsk_ltrack_t logical,
124 /* out */ dsk_pcyl_t *cyl, dsk_phead_t *head)
125 {
126 dsk_pcyl_t c = 0;
127 dsk_phead_t h = 0;
128
129 if (!self) return DSK_ERR_BADPTR;
130 if (!self->dg_heads) return DSK_ERR_DIVZERO;
131
132 if (logical >= self->dg_cylinders * self->dg_heads)
133 return DSK_ERR_BADPARM;
134
135 switch(self->dg_sidedness)
136 {
137 case SIDES_EXTSURFACE: /* [1.3.7] */
138 case SIDES_ALT: c = (logical / self->dg_heads);
139 h = (logical % self->dg_heads);
140 break;
141 case SIDES_OUTBACK: if (self->dg_heads > 2) return DSK_ERR_BADPARM;
142 if (logical < self->dg_cylinders)
143 {
144 c = logical;
145 h = 0;
146 }
147 else
148 {
149 c = (2 * self->dg_cylinders) - (1 + logical);
150 h = 1;
151 }
152 break;
153 case SIDES_OUTOUT: c = (logical % self->dg_cylinders);
154 h = (logical / self->dg_cylinders);
155 break;
156 }
157 if (cyl) *cyl = c;
158 if (head) *head = h;
159 return DSK_ERR_OK;
160 }
161
162
163 /* "Extended surface" discs have sector IDs that don't match the sectors'
164 * location on disc. This means, anywhere we reflect dsk_read() to dsk_xread(),
165 * we have to translate the physical location to the expected sector ID rather
166 * than assuming a 1:1 mapping. */
167
dg_x_head(const DSK_GEOMETRY * dg,dsk_phead_t h)168 dsk_phead_t dg_x_head(const DSK_GEOMETRY *dg, dsk_phead_t h)
169 {
170 if (dg == NULL) return h;
171
172 return (dg->dg_sidedness == SIDES_EXTSURFACE) ? 0 : h;
173 }
174
dg_x_sector(const DSK_GEOMETRY * dg,dsk_phead_t h,dsk_psect_t sec)175 dsk_phead_t dg_x_sector(const DSK_GEOMETRY *dg, dsk_phead_t h, dsk_psect_t sec)
176 {
177 if (dg == NULL) return sec;
178
179 if (dg->dg_sidedness == SIDES_EXTSURFACE)
180 sec += h * dg->dg_sectors;
181 return sec;
182 }
183
184
185